aboutsummaryrefslogtreecommitdiffstats
path: root/cps-service/src/main/java/org
diff options
context:
space:
mode:
authorArpit Singh <as00745003@techmahindra.com>2024-08-09 12:23:49 +0530
committerArpit Singh <as00745003@techmahindra.com>2024-10-09 09:28:30 +0530
commit07acbb4ddd713f74406b156cbcac2507f96f3b08 (patch)
tree8f4122b9c3ecb994b9bb203cdd8b3fd1ad191f64 /cps-service/src/main/java/org
parente2517a8b993ed884edb251b91ce600d0a1a9fefe (diff)
Implementation of Data validation feature in Create a Node API
Added support to validate JSON/XML data without the need of persisting it in the databse. - added "dryRunInQuery" flag as a new query parameter - added new method as part of CpsDataService layer to perform data validation - added new method in yang parser "validateData" to validate data without persisting it Issue-ID: CPS-2361 Change-Id: I43dd33cc6120576d0fac606d5c4b0168d107311d Signed-off-by: Arpit Singh <as00745003@techmahindra.com>
Diffstat (limited to 'cps-service/src/main/java/org')
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangParser.java34
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java33
4 files changed, 82 insertions, 13 deletions
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index 68e1880d77..b3eff8eb26 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -322,4 +322,18 @@ public interface CpsDataService {
Map<String, String> yangResourcesNameToContentMap,
String targetData,
FetchDescendantsOption fetchDescendantsOption);
+
+
+ /**
+ * Validates JSON or XML data by parsing it using the schema associated to an anchor within the given dataspace.
+ * Validation is performed without persisting the data.
+ *
+ * @param dataspaceName the name of the dataspace where the anchor is located.
+ * @param anchorName the name of the anchor used to validate the data.
+ * @param parentNodeXpath the xpath of the parent node where the data is to be validated.
+ * @param nodeData the JSON or XML data to be validated.
+ * @param contentType the content type of the data (e.g., JSON or XML).
+ */
+ void validateData(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ ContentType contentType);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index eed4f09bf0..b1b545be68 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -64,6 +64,7 @@ import org.springframework.stereotype.Service;
public class CpsDataServiceImpl implements CpsDataService {
private static final String ROOT_NODE_XPATH = "/";
+ private static final String PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH = "";
private static final long DEFAULT_LOCK_TIMEOUT_IN_MILLISECONDS = 300L;
private static final String NO_DATA_NODES = "No data nodes.";
@@ -358,6 +359,14 @@ public class CpsDataServiceImpl implements CpsDataService {
sendDataUpdatedEvent(anchor, listNodeXpath, Operation.DELETE, observedTimestamp);
}
+ @Override
+ public void validateData(final String dataspaceName, final String anchorName, final String parentNodeXpath,
+ final String nodeData, final ContentType contentType) {
+ final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
+ final String xpath = ROOT_NODE_XPATH.equals(parentNodeXpath) ? PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH :
+ CpsPathUtil.getNormalizedXpath(parentNodeXpath);
+ yangParser.validateData(contentType, nodeData, anchor, xpath);
+ }
private Collection<DataNode> rebuildSourceDataNodes(final String xpath, final Anchor sourceAnchor,
final Collection<DataNode> sourceDataNodes) {
@@ -422,7 +431,8 @@ public class CpsDataServiceImpl implements CpsDataService {
final String nodeData, final ContentType contentType) {
if (ROOT_NODE_XPATH.equals(parentNodeXpath)) {
- final ContainerNode containerNode = yangParser.parseData(contentType, nodeData, anchor, "");
+ final ContainerNode containerNode = yangParser.parseData(contentType, nodeData,
+ anchor, PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH);
final Collection<DataNode> dataNodes = new DataNodeBuilder()
.withContainerNode(containerNode)
.buildCollection();
@@ -450,7 +460,7 @@ public class CpsDataServiceImpl implements CpsDataService {
if (isRootNodeXpath(xpath)) {
final ContainerNode containerNode = yangParser.parseData(contentType, nodeData,
- yangResourcesNameToContentMap, "");
+ yangResourcesNameToContentMap, PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH);
final Collection<DataNode> dataNodes = new DataNodeBuilder()
.withContainerNode(containerNode)
.buildCollection();
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangParser.java b/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
index dc23c6bc4a..168e0999d5 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
@@ -21,6 +21,9 @@
package org.onap.cps.utils;
+import static org.onap.cps.utils.YangParserHelper.VALIDATE_AND_PARSE;
+import static org.onap.cps.utils.YangParserHelper.VALIDATE_ONLY;
+
import io.micrometer.core.annotation.Timed;
import java.util.Map;
import lombok.RequiredArgsConstructor;
@@ -57,11 +60,12 @@ public class YangParser {
final String parentNodeXpath) {
final SchemaContext schemaContext = getSchemaContext(anchor);
try {
- return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ return yangParserHelper
+ .parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_AND_PARSE);
} catch (final DataValidationException e) {
invalidateCache(anchor);
}
- return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_AND_PARSE);
}
/**
@@ -78,7 +82,31 @@ public class YangParser {
final Map<String, String> yangResourcesNameToContentMap,
final String parentNodeXpath) {
final SchemaContext schemaContext = getSchemaContext(yangResourcesNameToContentMap);
- return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_AND_PARSE);
+ }
+
+ /**
+ * Parses data to validate it, using the schema context for given anchor.
+ *
+ * @param anchor the anchor used for node data validation
+ * @param parentNodeXpath the xpath of the parent node
+ * @param nodeData JSON or XML data string to validate
+ * @param contentType the content type of the data (e.g., JSON or XML)
+ * @throws DataValidationException if validation fails
+ */
+ public void validateData(final ContentType contentType,
+ final String nodeData,
+ final Anchor anchor,
+ final String parentNodeXpath) {
+ final SchemaContext schemaContext = getSchemaContext(anchor);
+ try {
+ yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_ONLY);
+ } catch (final DataValidationException e) {
+ invalidateCache(anchor);
+ log.error("Data validation failed for anchor: {}, xpath: {}, details: {}", anchor, parentNodeXpath,
+ e.getMessage());
+ }
+ yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_ONLY);
}
private SchemaContext getSchemaContext(final Anchor anchor) {
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java b/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
index d95aceaf79..5612945ea9 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
@@ -72,6 +72,9 @@ public class YangParserHelper {
static final String DATA_ROOT_NODE_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0";
static final String DATA_ROOT_NODE_TAG_NAME = "data";
+ static final String DATA_VALIDATION_FAILURE_MESSAGE = "Data Validation Failed";
+ static final boolean VALIDATE_ONLY = true;
+ static final boolean VALIDATE_AND_PARSE = false;
/**
* Parses data into NormalizedNode according to given schema context.
@@ -85,11 +88,20 @@ public class YangParserHelper {
public ContainerNode parseData(final ContentType contentType,
final String nodeData,
final SchemaContext schemaContext,
- final String parentNodeXpath) {
+ final String parentNodeXpath,
+ final boolean validateOnly) {
if (contentType == ContentType.JSON) {
- return parseJsonData(nodeData, schemaContext, parentNodeXpath);
+ final ContainerNode validatedAndParsedJson = parseJsonData(nodeData, schemaContext, parentNodeXpath);
+ if (validateOnly) {
+ return null;
+ }
+ return validatedAndParsedJson;
+ }
+ final NormalizedNodeResult normalizedNodeResult = parseXmlData(nodeData, schemaContext, parentNodeXpath);
+ if (validateOnly) {
+ return null;
}
- return parseXmlData(nodeData, schemaContext, parentNodeXpath);
+ return buildContainerNodeFormNormalizedNodeResult(normalizedNodeResult);
}
private ContainerNode parseJsonData(final String jsonData,
@@ -124,13 +136,13 @@ public class YangParserHelper {
jsonParserStream.parse(jsonReader);
} catch (final IOException | JsonSyntaxException | IllegalStateException | IllegalArgumentException exception) {
throw new DataValidationException(
- "Data Validation Failed", "Failed to parse json data. " + exception.getMessage(), exception);
+ DATA_VALIDATION_FAILURE_MESSAGE, "Failed to parse json data. " + exception.getMessage(), exception);
}
return dataContainerNodeBuilder.build();
}
@SuppressFBWarnings(value = "DCN_NULLPOINTER_EXCEPTION", justification = "Problem originates in 3PP code")
- private ContainerNode parseXmlData(final String xmlData,
+ private NormalizedNodeResult parseXmlData(final String xmlData,
final SchemaContext schemaContext,
final String parentNodeXpath) {
final XMLInputFactory factory = XMLInputFactory.newInstance();
@@ -167,12 +179,17 @@ public class YangParserHelper {
} catch (final XMLStreamException | URISyntaxException | IOException | SAXException | NullPointerException
| ParserConfigurationException | TransformerException exception) {
throw new DataValidationException(
- "Data Validation Failed", "Failed to parse xml data: " + exception.getMessage(), exception);
+ DATA_VALIDATION_FAILURE_MESSAGE, "Failed to parse xml data: " + exception.getMessage(), exception);
}
+ return normalizedNodeResult;
+ }
+
+ private ContainerNode buildContainerNodeFormNormalizedNodeResult(final NormalizedNodeResult normalizedNodeResult) {
+
final DataContainerChild dataContainerChild =
- (DataContainerChild) getFirstChildXmlRoot(normalizedNodeResult.getResult());
+ (DataContainerChild) getFirstChildXmlRoot(normalizedNodeResult.getResult());
final YangInstanceIdentifier.NodeIdentifier nodeIdentifier =
- new YangInstanceIdentifier.NodeIdentifier(dataContainerChild.getIdentifier().getNodeType());
+ new YangInstanceIdentifier.NodeIdentifier(dataContainerChild.getIdentifier().getNodeType());
return Builders.containerBuilder().withChild(dataContainerChild).withNodeIdentifier(nodeIdentifier).build();
}