diff options
author | Rudrangi Anupriya <ra00745022@techmahindra.com> | 2024-11-06 22:20:11 +0530 |
---|---|---|
committer | Rudrangi Anupriya <ra00745022@techmahindra.com> | 2024-11-17 17:09:51 +0000 |
commit | 5baf570979a06ec52e40dfaf613bb74665a8d9ff (patch) | |
tree | f3626a781fa367764de2607b2eaf5ea54c557617 /cps-rest | |
parent | 37962e3faca4f2306546c4f70d480b0c323d2c68 (diff) |
XML content support for only cps Query v2
Here to bring Support for XML Response Entity in query data nodes
- Add ContentTypeInheadr in cpsQueryV2.yml to support application/xml
- Add contentTypeInHeader parameter to accept xml in QueryRestController.java
- Implement logic to convert data to xml
- written testcase for above changes made
Issue-ID: CPS-2359
Change-Id: Ieb7eeb66ccbb03703626132c6d5c2eade0e7cb4b
Signed-off-by: Rudrangi Anupriya <ra00745022@techmahindra.com>
Diffstat (limited to 'cps-rest')
3 files changed, 73 insertions, 20 deletions
diff --git a/cps-rest/docs/openapi/cpsQueryV2.yml b/cps-rest/docs/openapi/cpsQueryV2.yml index 7f0ceff768..9aaa4193c3 100644 --- a/cps-rest/docs/openapi/cpsQueryV2.yml +++ b/cps-rest/docs/openapi/cpsQueryV2.yml @@ -1,5 +1,6 @@ # ============LICENSE_START======================================================= # Copyright (C) 2023 TechMahindra Ltd. +# Modifications Copyright (C) 2023-2024 TechMahindra Ltd. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,6 +29,7 @@ nodesByDataspaceAndAnchorAndCpsPath: - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/cpsPathInQuery' - $ref: 'components.yml#/components/parameters/descendantsInQuery' + - $ref: 'components.yml#/components/parameters/contentTypeInHeader' responses: '200': description: OK @@ -38,6 +40,14 @@ nodesByDataspaceAndAnchorAndCpsPath: examples: dataSample: $ref: 'components.yml#/components/examples/dataSample' + application/xml: + schema: + type: object + xml: + name: stores + examples: + dataSample: + $ref: 'components.yml#/components/examples/dataSampleXml' '400': $ref: 'components.yml#/components/responses/BadRequest' '403': diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java index 547be669ae..6823f6b03e 100644 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada. - * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. + * Modifications Copyright (C) 2022-2024 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,9 +36,11 @@ import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.PaginationOption; import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.DataNode; +import org.onap.cps.utils.ContentType; import org.onap.cps.utils.DataMapUtils; import org.onap.cps.utils.JsonObjectMapper; import org.onap.cps.utils.PrefixResolver; +import org.onap.cps.utils.XmlFileUtils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -62,18 +64,20 @@ public class QueryRestController implements CpsQueryApi { final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants) ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS; return executeNodesByDataspaceQueryAndCreateResponse(dataspaceName, anchorName, cpsPath, - fetchDescendantsOption); + fetchDescendantsOption, ContentType.JSON); } @Override @Timed(value = "cps.data.controller.datanode.query.v2", description = "Time taken to query data nodes") public ResponseEntity<Object> getNodesByDataspaceAndAnchorAndCpsPathV2(final String dataspaceName, - final String anchorName, final String cpsPath, final String fetchDescendantsOptionAsString) { + final String anchorName, final String contentTypeInHeader, final String cpsPath, + final String fetchDescendantsOptionAsString) { + final ContentType contentType = ContentType.fromString(contentTypeInHeader); final FetchDescendantsOption fetchDescendantsOption = FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString); return executeNodesByDataspaceQueryAndCreateResponse(dataspaceName, anchorName, cpsPath, - fetchDescendantsOption); + fetchDescendantsOption, contentType); } @Override @@ -130,7 +134,8 @@ public class QueryRestController implements CpsQueryApi { } private ResponseEntity<Object> executeNodesByDataspaceQueryAndCreateResponse(final String dataspaceName, - final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { + final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption, + final ContentType contentType) { final Collection<DataNode> dataNodes = cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); final List<Map<String, Object>> dataNodesAsListOfMaps = new ArrayList<>(dataNodes.size()); @@ -143,6 +148,17 @@ public class QueryRestController implements CpsQueryApi { final Map<String, Object> dataMap = DataMapUtils.toDataMapWithIdentifier(dataNode, prefix); dataNodesAsListOfMaps.add(dataMap); } - return new ResponseEntity<>(jsonObjectMapper.asJsonString(dataNodesAsListOfMaps), HttpStatus.OK); + return buildResponseEntity(dataNodesAsListOfMaps, contentType); + } + + private ResponseEntity<Object> buildResponseEntity(final List<Map<String, Object>> dataNodesAsListOfMaps, + final ContentType contentType) { + final String responseData; + if (contentType == ContentType.XML) { + responseData = XmlFileUtils.convertDataMapsToXml(dataNodesAsListOfMaps); + } else { + responseData = jsonObjectMapper.asJsonString(dataNodesAsListOfMaps); + } + return new ResponseEntity<>(responseData, HttpStatus.OK); } } diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy index 80b287cda8..076ab32454 100644 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy @@ -3,7 +3,7 @@ * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech - * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. + * Modifications Copyright (C) 2022-2024 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.http.HttpStatus +import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc import spock.lang.Specification @@ -97,26 +98,52 @@ class QueryRestControllerSpec extends Specification { 'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS } - def 'Query data node v2 api by cps path for the given dataspace and anchor with #scenario.'() { + def 'Query data node v2 API by cps path for the given dataspace and anchor with #scenario and media type JSON'() { given: 'service method returns a list containing a data node' - def dataNode1 = new DataNodeBuilder().withXpath('/xpath') + def dataNode = new DataNodeBuilder().withXpath('/xpath') .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build() - mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption -> { - assert descendantsOption.depth == expectedDepth}}) >> [dataNode1, dataNode1] + mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption -> + assert descendantsOption.depth == expectedDepth + }) >> [dataNode, dataNode] when: 'query data nodes API is invoked' def response = mvc.perform( - get(dataNodeEndpointV2) - .param('cps-path', cpsPath) - .param('descendants', includeDescendantsOptionString)) - .andReturn().response - then: 'the response contains the the datanode in json format' + get(dataNodeEndpointV2) + .contentType(MediaType.APPLICATION_JSON) + .param('cps-path', cpsPath) + .param('descendants', includeDescendantsOptionString)) + .andReturn().response + then: 'the response contains the datanode in the expected JSON format' assert response.status == HttpStatus.OK.value() assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}') - where: 'the following options for include descendants are provided in the request' - scenario | includeDescendantsOptionString || expectedDepth - 'direct children' | 'direct' || 1 - 'descendants' | '2' || 2 + where: 'the following options for include descendants are provided in the request' + scenario | includeDescendantsOptionString || expectedDepth + 'direct children' | 'direct' || 1 + 'descendants' | '2' || 2 + } + + def 'Query data node v2 API by cps path for the given dataspace and anchor with #scenario and media type XML'() { + given: 'service method returns a list containing a data node' + def dataNode = new DataNodeBuilder().withXpath('/xpath') + .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build() + mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption -> + assert descendantsOption.depth == expectedDepth + }) >> [dataNode, dataNode] + when: 'query data nodes API is invoked' + def response = + mvc.perform( + get(dataNodeEndpointV2) + .contentType(MediaType.APPLICATION_XML) + .param('cps-path', cpsPath) + .param('descendants', includeDescendantsOptionString)) + .andReturn().response + then: 'the response contains the datanode in the expected XML format' + assert response.status == HttpStatus.OK.value() + assert response.getContentAsString().contains('<xpath><leaf>value</leaf><leafList>leaveListElement1</leafList><leafList>leaveListElement2</leafList></xpath>') + where: 'the following options for include descendants are provided in the request' + scenario | includeDescendantsOptionString || expectedDepth + 'direct children' | 'direct' || 1 + 'descendants' | '2' || 2 } def 'Query data node by cps path for the given dataspace across all anchors with #scenario.'() { |