aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java3
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java5
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java4
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounter.java84
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CountCmHandleSearchExecution.java45
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounterSpec.groovy128
6 files changed, 266 insertions, 3 deletions
diff --git a/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java b/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java
index c1d65758c7..28ff7c307c 100644
--- a/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java
+++ b/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2024 Nordix Foundation
+ * Copyright (C) 2024-2025 Nordix Foundation
* ================================================================================
* 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 @@ public class ArchitectureTestBase {
"java..",
"lombok..",
"org.apache..",
+ "org.aspectj..",
"org.mapstruct..",
"org.opendaylight..",
"org.slf4j..",
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index 317f6b70e1..d7b38d1a46 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2021-2025 Nordix Foundation
* Modifications Copyright (C) 2021 highstreet technologies GmbH
* Modifications Copyright (C) 2021-2022 Bell Canada
* ================================================================================
@@ -57,6 +57,7 @@ import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandleCompositeState;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties;
import org.onap.cps.ncmp.rest.util.CmHandleStateMapper;
+import org.onap.cps.ncmp.rest.util.CountCmHandleSearchExecution;
import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper;
import org.onap.cps.ncmp.rest.util.DeprecationHelper;
import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper;
@@ -256,6 +257,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
*/
@Override
@SuppressWarnings("deprecation") // mapOldConditionProperties method will be removed in Release 12
+ @CountCmHandleSearchExecution(methodName = "searchCmHandles", interfaceName = "CPS-E-05")
public ResponseEntity<List<RestOutputCmHandle>> searchCmHandles(
final CmHandleQueryParameters cmHandleQueryParameters) {
final CmHandleQueryApiParameters cmHandleQueryApiParameters =
@@ -276,6 +278,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
* @return collection of cm handle ids
*/
@Override
+ @CountCmHandleSearchExecution(methodName = "searchCmHandleIds", interfaceName = "CPS-E-05")
public ResponseEntity<List<String>> searchCmHandleIds(final CmHandleQueryParameters cmHandleQueryParameters,
final Boolean outputAlternateId) {
final CmHandleQueryApiParameters cmHandleQueryApiParameters =
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
index 0e27ba9355..e412107753 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021-2022 Bell Canada
- * Modifications Copyright (C) 2022-2024 Nordix Foundation
+ * Modifications Copyright (C) 2022-2025 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@ import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse;
import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse;
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
+import org.onap.cps.ncmp.rest.util.CountCmHandleSearchExecution;
import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -60,6 +61,7 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
* @return list of cm handle IDs
*/
@Override
+ @CountCmHandleSearchExecution(methodName = "searchCmHandleIds", interfaceName = "CPS-NCMP-I-01")
public ResponseEntity<List<String>> searchCmHandleIds(final CmHandleQueryParameters cmHandleQueryParameters,
final Boolean outputAlternateId) {
final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = ncmpRestInputMapper
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounter.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounter.java
new file mode 100644
index 0000000000..ecd248d89f
--- /dev/null
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounter.java
@@ -0,0 +1,84 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 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.rest.util;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import jakarta.validation.Valid;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
+import org.onap.cps.ncmp.rest.model.ConditionProperties;
+import org.springframework.stereotype.Component;
+
+@Aspect
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class CmHandleSearchExecutionCounter {
+
+ private static final String NO_CONDITION = "NONE";
+
+ private final MeterRegistry meterRegistry;
+
+ /**
+ * Counts the number of invocations of the methods annotated with @CountCmHandleSearchExecution based on the search
+ * conditions dynamically added. If search is executed without condition then it would be tagged as NONE, otherwise
+ * the conditions are concatenated with _ as separator.
+ *
+ * @param joinPoint join point
+ * @param countCmHandleSearchExecution count the cm handle search conditions
+ */
+ @Before("@annotation(countCmHandleSearchExecution)")
+ public void cmHandleSearchExecutionCounter(final JoinPoint joinPoint,
+ final CountCmHandleSearchExecution countCmHandleSearchExecution) {
+ final Object[] args = joinPoint.getArgs();
+
+ if (args.length == 0 || !(args[0] instanceof CmHandleQueryParameters cmHandleQueryParameters)) {
+ log.warn("Method {} is missing required CmHandleQueryParameters argument", joinPoint.getSignature());
+ return;
+ }
+
+ final String conditionTag = Optional.ofNullable(cmHandleQueryParameters.getCmHandleQueryParameters())
+ .filter(conditionTypes -> !conditionTypes.isEmpty())
+ .map(CmHandleSearchExecutionCounter::conditionTag)
+ .orElse(NO_CONDITION);
+
+ Counter.builder("cm_handle_search_invocations")
+ .tag("method", countCmHandleSearchExecution.methodName())
+ .tag("cps-interface", countCmHandleSearchExecution.interfaceName())
+ .tag("conditions", conditionTag)
+ .description("Number of invocations of search methods based on condition types")
+ .register(meterRegistry)
+ .increment();
+ }
+
+ private static String conditionTag(final List<@Valid ConditionProperties> conditionTypes) {
+ return conditionTypes.stream().map(ConditionProperties::getConditionName).sorted()
+ .collect(Collectors.joining("_"));
+ }
+}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CountCmHandleSearchExecution.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CountCmHandleSearchExecution.java
new file mode 100644
index 0000000000..27a0c4a87a
--- /dev/null
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CountCmHandleSearchExecution.java
@@ -0,0 +1,45 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 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.rest.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CountCmHandleSearchExecution {
+
+ /**
+ * Capture the method name for which the number of invocations needs to be tracked.
+ *
+ * @return the search method name
+ */
+ String methodName();
+
+ /**
+ * Capture the CPS and NCMP interface name of the called method.
+ *
+ * @return the CPS and NCMP interface name
+ */
+ String interfaceName();
+}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounterSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounterSpec.groovy
new file mode 100644
index 0000000000..bdadfc8689
--- /dev/null
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleSearchExecutionCounterSpec.groovy
@@ -0,0 +1,128 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 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.rest.util
+
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry
+import org.aspectj.lang.JoinPoint
+import org.aspectj.lang.Signature
+import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters
+import org.onap.cps.ncmp.rest.model.ConditionProperties
+import spock.lang.Specification
+
+class CmHandleSearchExecutionCounterSpec extends Specification {
+
+ def meterRegistry = new SimpleMeterRegistry()
+ def mockJoinPoint = Mock(JoinPoint)
+ def mockCountCmHandleSearchExecutionAnnotation = Mock(CountCmHandleSearchExecution)
+ def mockSignature = Mock(Signature)
+
+ def objectUnderTest = new CmHandleSearchExecutionCounter(meterRegistry)
+
+ def setup() {
+ mockCountCmHandleSearchExecutionAnnotation.methodName() >> 'testMethod'
+ mockCountCmHandleSearchExecutionAnnotation.interfaceName() >> 'testInterface'
+ mockSignature.toString() >> 'testSignature'
+ mockJoinPoint.getSignature() >> mockSignature
+ }
+
+ def 'should track search with conditions'() {
+ given: 'CmHandleQueryParameters with conditions'
+ def cmHandleQueryParameters = new CmHandleQueryParameters()
+ def condition1 = new ConditionProperties(conditionName: 'condition1')
+ def condition2 = new ConditionProperties(conditionName: 'condition2')
+ cmHandleQueryParameters.addCmHandleQueryParametersItem(condition1).addCmHandleQueryParametersItem(condition2)
+ and: 'joinPoint returns the parameters'
+ mockJoinPoint.getArgs() >> [cmHandleQueryParameters]
+ when: 'the annotated method is called'
+ objectUnderTest.cmHandleSearchExecutionCounter(mockJoinPoint, mockCountCmHandleSearchExecutionAnnotation)
+ then: 'the counter should be registered'
+ def counter = findCounter('cm_handle_search_invocations', [
+ 'method' : 'testMethod',
+ 'cps-interface': 'testInterface',
+ 'conditions' : 'condition1_condition2'
+ ])
+ and: 'is incremented once'
+ assert counter.count() == 1
+ }
+
+ def 'should track search with no conditions as NONE'() {
+ given: 'empty CmHandleQueryParameters'
+ def cmHandleQueryParameters = new CmHandleQueryParameters()
+ and: 'joinPoint returns the parameters'
+ mockJoinPoint.getArgs() >> [cmHandleQueryParameters]
+ when: 'the annotated method is called'
+ objectUnderTest.cmHandleSearchExecutionCounter(mockJoinPoint, mockCountCmHandleSearchExecutionAnnotation)
+ then: 'the counter should be registered with NONE tag'
+ def counter = findCounter('cm_handle_search_invocations', [
+ method : 'testMethod',
+ 'cps-interface': 'testInterface',
+ conditions : 'NONE'
+ ])
+ and: 'is incremented once'
+ assert counter.count() == 1
+ }
+
+ def 'should not create counter when args are empty'() {
+ given: 'joinPoint with empty args'
+ mockJoinPoint.getArgs() >> []
+ when: 'the aspect method is called'
+ objectUnderTest.cmHandleSearchExecutionCounter(mockJoinPoint, mockCountCmHandleSearchExecutionAnnotation)
+ then: 'no counter should be registered'
+ assert meterRegistry.find('cm_handle_search_invocations').counters().isEmpty()
+ }
+
+ def 'should not create counter when first arg is not CmHandleQueryParameters'() {
+ given: 'joinPoint with non-CmHandleQueryParameters arg'
+ mockJoinPoint.getArgs() >> ['not a CmHandleQueryParameters']
+ when: 'the aspect method is called'
+ objectUnderTest.cmHandleSearchExecutionCounter(mockJoinPoint, mockCountCmHandleSearchExecutionAnnotation)
+ then: 'no counter should be registered'
+ assert meterRegistry.find('cm_handle_search_invocations').counters().isEmpty()
+ }
+
+ def 'should sort condition names alphabetically'() {
+ given: 'CmHandleQueryParameters with unsorted conditions'
+ def cmHandleQueryParameters = new CmHandleQueryParameters()
+ def condition1 = new ConditionProperties(conditionName: 'zCondition')
+ def condition2 = new ConditionProperties(conditionName: 'aCondition')
+ cmHandleQueryParameters.addCmHandleQueryParametersItem(condition1).addCmHandleQueryParametersItem(condition2)
+ and: 'joinPoint returns our parameters'
+ mockJoinPoint.getArgs() >> [cmHandleQueryParameters]
+ when: 'the aspect method is called'
+ objectUnderTest.cmHandleSearchExecutionCounter(mockJoinPoint, mockCountCmHandleSearchExecutionAnnotation)
+ then: 'the counter should be registered with alphabetically sorted tags'
+ def counter = findCounter('cm_handle_search_invocations', [
+ 'method' : 'testMethod',
+ 'cps-interface': 'testInterface',
+ 'conditions' : 'aCondition_zCondition'
+ ])
+ and: 'counter is incremented once'
+ assert counter.count() == 1
+ }
+
+ def findCounter(name, tags) {
+ def counterSearch = meterRegistry.find(name)
+ tags.each { key, value ->
+ counterSearch = counterSearch.tag(key, value)
+ }
+ return counterSearch.counter()
+ }
+} \ No newline at end of file