2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2025-2026 OpenInfra Foundation Europe
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.ncmp.dmi.rest.stub.controller;
23 import com.fasterxml.jackson.databind.ObjectMapper;
24 import jakarta.servlet.http.HttpServletRequest;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Optional;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31 import lombok.RequiredArgsConstructor;
32 import lombok.extern.slf4j.Slf4j;
33 import org.onap.cps.ncmp.dmi.provmns.api.ProvMnS;
34 import org.onap.cps.ncmp.dmi.provmns.model.ClassNameIdGetDataNodeSelectorParameter;
35 import org.onap.cps.ncmp.dmi.provmns.model.ErrorResponseDefault;
36 import org.onap.cps.ncmp.dmi.provmns.model.PatchItem;
37 import org.onap.cps.ncmp.dmi.provmns.model.PatchOperation;
38 import org.onap.cps.ncmp.dmi.provmns.model.Resource;
39 import org.onap.cps.ncmp.dmi.provmns.model.ResourceOneOf;
40 import org.onap.cps.ncmp.dmi.provmns.model.Scope;
41 import org.onap.cps.ncmp.dmi.rest.stub.utils.Sleeper;
42 import org.springframework.beans.factory.annotation.Value;
43 import org.springframework.http.HttpStatus;
44 import org.springframework.http.ResponseEntity;
45 import org.springframework.web.bind.annotation.RequestMapping;
46 import org.springframework.web.bind.annotation.RestController;
49 @RequestMapping("${rest.api.provmns-base-path}")
50 @RequiredArgsConstructor
52 public class ProvMnsStubController implements ProvMnS {
54 static final ResourceOneOf dummyResource = new ResourceOneOf("some id");
56 static final Pattern PATTERN_SIMULATION = Pattern.compile("dmiSimulation=(\\w+_\\d{1,3})");
57 static final Pattern PATTERN_HTTP_ERROR = Pattern.compile("httpError_(\\d{3})");
58 static final Pattern PATTERN_SLOW_RESPONSE = Pattern.compile("slowResponse_(\\d{1,3})");
60 private final Sleeper sleeper;
61 private final ObjectMapper objectMapper;
64 dummyResource.setObjectClass("dummyClass");
65 dummyResource.setObjectInstance("dummyInstance");
66 dummyResource.setAttributes(Collections.singletonMap("dummyAttribute", "dummy value"));
69 @Value("${delay.provmns-read-delay-ms}")
70 private long provMnSReadDelayMs;
71 @Value("${delay.provmns-write-delay-ms}")
72 private long provMnSWriteDelayMs;
75 * Replaces a complete single resource or creates it if it does not exist.
77 * @param httpServletRequest URI request including path
78 * @param resource Resource representation of the resource to be created or replaced
79 * @return {@code Object} The representation of the updated resource is returned in the response
83 public ResponseEntity<Object> putMoi(final HttpServletRequest httpServletRequest, final Resource resource) {
84 log.info("putMoi: {}", resource);
85 final ResourceOneOf stubResource = new ResourceOneOf("Id set by Stub");
86 stubResource.setObjectClass("ObjectClass set by Stub");
87 stubResource.setObjectInstance("ObjectInstance set by Stub");
88 stubResource.setAttributes("Attribute set by Stub");
89 final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest,
91 return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(stubResource, HttpStatus.OK));
95 * Reads one or multiple resources.
97 * @param httpServletRequest URI request including path
98 * @param scope Extends the set of targeted resources beyond the base
99 * resource identified with the authority and path component of
101 * @param filter Reduces the targeted set of resources by applying a filter to
102 * the scoped set of resource representations. Only resources
103 * representations for which the filter construct evaluates to
104 * "true" are targeted.
105 * @param attributes Attributes of the scoped resources to be returned. The
106 * value is a comma-separated list of attribute names.
107 * @param fields Attribute fields of the scoped resources to be returned. The
108 * value is a comma-separated list of JSON pointers to the
110 * @param dataNodeSelector dataNodeSelector object
111 * @return {@code ResponseEntity} The resources identified in the request for retrieval are returned
112 * in the response message body.
115 public ResponseEntity<Object> getMoi(final HttpServletRequest httpServletRequest, final Scope scope,
116 final String filter, final List<String> attributes,
117 final List<String> fields,
118 final ClassNameIdGetDataNodeSelectorParameter dataNodeSelector) {
119 log.info("getMoi: scope: {}, filter: {}, attributes: {}, fields: {}, dataNodeSelector: {}",
120 scope, filter, attributes, fields, dataNodeSelector);
121 final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest,
123 return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(dummyResource, HttpStatus.OK));
127 * Patches (Create, Update or Delete) one or multiple resources.
129 * @param httpServletRequest URI request including path
130 * @param patchItems A list of items to be created, updated or replaced
131 * @return {@code ResponseEntity} The updated resource representations are returned in the response message body.
134 public ResponseEntity<Object> patchMoi(final HttpServletRequest httpServletRequest,
135 final List<PatchItem> patchItems) {
136 log.info("patchMoi: {}", patchItems);
137 final List<PatchItem> stubResponse = new ArrayList<>();
138 stubResponse.add(new PatchItem(PatchOperation.ADD, "/path=setByStub"));
139 stubResponse.add(new PatchItem(PatchOperation.REMOVE, "/path=alsoSetByStub"));
140 final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest,
141 provMnSWriteDelayMs);
142 return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(stubResponse, HttpStatus.OK));
146 * Delete one or multiple resources.
148 * @param httpServletRequest URI request including path
149 * @return {@code ResponseEntity} The response body is empty, HTTP status returned.
152 public ResponseEntity<Object> deleteMoi(final HttpServletRequest httpServletRequest) {
153 log.info("deleteMoi:");
154 final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest,
155 provMnSWriteDelayMs);
156 return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(HttpStatus.OK));
159 private Optional<ResponseEntity<Object>> simulate(final HttpServletRequest httpServletRequest,
160 final long defaultDelay) {
161 Matcher matcher = PATTERN_SIMULATION.matcher(httpServletRequest.getRequestURI());
162 if (matcher.find()) {
163 final String simulation = matcher.group(1);
164 matcher = PATTERN_SLOW_RESPONSE.matcher(simulation);
165 if (matcher.matches()) {
166 haveALittleRest(Integer.parseInt(matcher.group(1)));
168 matcher = PATTERN_HTTP_ERROR.matcher(simulation);
169 if (matcher.matches()) {
170 return Optional.of(createErrorRsponseEntity(Integer.parseInt(matcher.group(1))));
173 sleeper.delay(defaultDelay);
175 return Optional.empty();
178 private void haveALittleRest(final int durationInSeconds) {
179 log.warn("Stub is mocking slow response; delay {} seconds", durationInSeconds);
181 sleeper.haveALittleRest(durationInSeconds);
182 } catch (final InterruptedException e) {
183 log.trace("Sleep interrupted, re-interrupting the thread");
184 Thread.currentThread().interrupt();
188 private static ResponseEntity<Object> createErrorRsponseEntity(final int errorCode) {
189 log.warn("Stub is mocking an error response, code: {}", errorCode);
190 final ErrorResponseDefault errorResponseDefault = new ErrorResponseDefault("ERROR_FROM_STUB");
191 errorResponseDefault.setTitle("Title set by Stub");
192 errorResponseDefault.setStatus(String.valueOf(errorCode));
193 return new ResponseEntity<>(errorResponseDefault, HttpStatus.valueOf(errorCode));