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