From 673c6d94830a1677e685cab82a76747a0808d347 Mon Sep 17 00:00:00 2001 From: aditya puthuparambil Date: Tue, 24 Aug 2021 17:44:34 +0100 Subject: Add optional observed timestamp in the cps data api - Added optional query parameter in cps data endpoints - Updated service layer and notification to use observedTimestamp Note: - NCMP REST endpoints are not updated as a part of this patch - NCMP does not sent observed timestamp when using cps data services Issue-ID: CPS-477 Signed-off-by: puthuparambil.aditya Change-Id: I1f92da3da7b3a13c45405fdf44e5fef861991d9a Signed-off-by: Renu Kumari --- .../cps/rest/controller/DataRestController.java | 58 +++++++++++++++------- .../rest/exceptions/CpsRestExceptionHandler.java | 6 +++ cps-rest/src/main/resources/static/components.yml | 8 +++ cps-rest/src/main/resources/static/cpsData.yml | 6 +++ 4 files changed, 60 insertions(+), 18 deletions(-) (limited to 'cps-rest/src/main') diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java index 5c79472a4..0e2050e5c 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020 Bell Canada. + * Copyright (C) 2020-2021 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021 Nordix Foundation * ================================================================================ @@ -9,6 +9,7 @@ * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,8 +22,10 @@ package org.onap.cps.rest.controller; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import javax.validation.ValidationException; +import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; import org.onap.cps.rest.api.CpsDataApi; import org.onap.cps.spi.FetchDescendantsOption; @@ -38,25 +41,29 @@ import org.springframework.web.bind.annotation.RestController; public class DataRestController implements CpsDataApi { private static final String ROOT_XPATH = "/"; + private static final String ISO_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + private static final DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_FORMAT); @Autowired private CpsDataService cpsDataService; @Override public ResponseEntity createNode(final String dataspaceName, final String anchorName, - final String jsonData, final String parentNodeXpath) { + final String jsonData, final String parentNodeXpath, final String observedTimestamp) { if (isRootXpath(parentNodeXpath)) { - cpsDataService.saveData(dataspaceName, anchorName, jsonData); + cpsDataService.saveData(dataspaceName, anchorName, jsonData, toOffsetDateTime(observedTimestamp)); } else { - cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, jsonData); + cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, jsonData, + toOffsetDateTime(observedTimestamp)); } return new ResponseEntity<>(HttpStatus.CREATED); } @Override public ResponseEntity addListNodeElements(final String parentNodeXpath, - final String dataspaceName, final String anchorName, final String jsonData) { - cpsDataService.saveListNodeData(dataspaceName, anchorName, parentNodeXpath, jsonData); + final String dataspaceName, final String anchorName, final String jsonData, final String observedTimestamp) { + cpsDataService.saveListNodeData(dataspaceName, anchorName, parentNodeXpath, jsonData, + toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.CREATED); } @@ -77,33 +84,48 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity updateNodeLeaves(final String dataspaceName, - final String anchorName, final String jsonData, final String parentNodeXpath) { - cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, jsonData); + final String anchorName, final String jsonData, final String parentNodeXpath, final String observedTimestamp) { + cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, jsonData, + toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.OK); } @Override - public ResponseEntity replaceNode(final String dataspaceName, - final String anchorName, @Valid final String jsonData, @Valid final String parentNodeXpath) { - cpsDataService.replaceNodeTree(dataspaceName, anchorName, parentNodeXpath, jsonData); + public ResponseEntity replaceNode(final String dataspaceName, final String anchorName, + final String jsonData, final String parentNodeXpath, final String observedTimestamp) { + cpsDataService + .replaceNodeTree(dataspaceName, anchorName, parentNodeXpath, jsonData, toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.OK); } @Override - public ResponseEntity replaceListNodeElements(@NotNull @Valid final String parentNodeXpath, - final String dataspaceName, final String anchorName, @Valid final String jsonData) { - cpsDataService.replaceListNodeData(dataspaceName, anchorName, parentNodeXpath, jsonData); + public ResponseEntity replaceListNodeElements(final String parentNodeXpath, + final String dataspaceName, final String anchorName, final String jsonData, + final String observedTimestamp) { + cpsDataService.replaceListNodeData(dataspaceName, anchorName, parentNodeXpath, jsonData, + toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.OK); } @Override public ResponseEntity deleteListNodeElements(final String dataspaceName, final String anchorName, - final String listNodeXpath) { - cpsDataService.deleteListNodeData(dataspaceName, anchorName, listNodeXpath); + final String listNodeXpath, final String observedTimestamp) { + cpsDataService + .deleteListNodeData(dataspaceName, anchorName, listNodeXpath, toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } private static boolean isRootXpath(final String xpath) { return ROOT_XPATH.equals(xpath); } + + private OffsetDateTime toOffsetDateTime(final String datetTimestamp) { + try { + return StringUtils.isEmpty(datetTimestamp) + ? null : OffsetDateTime.parse(datetTimestamp, ISO_TIMESTAMP_FORMATTER); + } catch (final Exception exception) { + throw new ValidationException( + String.format("observed-timestamp must be in '%s' format", ISO_TIMESTAMP_FORMAT)); + } + } } diff --git a/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java b/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java index 143ad8b88..d790e0802 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java @@ -22,6 +22,7 @@ package org.onap.cps.rest.exceptions; import javax.servlet.http.HttpServletRequest; +import javax.validation.ValidationException; import lombok.extern.slf4j.Slf4j; import org.onap.cps.rest.controller.AdminRestController; import org.onap.cps.rest.controller.DataRestController; @@ -67,6 +68,11 @@ public class CpsRestExceptionHandler { return buildErrorResponse(HttpStatus.BAD_REQUEST, exception); } + @ExceptionHandler({ValidationException.class}) + public static ResponseEntity handleBadRequestExceptions(final ValidationException validationException) { + return buildErrorResponse(HttpStatus.BAD_REQUEST, validationException); + } + @ExceptionHandler({NotFoundInDataspaceException.class, DataNodeNotFoundException.class}) public static ResponseEntity handleNotFoundExceptions(final CpsException exception, final HttpServletRequest request) { diff --git a/cps-rest/src/main/resources/static/components.yml b/cps-rest/src/main/resources/static/components.yml index 51a49a6e9..75a6f99fc 100644 --- a/cps-rest/src/main/resources/static/components.yml +++ b/cps-rest/src/main/resources/static/components.yml @@ -158,6 +158,14 @@ components: schema: type: boolean default: false + observedTimestampInQuery: + name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: '2021-03-21T00:10:34.030-0100' responses: NotFound: diff --git a/cps-rest/src/main/resources/static/cpsData.yml b/cps-rest/src/main/resources/static/cpsData.yml index 9c4f3334e..75d954473 100644 --- a/cps-rest/src/main/resources/static/cpsData.yml +++ b/cps-rest/src/main/resources/static/cpsData.yml @@ -55,6 +55,7 @@ listNodeByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/requiredXpathInQuery' + - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' requestBody: required: true content: @@ -81,6 +82,7 @@ listNodeByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/requiredXpathInQuery' + - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' requestBody: required: true content: @@ -107,6 +109,7 @@ listNodeByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/requiredXpathInQuery' + - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' responses: '204': $ref: 'components.yml#/components/responses/NoContent' @@ -128,6 +131,7 @@ nodesByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/xpathInQuery' + - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' requestBody: required: true content: @@ -154,6 +158,7 @@ nodesByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/xpathInQuery' + - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' requestBody: required: true content: @@ -180,6 +185,7 @@ nodesByDataspaceAndAnchor: - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/xpathInQuery' + - $ref: 'components.yml#/components/parameters/observedTimestampInQuery' requestBody: required: true content: -- cgit 1.2.3-korg