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.components.impl.aaf.AafPermission;
47 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
48 import org.openecomp.sdc.be.config.BeEcompErrorManager;
49 import org.openecomp.sdc.be.dao.api.ActionStatus;
50 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
51 import org.openecomp.sdc.be.impl.ComponentsUtils;
52 import org.openecomp.sdc.be.model.PropertyDefinition;
53 import org.openecomp.sdc.be.model.User;
54 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
55 import org.openecomp.sdc.be.resources.data.EntryData;
56 import org.openecomp.sdc.be.user.UserBusinessLogic;
57 import org.openecomp.sdc.common.api.Constants;
58 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
59 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
60 import org.openecomp.sdc.common.log.enums.StatusCode;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
65 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
67 @Tag(name = "SDCE-2 APIs")
68 @Server(url = "/sdc2/rest")
70 public class ComponentPropertyServlet extends BeGenericServlet {
72 private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class);
73 private static final String CREATE_PROPERTY = "Create Property";
74 private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}";
75 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ComponentPropertyServlet.class.getName());
76 private final PropertyBusinessLogic propertyBusinessLogic;
77 private final ApplicationDataTypeCache applicationDataTypeCache;
80 public ComponentPropertyServlet(UserBusinessLogic userBusinessLogic, ComponentsUtils componentsUtils,
81 ApplicationDataTypeCache applicationDataTypeCache, PropertyBusinessLogic propertyBusinessLogic) {
82 super(userBusinessLogic, componentsUtils);
83 this.applicationDataTypeCache = applicationDataTypeCache;
84 this.propertyBusinessLogic = propertyBusinessLogic;
88 @Path("services/{serviceId}/properties")
89 @Consumes(MediaType.APPLICATION_JSON)
90 @Produces(MediaType.APPLICATION_JSON)
91 @Operation(description = "Create Service Property", method = "POST", summary = "Returns created service property", responses = {
92 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
93 @ApiResponse(responseCode = "201", description = "Service property created"),
94 @ApiResponse(responseCode = "403", description = "Restricted operation"),
95 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
96 @ApiResponse(responseCode = "409", description = "Service property already exist")})
97 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
98 public Response createPropertyInService(
99 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
100 @Parameter(description = "Service property to be created", required = true) String data, @Context final HttpServletRequest request,
101 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
102 return createProperty(serviceId, data, request, userId);
106 @Path("resources/{resourceId}/properties")
107 @Consumes(MediaType.APPLICATION_JSON)
108 @Produces(MediaType.APPLICATION_JSON)
109 @Operation(description = "Create Resource Property", method = "POST", summary = "Returns created service property", responses = {
110 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
111 @ApiResponse(responseCode = "201", description = "Resource property created"),
112 @ApiResponse(responseCode = "403", description = "Restricted operation"),
113 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
114 @ApiResponse(responseCode = "409", description = "Resource property already exist")})
115 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
116 public Response createPropertyInResource(
117 @Parameter(description = "Resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
118 @Parameter(description = "Resource property to be created", required = true) String data, @Context final HttpServletRequest request,
119 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
120 return createProperty(resourceId, data, request, userId);
124 @Path("services/{serviceId}/properties/{propertyId}")
125 @Consumes(MediaType.APPLICATION_JSON)
126 @Produces(MediaType.APPLICATION_JSON)
127 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property of service", responses = {
128 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
129 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
130 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
131 @ApiResponse(responseCode = "404", description = "Service property not found")})
132 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
133 public Response getPropertyInService(
134 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
135 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
136 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
137 return getProperty(serviceId, propertyId, request, userId);
141 @Path("resources/{resourceId}/properties/{propertyId}")
142 @Consumes(MediaType.APPLICATION_JSON)
143 @Produces(MediaType.APPLICATION_JSON)
144 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property of resource", responses = {
145 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
146 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
147 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
148 @ApiResponse(responseCode = "404", description = "Resource property not found")})
149 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
150 public Response getPropertyInResource(
151 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
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) {
154 return getProperty(resourceId, propertyId, request, userId);
158 @Path("services/{serviceId}/properties")
159 @Consumes(MediaType.APPLICATION_JSON)
160 @Produces(MediaType.APPLICATION_JSON)
161 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property list of service", responses = {
162 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
163 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
164 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
165 @ApiResponse(responseCode = "404", description = "Service property not found")})
166 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
167 public Response getPropertyListInService(
168 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
169 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
170 return getPropertyList(serviceId, request, userId);
174 @Path("resources/{resourceId}/properties")
175 @Consumes(MediaType.APPLICATION_JSON)
176 @Produces(MediaType.APPLICATION_JSON)
177 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property list of resource", responses = {
178 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
179 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
180 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
181 @ApiResponse(responseCode = "404", description = "Resource property not found")})
182 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
183 public Response getPropertyListInResource(
184 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
185 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
186 return getPropertyList(resourceId, request, userId);
190 @Path("services/{serviceId}/properties/{propertyId}")
191 @Consumes(MediaType.APPLICATION_JSON)
192 @Produces(MediaType.APPLICATION_JSON)
193 @Operation(description = "Delete Service Property", method = "DELETE", summary = "Returns deleted property", responses = {
194 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
195 @ApiResponse(responseCode = "204", description = "deleted property"),
196 @ApiResponse(responseCode = "403", description = "Restricted operation"),
197 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
198 @ApiResponse(responseCode = "404", description = "Service property not found")})
199 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
200 public Response deletePropertyInService(
201 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
202 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
203 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
204 return deleteProperty(serviceId, propertyId, request, userId);
208 @Path("resources/{resourceId}/properties/{propertyId}")
209 @Consumes(MediaType.APPLICATION_JSON)
210 @Produces(MediaType.APPLICATION_JSON)
211 @Operation(description = "Delete Resource Property", method = "DELETE", summary = "Returns deleted property", responses = {
212 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
213 @ApiResponse(responseCode = "204", description = "deleted property"),
214 @ApiResponse(responseCode = "403", description = "Restricted operation"),
215 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
216 @ApiResponse(responseCode = "404", description = "Resource property not found")})
217 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
218 public Response deletePropertyInResource(
219 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
220 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
221 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
222 return deleteProperty(resourceId, propertyId, request, userId);
226 @Path("services/{serviceId}/properties")
227 @Consumes(MediaType.APPLICATION_JSON)
228 @Produces(MediaType.APPLICATION_JSON)
229 @Operation(description = "Update Service Property", method = "PUT", summary = "Returns updated property", responses = {
230 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
231 @ApiResponse(responseCode = "200", description = "Service property updated"),
232 @ApiResponse(responseCode = "403", description = "Restricted operation"),
233 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
234 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
235 public Response updatePropertyInService(
236 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
237 @Parameter(description = "Service property to update", required = true) String data, @Context final HttpServletRequest request,
238 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
239 return updateProperty(serviceId, data, request, userId);
243 @Path("resources/{resourceId}/properties")
244 @Consumes(MediaType.APPLICATION_JSON)
245 @Produces(MediaType.APPLICATION_JSON)
246 @Operation(description = "Update Resource Property", method = "PUT", summary = "Returns updated property", responses = {
247 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
248 @ApiResponse(responseCode = "200", description = "Resource property updated"),
249 @ApiResponse(responseCode = "403", description = "Restricted operation"),
250 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
251 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
252 public Response updatePropertyInResource(
253 @Parameter(description = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
254 @Parameter(description = "Resource property to update", required = true) String data, @Context final HttpServletRequest request,
255 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
256 return updateProperty(resourceId, data, request, userId);
259 private Response createProperty(String componentId, String data, HttpServletRequest request, String userId) {
260 String url = request.getMethod() + " " + request.getRequestURI();
261 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
262 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.STARTED, "CREATE_PROPERTIES by user {} ", userId);
264 Either<Map<String, PropertyDefinition>, ActionStatus> propertyDefinition = getPropertyModel(componentId, data);
265 if (propertyDefinition.isRight()) {
266 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(propertyDefinition.right().value());
267 return buildErrorResponse(responseFormat);
269 Map<String, PropertyDefinition> properties = propertyDefinition.left().value();
270 if (properties == null || properties.size() != 1) {
271 log.info("Property content is invalid - {}", data);
272 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
273 return buildErrorResponse(responseFormat);
275 Map.Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
276 PropertyDefinition newPropertyDefinition = entry.getValue();
277 newPropertyDefinition.setParentUniqueId(componentId);
278 String propertyName = newPropertyDefinition.getName();
279 Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyEither = propertyBusinessLogic
280 .addPropertyToComponent(componentId, propertyName, newPropertyDefinition, userId);
281 if (addPropertyEither.isRight()) {
282 return buildErrorResponse(addPropertyEither.right().value());
284 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.COMPLETE, "CREATE_PROPERTIES by user {} ", userId);
285 return buildOkResponse(newPropertyDefinition);
286 } catch (Exception e) {
287 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
288 log.debug("create property failed with exception", e);
289 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
290 return buildErrorResponse(responseFormat);
294 private Response updateProperty(String componentId, String data, HttpServletRequest request, String userId) {
295 String url = request.getMethod() + " " + request.getRequestURI();
296 log.debug("Start handle request of {}", url);
297 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED, "UPDATE_PROPERTIES by user {} ", userId);
299 User modifier = new User();
300 modifier.setUserId(userId);
301 log.debug("modifier id is {}", userId);
304 // convert json to PropertyDefinition
305 Either<Map<String, PropertyDefinition>, ActionStatus> propertiesListEither = getPropertiesListForUpdate(data);
306 if (propertiesListEither.isRight()) {
307 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(propertiesListEither.right().value());
308 return buildErrorResponse(responseFormat);
310 Map<String, PropertyDefinition> properties = propertiesListEither.left().value();
311 if (properties == null) {
312 log.info("Property content is invalid - {}", data);
313 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
314 return buildErrorResponse(responseFormat);
316 //Validate value and Constraint of property and Fetch all data types from cache
317 Either<Boolean, ResponseFormat> constraintValidatorResponse = new PropertyValueConstraintValidationUtil()
318 .validatePropertyConstraints(properties.values(), applicationDataTypeCache,
319 propertyBusinessLogic.getComponentModelByComponentId(componentId));
320 if (constraintValidatorResponse.isRight()) {
321 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
322 return buildErrorResponse(constraintValidatorResponse.right().value());
325 for (PropertyDefinition propertyDefinition : properties.values()) {
326 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
327 .updateComponentProperty(componentId, propertyDefinition.getUniqueId(), propertyDefinition, userId);
328 if (status.isRight()) {
329 log.info("Failed to update Property. Reason - {}", status.right().value());
330 return buildErrorResponse(status.right().value());
332 EntryData<String, PropertyDefinition> property = status.left().value();
333 PropertyDefinition updatedPropertyDefinition = property.getValue();
334 log.debug("Property id {} updated successfully ", updatedPropertyDefinition.getUniqueId());
336 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
337 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "UPDATE_PROPERTIES by user {} ", userId);
338 return buildOkResponse(responseFormat, properties);
339 } catch (Exception e) {
340 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
341 log.debug("update property failed with exception", e);
342 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
343 return buildErrorResponse(responseFormat);
347 private Response getProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
348 String url = request.getMethod() + " " + request.getRequestURI();
349 log.debug(DEBUG_MESSAGE, url, userId);
351 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> retrievedPropertyEither = propertyBusinessLogic
352 .getComponentProperty(componentId, propertyId, userId);
353 if (retrievedPropertyEither.isRight()) {
354 return buildErrorResponse(retrievedPropertyEither.right().value());
356 return buildOkResponse(retrievedPropertyEither.left().value());
357 } catch (Exception e) {
358 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
359 log.debug("get property failed with exception", e);
360 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
361 return buildErrorResponse(responseFormat);
365 private Response getPropertyList(String componentId, HttpServletRequest request, String userId) {
366 String url = request.getMethod() + " " + request.getRequestURI();
367 log.debug(DEBUG_MESSAGE, url, userId);
369 Either<List<PropertyDefinition>, ResponseFormat> propertiesListEither = propertyBusinessLogic.getPropertiesList(componentId, userId);
370 if (propertiesListEither.isRight()) {
371 return buildErrorResponse(propertiesListEither.right().value());
373 return buildOkResponse(propertiesListEither.left().value());
374 } catch (Exception e) {
375 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
376 log.debug("get property failed with exception", e);
377 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
378 return buildErrorResponse(responseFormat);
382 private Response deleteProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
383 String url = request.getMethod() + " " + request.getRequestURI();
384 log.debug(DEBUG_MESSAGE, url, userId);
386 // delete the property
387 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
388 .deletePropertyFromComponent(componentId, propertyId, userId);
389 if (status.isRight()) {
390 log.debug("Failed to delete Property. Reason - ", status.right().value());
391 return buildErrorResponse(status.right().value());
393 Map.Entry<String, PropertyDefinition> property = status.left().value();
394 String name = property.getKey();
395 PropertyDefinition propertyDefinition = property.getValue();
396 log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId());
397 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT);
398 return buildOkResponse(responseFormat, propertyToJson(property));
399 } catch (Exception e) {
400 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
401 log.debug("delete property failed with exception", e);
402 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
403 return buildErrorResponse(responseFormat);