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.servers.Servers;
28 import io.swagger.v3.oas.annotations.tags.Tag;
29 import io.swagger.v3.oas.annotations.tags.Tags;
30 import java.util.List;
32 import javax.inject.Inject;
33 import javax.inject.Singleton;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.ws.rs.Consumes;
36 import javax.ws.rs.DELETE;
37 import javax.ws.rs.GET;
38 import javax.ws.rs.HeaderParam;
39 import javax.ws.rs.POST;
40 import javax.ws.rs.PUT;
41 import javax.ws.rs.Path;
42 import javax.ws.rs.PathParam;
43 import javax.ws.rs.Produces;
44 import javax.ws.rs.core.Context;
45 import javax.ws.rs.core.MediaType;
46 import javax.ws.rs.core.Response;
47 import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic;
48 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
49 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
50 import org.openecomp.sdc.be.config.BeEcompErrorManager;
51 import org.openecomp.sdc.be.dao.api.ActionStatus;
52 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
53 import org.openecomp.sdc.be.impl.ComponentsUtils;
54 import org.openecomp.sdc.be.model.PropertyDefinition;
55 import org.openecomp.sdc.be.model.User;
56 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
57 import org.openecomp.sdc.be.resources.data.EntryData;
58 import org.openecomp.sdc.be.user.UserBusinessLogic;
59 import org.openecomp.sdc.common.api.Constants;
60 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
61 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
62 import org.openecomp.sdc.common.log.enums.StatusCode;
63 import org.openecomp.sdc.exception.ResponseFormat;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
67 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
69 @Tags({@Tag(name = "SDCE-2 APIs")})
70 @Servers({@Server(url = "/sdc2/rest")})
72 public class ComponentPropertyServlet extends BeGenericServlet {
74 private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class);
75 private static final String CREATE_PROPERTY = "Create Property";
76 private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}";
77 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ComponentPropertyServlet.class.getName());
78 private final PropertyBusinessLogic propertyBusinessLogic;
79 private final ApplicationDataTypeCache applicationDataTypeCache;
82 public ComponentPropertyServlet(UserBusinessLogic userBusinessLogic, ComponentsUtils componentsUtils,
83 ApplicationDataTypeCache applicationDataTypeCache, PropertyBusinessLogic propertyBusinessLogic) {
84 super(userBusinessLogic, componentsUtils);
85 this.applicationDataTypeCache = applicationDataTypeCache;
86 this.propertyBusinessLogic = propertyBusinessLogic;
90 @Path("services/{serviceId}/properties")
91 @Consumes(MediaType.APPLICATION_JSON)
92 @Produces(MediaType.APPLICATION_JSON)
93 @Operation(description = "Create Service Property", method = "POST", summary = "Returns created service property", responses = {
94 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
95 @ApiResponse(responseCode = "201", description = "Service property created"),
96 @ApiResponse(responseCode = "403", description = "Restricted operation"),
97 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
98 @ApiResponse(responseCode = "409", description = "Service property already exist")})
99 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
100 public Response createPropertyInService(
101 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
102 @Parameter(description = "Service property to be created", required = true) String data, @Context final HttpServletRequest request,
103 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
104 return createProperty(serviceId, data, request, userId);
108 @Path("resources/{resourceId}/properties")
109 @Consumes(MediaType.APPLICATION_JSON)
110 @Produces(MediaType.APPLICATION_JSON)
111 @Operation(description = "Create Resource Property", method = "POST", summary = "Returns created service property", responses = {
112 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
113 @ApiResponse(responseCode = "201", description = "Resource property created"),
114 @ApiResponse(responseCode = "403", description = "Restricted operation"),
115 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
116 @ApiResponse(responseCode = "409", description = "Resource property already exist")})
117 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
118 public Response createPropertyInResource(
119 @Parameter(description = "Resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
120 @Parameter(description = "Resource property to be created", required = true) String data, @Context final HttpServletRequest request,
121 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
122 return createProperty(resourceId, data, request, userId);
126 @Path("services/{serviceId}/properties/{propertyId}")
127 @Consumes(MediaType.APPLICATION_JSON)
128 @Produces(MediaType.APPLICATION_JSON)
129 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property of service", responses = {
130 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
131 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
132 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
133 @ApiResponse(responseCode = "404", description = "Service property not found")})
134 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
135 public Response getPropertyInService(
136 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
137 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
138 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
139 return getProperty(serviceId, propertyId, request, userId);
143 @Path("resources/{resourceId}/properties/{propertyId}")
144 @Consumes(MediaType.APPLICATION_JSON)
145 @Produces(MediaType.APPLICATION_JSON)
146 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property of resource", responses = {
147 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
148 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
149 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
150 @ApiResponse(responseCode = "404", description = "Resource property not found")})
151 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
152 public Response getPropertyInResource(
153 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
154 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
155 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
156 return getProperty(resourceId, propertyId, request, userId);
160 @Path("services/{serviceId}/properties")
161 @Consumes(MediaType.APPLICATION_JSON)
162 @Produces(MediaType.APPLICATION_JSON)
163 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property list of service", responses = {
164 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
165 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
166 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
167 @ApiResponse(responseCode = "404", description = "Service property not found")})
168 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
169 public Response getPropertyListInService(
170 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
171 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
172 return getPropertyList(serviceId, request, userId);
176 @Path("resources/{resourceId}/properties")
177 @Consumes(MediaType.APPLICATION_JSON)
178 @Produces(MediaType.APPLICATION_JSON)
179 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property list of resource", responses = {
180 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
181 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
182 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
183 @ApiResponse(responseCode = "404", description = "Resource property not found")})
184 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
185 public Response getPropertyListInResource(
186 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
187 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
188 return getPropertyList(resourceId, request, userId);
192 @Path("services/{serviceId}/properties/{propertyId}")
193 @Consumes(MediaType.APPLICATION_JSON)
194 @Produces(MediaType.APPLICATION_JSON)
195 @Operation(description = "Delete Service Property", method = "DELETE", summary = "Returns deleted property", responses = {
196 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
197 @ApiResponse(responseCode = "204", description = "deleted property"),
198 @ApiResponse(responseCode = "403", description = "Restricted operation"),
199 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
200 @ApiResponse(responseCode = "404", description = "Service property not found")})
201 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
202 public Response deletePropertyInService(
203 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
204 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
205 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
206 return deleteProperty(serviceId, propertyId, request, userId);
210 @Path("resources/{resourceId}/properties/{propertyId}")
211 @Consumes(MediaType.APPLICATION_JSON)
212 @Produces(MediaType.APPLICATION_JSON)
213 @Operation(description = "Delete Resource Property", method = "DELETE", summary = "Returns deleted property", responses = {
214 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
215 @ApiResponse(responseCode = "204", description = "deleted property"),
216 @ApiResponse(responseCode = "403", description = "Restricted operation"),
217 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
218 @ApiResponse(responseCode = "404", description = "Resource property not found")})
219 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
220 public Response deletePropertyInResource(
221 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
222 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
223 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
224 return deleteProperty(resourceId, propertyId, request, userId);
228 @Path("services/{serviceId}/properties")
229 @Consumes(MediaType.APPLICATION_JSON)
230 @Produces(MediaType.APPLICATION_JSON)
231 @Operation(description = "Update Service Property", method = "PUT", summary = "Returns updated property", responses = {
232 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
233 @ApiResponse(responseCode = "200", description = "Service property updated"),
234 @ApiResponse(responseCode = "403", description = "Restricted operation"),
235 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
236 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
237 public Response updatePropertyInService(
238 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
239 @Parameter(description = "Service property to update", required = true) String data, @Context final HttpServletRequest request,
240 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
241 return updateProperty(serviceId, data, request, userId);
245 @Path("resources/{resourceId}/properties")
246 @Consumes(MediaType.APPLICATION_JSON)
247 @Produces(MediaType.APPLICATION_JSON)
248 @Operation(description = "Update Resource Property", method = "PUT", summary = "Returns updated property", responses = {
249 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
250 @ApiResponse(responseCode = "200", description = "Resource property updated"),
251 @ApiResponse(responseCode = "403", description = "Restricted operation"),
252 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
253 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
254 public Response updatePropertyInResource(
255 @Parameter(description = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
256 @Parameter(description = "Resource property to update", required = true) String data, @Context final HttpServletRequest request,
257 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
258 return updateProperty(resourceId, data, request, userId);
261 private Response createProperty(String componentId, String data, HttpServletRequest request, String userId) {
262 String url = request.getMethod() + " " + request.getRequestURI();
263 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
264 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.STARTED, "CREATE_PROPERTIES by user {} ", userId);
266 Either<Map<String, PropertyDefinition>, ActionStatus> propertyDefinition = getPropertyModel(componentId, data);
267 if (propertyDefinition.isRight()) {
268 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(propertyDefinition.right().value());
269 return buildErrorResponse(responseFormat);
271 Map<String, PropertyDefinition> properties = propertyDefinition.left().value();
272 if (properties == null || properties.size() != 1) {
273 log.info("Property content is invalid - {}", data);
274 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
275 return buildErrorResponse(responseFormat);
277 Map.Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
278 PropertyDefinition newPropertyDefinition = entry.getValue();
279 newPropertyDefinition.setParentUniqueId(componentId);
280 String propertyName = newPropertyDefinition.getName();
281 Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyEither = propertyBusinessLogic
282 .addPropertyToComponent(componentId, propertyName, newPropertyDefinition, userId);
283 if (addPropertyEither.isRight()) {
284 return buildErrorResponse(addPropertyEither.right().value());
286 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.COMPLETE, "CREATE_PROPERTIES by user {} ", userId);
287 return buildOkResponse(newPropertyDefinition);
288 } catch (Exception e) {
289 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
290 log.debug("create property failed with exception", e);
291 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
292 return buildErrorResponse(responseFormat);
296 private Response updateProperty(String componentId, String data, HttpServletRequest request, String userId) {
297 String url = request.getMethod() + " " + request.getRequestURI();
298 log.debug("Start handle request of {}", url);
299 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED, "UPDATE_PROPERTIES by user {} ", userId);
301 User modifier = new User();
302 modifier.setUserId(userId);
303 log.debug("modifier id is {}", userId);
306 // convert json to PropertyDefinition
307 Either<Map<String, PropertyDefinition>, ActionStatus> propertiesListEither = getPropertiesListForUpdate(data);
308 if (propertiesListEither.isRight()) {
309 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(propertiesListEither.right().value());
310 return buildErrorResponse(responseFormat);
312 Map<String, PropertyDefinition> properties = propertiesListEither.left().value();
313 if (properties == null) {
314 log.info("Property content is invalid - {}", data);
315 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
316 return buildErrorResponse(responseFormat);
318 //Validate value and Constraint of property and Fetch all data types from cache
319 Either<Boolean, ResponseFormat> constraintValidatorResponse = PropertyValueConstraintValidationUtil.getInstance()
320 .validatePropertyConstraints(properties.values(), applicationDataTypeCache,
321 propertyBusinessLogic.getComponentModelByComponentId(componentId));
322 if (constraintValidatorResponse.isRight()) {
323 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
324 return buildErrorResponse(constraintValidatorResponse.right().value());
327 for (PropertyDefinition propertyDefinition : properties.values()) {
328 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
329 .updateComponentProperty(componentId, propertyDefinition.getUniqueId(), propertyDefinition, userId);
330 if (status.isRight()) {
331 log.info("Failed to update Property. Reason - ", status.right().value());
332 return buildErrorResponse(status.right().value());
334 EntryData<String, PropertyDefinition> property = status.left().value();
335 PropertyDefinition updatedPropertyDefinition = property.getValue();
336 log.debug("Property id {} updated successfully ", updatedPropertyDefinition.getUniqueId());
338 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
339 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "UPDATE_PROPERTIES by user {} ", userId);
340 return buildOkResponse(responseFormat, properties);
341 } catch (Exception e) {
342 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
343 log.debug("update property failed with exception", e);
344 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
345 return buildErrorResponse(responseFormat);
349 private Response getProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
350 String url = request.getMethod() + " " + request.getRequestURI();
351 log.debug(DEBUG_MESSAGE, url, userId);
353 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> retrievedPropertyEither = propertyBusinessLogic
354 .getComponentProperty(componentId, propertyId, userId);
355 if (retrievedPropertyEither.isRight()) {
356 return buildErrorResponse(retrievedPropertyEither.right().value());
358 return buildOkResponse(retrievedPropertyEither.left().value());
359 } catch (Exception e) {
360 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
361 log.debug("get property failed with exception", e);
362 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
363 return buildErrorResponse(responseFormat);
367 private Response getPropertyList(String componentId, HttpServletRequest request, String userId) {
368 String url = request.getMethod() + " " + request.getRequestURI();
369 log.debug(DEBUG_MESSAGE, url, userId);
371 Either<List<PropertyDefinition>, ResponseFormat> propertiesListEither = propertyBusinessLogic.getPropertiesList(componentId, userId);
372 if (propertiesListEither.isRight()) {
373 return buildErrorResponse(propertiesListEither.right().value());
375 return buildOkResponse(propertiesListEither.left().value());
376 } catch (Exception e) {
377 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
378 log.debug("get property failed with exception", e);
379 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
380 return buildErrorResponse(responseFormat);
384 private Response deleteProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
385 String url = request.getMethod() + " " + request.getRequestURI();
386 log.debug(DEBUG_MESSAGE, url, userId);
388 // delete the property
389 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
390 .deletePropertyFromComponent(componentId, propertyId, userId);
391 if (status.isRight()) {
392 log.debug("Failed to delete Property. Reason - ", status.right().value());
393 return buildErrorResponse(status.right().value());
395 Map.Entry<String, PropertyDefinition> property = status.left().value();
396 String name = property.getKey();
397 PropertyDefinition propertyDefinition = property.getValue();
398 log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId());
399 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT);
400 return buildOkResponse(responseFormat, propertyToJson(property));
401 } catch (Exception e) {
402 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
403 log.debug("delete property failed with exception", e);
404 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
405 return buildErrorResponse(responseFormat);