20e0094bd6322302b6641e11ccf6dc3e8bb15688
[cps/ncmp-dmi-plugin.git] /
1 /*
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.ncmp.dmi.rest.stub.controller;
22
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;
47
48 @RestController
49 @RequestMapping("${rest.api.provmns-base-path}")
50 @RequiredArgsConstructor
51 @Slf4j
52 public class ProvMnsStubController implements ProvMnS {
53
54     static final ResourceOneOf dummyResource = new ResourceOneOf("some id");
55
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})");
59
60     private final Sleeper sleeper;
61     private final ObjectMapper objectMapper;
62
63     static {
64         dummyResource.setObjectClass("dummyClass");
65         dummyResource.setObjectInstance("dummyInstance");
66         dummyResource.setAttributes(Collections.singletonMap("dummyAttribute", "dummy value"));
67     }
68
69     @Value("${delay.provmns-read-delay-ms}")
70     private long provMnSReadDelayMs;
71     @Value("${delay.provmns-write-delay-ms}")
72     private long provMnSWriteDelayMs;
73
74     /**
75      * Replaces a complete single resource or creates it if it does not exist.
76      *
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
80      *                                message body.
81      */
82     @Override
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,
90             provMnSWriteDelayMs);
91         return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(stubResource, HttpStatus.OK));
92     }
93
94     /**
95      * Reads one or multiple resources.
96      *
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
100      *                                the URI.
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
109      *                                attribute fields.
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.
113      */
114     @Override
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,
122             provMnSReadDelayMs);
123         return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(dummyResource, HttpStatus.OK));
124     }
125
126     /**
127      * Patches (Create, Update or Delete) one or multiple resources.
128      *
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.
132      */
133     @Override
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));
143     }
144
145     /**
146      * Delete one or multiple resources.
147      *
148      * @param httpServletRequest      URI request including path
149      * @return {@code ResponseEntity} The response body is empty, HTTP status returned.
150      */
151     @Override
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));
157     }
158
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)));
167             }
168             matcher = PATTERN_HTTP_ERROR.matcher(simulation);
169             if (matcher.matches()) {
170                 return Optional.of(createErrorRsponseEntity(Integer.parseInt(matcher.group(1))));
171             }
172         } else {
173             sleeper.delay(defaultDelay);
174         }
175         return Optional.empty();
176     }
177
178     private void haveALittleRest(final int durationInSeconds) {
179         log.warn("Stub is mocking slow response; delay {} seconds", durationInSeconds);
180         try {
181             sleeper.haveALittleRest(durationInSeconds);
182         } catch (final InterruptedException e) {
183             log.trace("Sleep interrupted, re-interrupting the thread");
184             Thread.currentThread().interrupt();
185         }
186     }
187
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));
194     }
195
196 }