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.cache.ApplicationDataTypeCache;
54 import org.openecomp.sdc.be.resources.data.EntryData;
55 import org.openecomp.sdc.common.api.Constants;
56 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
57 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
58 import org.openecomp.sdc.common.log.enums.StatusCode;
59 import org.openecomp.sdc.exception.ResponseFormat;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
63 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
65 @Tag(name = "SDCE-2 APIs")
66 @Server(url = "/sdc2/rest")
68 public class ComponentPropertyServlet extends BeGenericServlet {
70 private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class);
71 private static final String CREATE_PROPERTY = "Create Property";
72 private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}";
73 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ComponentPropertyServlet.class.getName());
74 private final PropertyBusinessLogic propertyBusinessLogic;
75 private final ApplicationDataTypeCache applicationDataTypeCache;
78 public ComponentPropertyServlet(ComponentsUtils componentsUtils,
79 ApplicationDataTypeCache applicationDataTypeCache, PropertyBusinessLogic propertyBusinessLogic) {
80 super(componentsUtils);
81 this.applicationDataTypeCache = applicationDataTypeCache;
82 this.propertyBusinessLogic = propertyBusinessLogic;
86 @Path("services/{serviceId}/properties")
87 @Consumes(MediaType.APPLICATION_JSON)
88 @Produces(MediaType.APPLICATION_JSON)
89 @Operation(description = "Create Service Property", method = "POST", summary = "Returns created service property", responses = {
90 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
91 @ApiResponse(responseCode = "201", description = "Service property created"),
92 @ApiResponse(responseCode = "403", description = "Restricted operation"),
93 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
94 @ApiResponse(responseCode = "409", description = "Service property already exist")})
95 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
96 public Response createPropertyInService(
97 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
98 @Parameter(description = "Service property to be created", required = true) String data, @Context final HttpServletRequest request,
99 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
100 return createProperty(serviceId, data, request, userId);
104 @Path("resources/{resourceId}/properties")
105 @Consumes(MediaType.APPLICATION_JSON)
106 @Produces(MediaType.APPLICATION_JSON)
107 @Operation(description = "Create Resource Property", method = "POST", summary = "Returns created service property", responses = {
108 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
109 @ApiResponse(responseCode = "201", description = "Resource property created"),
110 @ApiResponse(responseCode = "403", description = "Restricted operation"),
111 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
112 @ApiResponse(responseCode = "409", description = "Resource property already exist")})
113 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
114 public Response createPropertyInResource(
115 @Parameter(description = "Resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
116 @Parameter(description = "Resource property to be created", required = true) String data, @Context final HttpServletRequest request,
117 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
118 return createProperty(resourceId, data, request, userId);
122 @Path("services/{serviceId}/properties/{propertyId}")
123 @Consumes(MediaType.APPLICATION_JSON)
124 @Produces(MediaType.APPLICATION_JSON)
125 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property of service", responses = {
126 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
127 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
128 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
129 @ApiResponse(responseCode = "404", description = "Service property not found")})
130 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
131 public Response getPropertyInService(
132 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
133 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
134 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
135 return getProperty(serviceId, propertyId, request, userId);
139 @Path("resources/{resourceId}/properties/{propertyId}")
140 @Consumes(MediaType.APPLICATION_JSON)
141 @Produces(MediaType.APPLICATION_JSON)
142 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property of resource", responses = {
143 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
144 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
145 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
146 @ApiResponse(responseCode = "404", description = "Resource property not found")})
147 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
148 public Response getPropertyInResource(
149 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
150 @Parameter(description = "property id to get", required = true) @PathParam("propertyId") final String propertyId,
151 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
152 return getProperty(resourceId, propertyId, request, userId);
156 @Path("services/{serviceId}/properties")
157 @Consumes(MediaType.APPLICATION_JSON)
158 @Produces(MediaType.APPLICATION_JSON)
159 @Operation(description = "Get Service Property", method = "GET", summary = "Returns property list of service", responses = {
160 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
161 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
162 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
163 @ApiResponse(responseCode = "404", description = "Service property not found")})
164 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
165 public Response getPropertyListInService(
166 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
167 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
168 return getPropertyList(serviceId, request, userId);
172 @Path("resources/{resourceId}/properties")
173 @Consumes(MediaType.APPLICATION_JSON)
174 @Produces(MediaType.APPLICATION_JSON)
175 @Operation(description = "Get Resource Property", method = "GET", summary = "Returns property list of resource", responses = {
176 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
177 @ApiResponse(responseCode = "200", description = "property"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
178 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
179 @ApiResponse(responseCode = "404", description = "Resource property not found")})
180 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
181 public Response getPropertyListInResource(
182 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
183 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
184 return getPropertyList(resourceId, request, userId);
188 @Path("services/{serviceId}/properties/{propertyId}")
189 @Consumes(MediaType.APPLICATION_JSON)
190 @Produces(MediaType.APPLICATION_JSON)
191 @Operation(description = "Delete Service Property", method = "DELETE", summary = "Returns deleted property", responses = {
192 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
193 @ApiResponse(responseCode = "204", description = "deleted property"),
194 @ApiResponse(responseCode = "403", description = "Restricted operation"),
195 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
196 @ApiResponse(responseCode = "404", description = "Service property not found")})
197 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
198 public Response deletePropertyInService(
199 @Parameter(description = "service id of property", required = true) @PathParam("serviceId") final String serviceId,
200 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
201 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
202 return deleteProperty(serviceId, propertyId, request, userId);
206 @Path("resources/{resourceId}/properties/{propertyId}")
207 @Consumes(MediaType.APPLICATION_JSON)
208 @Produces(MediaType.APPLICATION_JSON)
209 @Operation(description = "Delete Resource Property", method = "DELETE", summary = "Returns deleted property", responses = {
210 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
211 @ApiResponse(responseCode = "204", description = "deleted property"),
212 @ApiResponse(responseCode = "403", description = "Restricted operation"),
213 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
214 @ApiResponse(responseCode = "404", description = "Resource property not found")})
215 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
216 public Response deletePropertyInResource(
217 @Parameter(description = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
218 @Parameter(description = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId,
219 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
220 return deleteProperty(resourceId, propertyId, request, userId);
224 @Path("services/{serviceId}/properties")
225 @Consumes(MediaType.APPLICATION_JSON)
226 @Produces(MediaType.APPLICATION_JSON)
227 @Operation(description = "Update Service Property", method = "PUT", summary = "Returns updated property", responses = {
228 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
229 @ApiResponse(responseCode = "200", description = "Service property updated"),
230 @ApiResponse(responseCode = "403", description = "Restricted operation"),
231 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
232 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
233 public Response updatePropertyInService(
234 @Parameter(description = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId,
235 @Parameter(description = "Service property to update", required = true) String data, @Context final HttpServletRequest request,
236 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
237 return updateProperty(serviceId, data, request, userId);
241 @Path("resources/{resourceId}/properties")
242 @Consumes(MediaType.APPLICATION_JSON)
243 @Produces(MediaType.APPLICATION_JSON)
244 @Operation(description = "Update Resource Property", method = "PUT", summary = "Returns updated property", responses = {
245 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
246 @ApiResponse(responseCode = "200", description = "Resource property updated"),
247 @ApiResponse(responseCode = "403", description = "Restricted operation"),
248 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
249 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
250 public Response updatePropertyInResource(
251 @Parameter(description = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
252 @Parameter(description = "Resource property to update", required = true) String data, @Context final HttpServletRequest request,
253 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
254 return updateProperty(resourceId, data, request, userId);
257 private Response createProperty(String componentId, String data, HttpServletRequest request, String userId) {
258 String url = request.getMethod() + " " + request.getRequestURI();
259 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
260 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.STARTED, "CREATE_PROPERTIES by user {} ", userId);
262 Either<Map<String, PropertyDefinition>, ActionStatus> propertyDefinition = getPropertyModel(componentId, data);
263 if (propertyDefinition.isRight()) {
264 return buildErrorResponse(getComponentsUtils().getResponseFormat(propertyDefinition.right().value()));
266 Map<String, PropertyDefinition> properties = propertyDefinition.left().value();
267 if (properties == null || properties.size() != 1) {
268 log.info("Property content is invalid - {}", data);
269 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
271 Map.Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
272 PropertyDefinition newPropertyDefinition = entry.getValue();
273 newPropertyDefinition.setParentUniqueId(componentId);
274 newPropertyDefinition.setUserCreated(true);
275 Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyEither =
276 propertyBusinessLogic.addPropertyToComponent(componentId, newPropertyDefinition, userId);
277 if (addPropertyEither.isRight()) {
278 return buildErrorResponse(addPropertyEither.right().value());
280 loggerSupportability.log(LoggerSupportabilityActions.CREATE_PROPERTIES, StatusCode.COMPLETE, "CREATE_PROPERTIES by user {} ", userId);
281 return buildOkResponse(newPropertyDefinition);
282 } catch (Exception e) {
283 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
284 log.debug("create property failed with exception", e);
285 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
289 private Response updateProperty(String componentId, String data, HttpServletRequest request, String userId) {
290 String url = request.getMethod() + " " + request.getRequestURI();
291 log.debug("Start handle request of {}", url);
292 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED, "UPDATE_PROPERTIES by user {} ", userId);
293 log.debug("modifier id is {}", userId);
296 // convert json to PropertyDefinition
297 Either<Map<String, PropertyDefinition>, ActionStatus> propertiesListEither = getPropertiesListForUpdate(data);
298 if (propertiesListEither.isRight()) {
299 return buildErrorResponse(getComponentsUtils().getResponseFormat(propertiesListEither.right().value()));
301 Map<String, PropertyDefinition> properties = propertiesListEither.left().value();
302 if (properties == null) {
303 log.info("Property content is invalid - {}", data);
304 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
306 //Validate value and Constraint of property and Fetch all data types from cache
307 Either<Boolean, ResponseFormat> constraintValidatorResponse = new PropertyValueConstraintValidationUtil()
308 .validatePropertyConstraints(properties.values(), applicationDataTypeCache,
309 propertyBusinessLogic.getComponentModelByComponentId(componentId));
310 if (constraintValidatorResponse.isRight()) {
311 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
312 return buildErrorResponse(constraintValidatorResponse.right().value());
315 for (PropertyDefinition propertyDefinition : properties.values()) {
316 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
317 .updateComponentProperty(componentId, propertyDefinition.getUniqueId(), propertyDefinition, userId);
318 if (status.isRight()) {
319 log.info("Failed to update Property. Reason - {}", status.right().value());
320 return buildErrorResponse(status.right().value());
322 log.debug("Property id {} updated successfully ", status.left().value().getValue().getUniqueId());
324 loggerSupportability.log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "UPDATE_PROPERTIES by user {} ", userId);
325 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties);
326 } catch (Exception e) {
327 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
328 log.debug("update property failed with exception", e);
329 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
333 private Response getProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
334 String url = request.getMethod() + " " + request.getRequestURI();
335 log.debug(DEBUG_MESSAGE, url, userId);
337 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> retrievedPropertyEither = propertyBusinessLogic
338 .getComponentProperty(componentId, propertyId, userId);
339 if (retrievedPropertyEither.isRight()) {
340 return buildErrorResponse(retrievedPropertyEither.right().value());
342 return buildOkResponse(retrievedPropertyEither.left().value());
343 } catch (Exception e) {
344 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
345 log.debug("get property failed with exception", e);
346 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
350 private Response getPropertyList(String componentId, HttpServletRequest request, String userId) {
351 String url = request.getMethod() + " " + request.getRequestURI();
352 log.debug(DEBUG_MESSAGE, url, userId);
354 Either<List<PropertyDefinition>, ResponseFormat> propertiesListEither = propertyBusinessLogic.getPropertiesList(componentId, userId);
355 if (propertiesListEither.isRight()) {
356 return buildErrorResponse(propertiesListEither.right().value());
358 return buildOkResponse(propertiesListEither.left().value());
359 } catch (Exception e) {
360 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_PROPERTY);
361 log.debug("get property failed with exception", e);
362 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
366 private Response deleteProperty(String componentId, String propertyId, HttpServletRequest request, String userId) {
367 String url = request.getMethod() + " " + request.getRequestURI();
368 log.debug(DEBUG_MESSAGE, url, userId);
370 // delete the property
371 Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> status = propertyBusinessLogic
372 .deletePropertyFromComponent(componentId, propertyId, userId);
373 if (status.isRight()) {
374 log.debug("Failed to delete Property. Reason - ", status.right().value());
375 return buildErrorResponse(status.right().value());
377 Map.Entry<String, PropertyDefinition> property = status.left().value();
378 log.debug("Property {} deleted successfully with id {}", property.getKey(), property.getValue().getUniqueId());
379 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), propertyToJson(property));
380 } catch (Exception e) {
381 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
382 log.debug("delete property failed with exception", e);
383 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));