dffccb951dbde3ea53aade8f02ca529f3884896d
[cps/ncmp-dmi-plugin.git] /
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2025 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.http.HttpStatus;
43 import org.springframework.http.ResponseEntity;
44 import org.springframework.web.bind.annotation.RequestMapping;
45 import org.springframework.web.bind.annotation.RestController;
46
47 @RestController
48 @RequestMapping("${rest.api.provmns-base-path}")
49 @RequiredArgsConstructor
50 @Slf4j
51 public class ProvMnsStubController implements ProvMnS {
52
53     static final ResourceOneOf dummyResource = new ResourceOneOf("some id");
54
55     static final Pattern PATTERN_SIMULATION = Pattern.compile("dmiSimulation=(\\w+_\\d{1,3})");
56     static final Pattern PATTERN_HTTP_ERROR = Pattern.compile("httpError_(\\d{3})");
57     static final Pattern PATTERN_SLOW_RESPONSE = Pattern.compile("slowResponse_(\\d{1,3})");
58
59     private final Sleeper sleeper;
60     private final ObjectMapper objectMapper;
61
62     static {
63         dummyResource.setObjectClass("dummyClass");
64         dummyResource.setObjectInstance("dummyInstance");
65         dummyResource.setAttributes(Collections.singletonMap("dummyAttribute", "dummy value"));
66     }
67
68     /**
69      * Replaces a complete single resource or creates it if it does not exist.
70      *
71      * @param httpServletRequest      URI request including path
72      * @param resource                Resource representation of the resource to be created or replaced
73      * @return {@code Object}         The representation of the updated resource is returned in the response
74      *                                message body.
75      */
76     @Override
77     public ResponseEntity<Object> putMoi(final HttpServletRequest httpServletRequest, final Resource resource) {
78         log.info("putMoi: {}", resource);
79         final ResourceOneOf stubResource = new ResourceOneOf("Id set by Stub");
80         stubResource.setObjectClass("ObjectClass set by Stub");
81         stubResource.setObjectInstance("ObjectInstance set by Stub");
82         stubResource.setAttributes("Attribute set by Stub");
83         final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest);
84         return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(stubResource, HttpStatus.OK));
85     }
86
87     /**
88      * Reads one or multiple resources.
89      *
90      * @param httpServletRequest      URI request including path
91      * @param scope                   Extends the set of targeted resources beyond the base
92      *                                resource identified with the authority and path component of
93      *                                the URI.
94      * @param filter                  Reduces the targeted set of resources by applying a filter to
95      *                                the scoped set of resource representations. Only resources
96      *                                representations for which the filter construct evaluates to
97      *                                "true" are targeted.
98      * @param attributes              Attributes of the scoped resources to be returned. The
99      *                                value is a comma-separated list of attribute names.
100      * @param fields                  Attribute fields of the scoped resources to be returned. The
101      *                                value is a comma-separated list of JSON pointers to the
102      *                                attribute fields.
103      * @param dataNodeSelector        dataNodeSelector object
104      * @return {@code ResponseEntity} The resources identified in the request for retrieval are returned
105      *                                in the response message body.
106      */
107     @Override
108     public ResponseEntity<Object> getMoi(final HttpServletRequest httpServletRequest, final Scope scope,
109                                            final String filter, final List<String> attributes,
110                                            final List<String> fields,
111                                            final ClassNameIdGetDataNodeSelectorParameter dataNodeSelector) {
112         log.info("getMoi: scope: {}, filter: {}, attributes: {}, fields: {}, dataNodeSelector: {}",
113                 scope, filter, attributes, fields, dataNodeSelector);
114         final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest);
115         return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(dummyResource, HttpStatus.OK));
116     }
117
118     /**
119      * Patches (Create, Update or Delete) one or multiple resources.
120      *
121      * @param httpServletRequest      URI request including path
122      * @param patchItems              A list of items to be created, updated or replaced
123      * @return {@code ResponseEntity} The updated resource representations are returned in the response message body.
124      */
125     @Override
126     public ResponseEntity<Object> patchMoi(final HttpServletRequest httpServletRequest,
127                                            final List<PatchItem> patchItems) {
128         log.info("patchMoi: {}", patchItems);
129         final List<PatchItem> stubResponse = new ArrayList<>();
130         stubResponse.add(new PatchItem(PatchOperation.ADD, "/path=setByStub"));
131         stubResponse.add(new PatchItem(PatchOperation.REMOVE, "/path=alsoSetByStub"));
132         final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest);
133         return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(stubResponse, HttpStatus.OK));
134     }
135
136     /**
137      * Delete one or multiple resources.
138      *
139      * @param httpServletRequest      URI request including path
140      * @return {@code ResponseEntity} The response body is empty, HTTP status returned.
141      */
142     @Override
143     public ResponseEntity<Object> deleteMoi(final HttpServletRequest httpServletRequest) {
144         log.info("deleteMoi:");
145         final Optional<ResponseEntity<Object>> optionalResponseEntity = simulate(httpServletRequest);
146         return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(HttpStatus.OK));
147     }
148
149     private Optional<ResponseEntity<Object>> simulate(final HttpServletRequest httpServletRequest) {
150         Matcher matcher = PATTERN_SIMULATION.matcher(httpServletRequest.getRequestURI());
151         if (matcher.find()) {
152             final String simulation = matcher.group(1);
153             matcher = PATTERN_SLOW_RESPONSE.matcher(simulation);
154             if (matcher.matches()) {
155                 haveALittleRest(Integer.parseInt(matcher.group(1)));
156             }
157             matcher = PATTERN_HTTP_ERROR.matcher(simulation);
158             if (matcher.matches()) {
159                 return Optional.of(createErrorRsponseEntity(Integer.parseInt(matcher.group(1))));
160             }
161         }
162         return Optional.empty();
163     }
164
165     private void haveALittleRest(final int durationInSeconds) {
166         log.warn("Stub is mocking slow response; delay {} seconds", durationInSeconds);
167         try {
168             sleeper.haveALittleRest(durationInSeconds);
169         } catch (final InterruptedException e) {
170             log.trace("Sleep interrupted, re-interrupting the thread");
171             Thread.currentThread().interrupt();
172         }
173     }
174
175     private static ResponseEntity<Object> createErrorRsponseEntity(final int errorCode) {
176         log.warn("Stub is mocking an error response, code: {}", errorCode);
177         final ErrorResponseDefault errorResponseDefault = new ErrorResponseDefault("ERROR_FROM_STUB");
178         errorResponseDefault.setTitle("Title set by Stub");
179         errorResponseDefault.setStatus(String.valueOf(errorCode));
180         return new ResponseEntity<>(errorResponseDefault, HttpStatus.valueOf(errorCode));
181     }
182
183 }