Introduce new API models and splitting function 33/143633/3
authoregernug <gerard.nugent@est.tech>
Thu, 19 Mar 2026 13:59:15 +0000 (13:59 +0000)
committeregernug <gerard.nugent@est.tech>
Wed, 25 Mar 2026 09:50:20 +0000 (09:50 +0000)
- Introduced new models for DataJobReadRequest and ReadProperties.
- Introduced new ReadRequestExaminer class with a method to split dataNodeSelector on newline and OR.

Issue-ID: CPS-3189

Change-Id: I0265599dc467ba78f1db57b225fbc9993e40f6b5
Signed-off-by: egernug <gerard.nugent@est.tech>
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DataJobReadRequest.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadOperation.java [deleted file]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadProperties.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/JexParser.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/JexParserSpec.groovy

index 2cba7ed..54ea285 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,15 +31,9 @@ public interface DataJobService {
     /**
      * process read data job operations.
      *
-     * @param authorization      the authorization header from the REST request
-     * @param dataJobId          unique identifier of the job within the request
-     * @param dataJobMetadata    data job request headers
      * @param dataJobReadRequest read data job request
      */
-    void readDataJob(String authorization,
-                     String dataJobId,
-                     DataJobMetadata dataJobMetadata,
-                     DataJobReadRequest dataJobReadRequest);
+    void readDataJob(DataJobReadRequest dataJobReadRequest);
 
     /**
      * process write data job operations.
index 19408b1..6e8520d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2024 Nordix Foundation
+ *  Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 package org.onap.cps.ncmp.api.datajobs.models;
 
-import java.util.List;
+import java.util.Map;
 
 /**
- * Describes the read data job operation to be forwarded to dmi.
+ * Represents a read data job request to be forwarded to a DMI plugin.
+ * Contains metadata and configuration for executing read operations on network elements.
  *
- * @param data List of read operations to be executed.
+ * @param name              the name of the data job
+ * @param jobId             the unique identifier for the data job
+ * @param description       a description of the data job purpose
+ * @param readProperties    the read operation properties including targets and data specifications
+ * @param customProperties  additional custom properties for the data job
  */
-public record DataJobReadRequest(List<ReadOperation> data) {}
+public record DataJobReadRequest(String name, String jobId, String description,
+                                 ReadProperties readProperties,
+                                 Map<String, String> customProperties) {}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadOperation.java
deleted file mode 100644 (file)
index 2459e4c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  ============LICENSE_START=======================================================
- *  Copyright (C) 2024 Nordix Foundation
- *  ================================================================================
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  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.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.datajobs.models;
-
-import java.util.List;
-
-/**
- * Holds information of read data job operation.
- * based on <a href="https://www.etsi.org/deliver/etsi_ts/128500_128599/128532/16.04.00_60/ts_128532v160400p.pdf">ETSI TS 128 532 V16.4.0 (2020-08)</a>
- *
- * @param path        Identifier of a managed object (MO) on a network element. Defines the resource on which operation
- *                    is executed. Url Encoded Fully Distinguished Name (FDN).
- * @param op          Describes the operation to execute. The value can only be "read".
- * @param operationId Unique identifier of the operation within the request.
- * @param attributes  Specifies the attributes of the resources that are returned.
- * @param fields      Specifies the attribute fields of the resources that are returned. This should be used if an
- *                    attribute is a struct and only a subset of its fields should be returned.
- * @param filter      This filters the managed Objects.
- * @param scopeType   This selects MOs depending on relationships with Base Managed Object.
- *                    e.g. "BASE_ONLY", "BASE_ALL", "BASE_NTH_LEVEL" etc.
- * @param scopeLevel  Defines the level for objects to be returned for certain scopeTypes. The base level is zero.
- */
-public record ReadOperation(String path, String op, String operationId, List<String> attributes, List<String> fields,
-                            String filter, String scopeType, int scopeLevel) {
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadProperties.java
new file mode 100644 (file)
index 0000000..f921b4d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2026 OpenInfra Foundation Europe. All rights reserved.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  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.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.datajobs.models;
+
+/**
+ * Represents the properties for a read data job operation.
+ * Defines what data to read and how to format the results.
+ *
+ * @param dataNodeSelector  the selector expression to identify target data nodes
+ * @param resultsType       the format type for the results (e.g., JSON, XML)
+ */
+public record ReadProperties(String dataNodeSelector, String resultsType) {
+}
index d4ffada..00d65e5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest;
 import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation;
 import org.onap.cps.ncmp.api.datajobs.models.ProducerKey;
 import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse;
+import org.onap.cps.ncmp.impl.utils.JexParser;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.stereotype.Service;
 
@@ -44,13 +45,11 @@ public class DataJobServiceImpl implements DataJobService {
     private final JsonObjectMapper jsonObjectMapper;
 
     @Override
-    public void readDataJob(final String authorization,
-                            final String dataJobId,
-                            final DataJobMetadata dataJobMetadata,
-                            final DataJobReadRequest dataJobReadRequest) {
-        logJobIdAndSize(dataJobId, dataJobReadRequest.data().size());
-        log.info("Destination: {}", dataJobMetadata.destination());
-        log.info("authorization: {}", authorization);
+    public void readDataJob(final DataJobReadRequest dataJobReadRequest) {
+        log.info("DataJobId: {}", dataJobReadRequest.jobId());
+        final List<String> selectors =
+                JexParser.toXpaths(dataJobReadRequest.readProperties().dataNodeSelector());
+        log.info("DataJobId: {} - Total selectors: {}", dataJobReadRequest.jobId(), selectors.size());
     }
 
     @Override
index ed640b2..ce250cd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2025-2026 OpenInfra Foundation Europe. All rights reserved.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ public class JexParser {
 
     private static final Pattern XPATH_SEGMENT_PATTERN = Pattern.compile("^([^]]*)\\[id=\\\"([^\\\"]*)\\\"]");
     private static final String JEX_COMMENT_PREFIX = "&&";
-    private static final String LINE_SEPARATOR_REGEX = "\\R";
+    private static final String LINE_OR_LOGICAL_OR_REGEX = "\\R|\\bOR\\b";
     private static final String LINE_JOINER_DELIMITER = "\n";
     private static final String SEGMENT_SEPARATOR = "/";
 
@@ -50,9 +50,10 @@ public class JexParser {
         if (jsonExpressionsAsString == null) {
             return Collections.emptyList();
         }
-        final String[] lines = jsonExpressionsAsString.split(LINE_SEPARATOR_REGEX);
+        final String[] lines = jsonExpressionsAsString.split(LINE_OR_LOGICAL_OR_REGEX);
         return Arrays.stream(lines)
                 .map(String::trim)
+                .filter(xpath -> !xpath.isEmpty())
                 .filter(xpath -> !xpath.startsWith(JEX_COMMENT_PREFIX))
                 .distinct()
                 .toList();
index dcad514..45029fb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@ import ch.qos.logback.core.read.ListAppender
 import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata
 import org.onap.cps.ncmp.api.datajobs.models.DataJobReadRequest
 import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest
-import org.onap.cps.ncmp.api.datajobs.models.ReadOperation
+import org.onap.cps.ncmp.api.datajobs.models.ReadProperties
 import org.onap.cps.ncmp.api.datajobs.models.WriteOperation
 import org.onap.cps.utils.JsonObjectMapper
 import org.slf4j.LoggerFactory
@@ -35,8 +35,8 @@ import spock.lang.Specification
 
 class DataJobServiceImplSpec extends Specification {
 
-    def mockWriteRequestExaminer = Mock(WriteRequestExaminer)
     def mockDmiSubJobRequestHandler = Mock(DmiSubJobRequestHandler)
+    def mockWriteRequestExaminer = Mock(WriteRequestExaminer)
     def mockJsonObjectMapper = Mock(JsonObjectMapper)
 
     def objectUnderTest = new DataJobServiceImpl(mockDmiSubJobRequestHandler, mockWriteRequestExaminer, mockJsonObjectMapper)
@@ -54,14 +54,16 @@ class DataJobServiceImplSpec extends Specification {
         ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)).detachAndStopAllAppenders()
     }
 
-    def 'Read data job request.'() {
-        when: 'read data job request is processed'
-            def readOperation = new ReadOperation('', '', '', [], [], '', '', 1)
-            objectUnderTest.readDataJob(authorization, 'my-job-id', myDataJobMetadata, new DataJobReadRequest([readOperation]))
-        then: 'the data job id is correctly logged'
-            def loggingEvent = logger.list[0]
-            assert loggingEvent.level == Level.INFO
-            assert loggingEvent.formattedMessage.contains('Data Job ID: my-job-id')
+    def 'Read data job request'() {
+        given: 'a read data job request with two selectors'
+            def dataJobReadRequest = new DataJobReadRequest('job-name', 'job-id', 'description',
+                new ReadProperties('selector1\nselector2', 'some-type'), [:])
+        when: 'the read data job request is processed'
+            objectUnderTest.readDataJob(dataJobReadRequest)
+        then: 'the total number of selectors is logged'
+            with(logger.list.find { it.formattedMessage.contains('Total selectors') }) {
+                assert it.formattedMessage.contains('Total selectors: 2')
+            }
     }
 
     def 'Write data-job request and verify logging when info enabled.'() {
index e8fcfb9..2b44a07 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2025-2026 OpenInfra Foundation Europe. All rights reserved.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the 'License');
  *  you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import spock.lang.Specification
 
 class JexParserSpec extends Specification {
 
-    def 'Parsing multi-line json expressions with #scenario.'() {
+    def 'Parsing json expressions with #scenario.'() {
         when: 'the parser gets a (multi-line) json expressions'
             def result = JexParser.toXpaths(jsonExpressions)
         then: 'the expected xpaths are returned'
@@ -37,13 +37,18 @@ class JexParserSpec extends Specification {
             'preceding commented line' | '&&ignore this\n/SubNetwork[id="SN1"]'
     }
 
-    def 'Parsing multi-line json expressions with multiple xpaths.'() {
-        given: 'multi-line json expressions'
-            def jsonExpressions = '/SubNetwork[id="SN1"]\n/ManagedElement[id="ME1"]'
+    def 'Parsing json expressions with multiple xpaths using #scenario'() {
         when: 'convert it to xpaths'
             def result = JexParser.toXpaths(jsonExpressions)
         then: 'the expected xpaths are returned'
             assert result == ['/SubNetwork[id="SN1"]','/ManagedElement[id="ME1"]']
+        where: 'following expressions are used'
+            scenario                         | jsonExpressions
+            'newline delimiter'              | '/SubNetwork[id="SN1"]\n/ManagedElement[id="ME1"]'
+            'OR delimiter'                   | '/SubNetwork[id="SN1"] OR /ManagedElement[id="ME1"]'
+            'mixed delimiters'               | '/SubNetwork[id="SN1"] OR\n/ManagedElement[id="ME1"]'
+            'reverse mixed delimiters'       | '/SubNetwork[id="SN1"]\nOR/ManagedElement[id="ME1"]'
+            'OR delimiter with extra spacing'| '/SubNetwork[id="SN1"]   OR    /ManagedElement[id="ME1"]'
     }
 
     def 'Extracts xpaths from json expressions, ignored expressions: #scenario.'() {