07b9440c9bd2fba657c9f738304a32866c4ff018
[ccsdk/oran.git] /
1 /*-
2  * ========================LICENSE_START=================================
3  * ONAP : ccsdk oran
4  * ======================================================================
5  * Copyright (C) 2019-2023 Nordix Foundation. All rights reserved.
6  * ======================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
22
23 import com.fasterxml.jackson.databind.ObjectMapper;
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import io.swagger.v3.oas.annotations.tags.Tag;
27 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.api.v2.ServiceRegistryAndSupervisionApi;
28 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
29 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceRegistrationInfo;
30 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceStatus;
31 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceStatusList;
32 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
33 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
34 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service;
35 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
36 import org.springframework.beans.factory.annotation.Autowired;
37 import org.springframework.http.HttpStatus;
38 import org.springframework.http.ResponseEntity;
39 import org.springframework.web.bind.annotation.PutMapping;
40 import org.springframework.web.bind.annotation.RestController;
41 import org.springframework.web.server.ServerWebExchange;
42 import reactor.core.publisher.Mono;
43
44 import java.net.MalformedURLException;
45 import java.net.URL;
46 import java.time.Duration;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.List;
50
51 @RestController("ServiceControllerV2")
52 @Tag( //
53         name = ServiceController.API_NAME, //
54         description = ServiceController.API_DESCRIPTION //
55
56 )
57 public class ServiceController implements ServiceRegistryAndSupervisionApi {
58
59     public static final String API_NAME = "Service Registry and Supervision";
60     public static final String API_DESCRIPTION = "";
61
62     private final Services services;
63     private final Policies policies;
64
65     @Autowired
66     private ObjectMapper objectMapper;
67
68     private static Gson gson = new GsonBuilder().create();
69
70     ServiceController(Services services, Policies policies) {
71         this.services = services;
72         this.policies = policies;
73     }
74
75     private static final String GET_SERVICE_DETAILS =
76             "Either information about a registered service with given identity or all registered services are returned.";
77
78     @Override
79     public Mono<ResponseEntity<Object>> getServices(final String name, final ServerWebExchange exchange) throws Exception {
80         if (name != null && this.services.get(name) == null) {
81             return ErrorResponse.createMono("Service not found", HttpStatus.NOT_FOUND);
82         }
83
84         List<ServiceStatus> servicesStatus = new ArrayList<>();
85         for (Service s : this.services.getAll()) {
86             if (name == null || name.equals(s.getName())) {
87                 servicesStatus.add(toServiceStatus(s));
88             }
89         }
90         String res = objectMapper.writeValueAsString(new ServiceStatusList().serviceList(servicesStatus));
91         return Mono.just(new ResponseEntity<>(res, HttpStatus.OK));
92     }
93
94     private ServiceStatus toServiceStatus(Service s) {
95         return new ServiceStatus()
96                 .serviceId(s.getName())
97                 .keepAliveIntervalSeconds(s.getKeepAliveInterval().toSeconds())
98                 .timeSinceLastActivitySeconds(s.timeSinceLastPing().toSeconds())
99                 .callbackUrl(s.getCallbackUrl());
100     }
101
102     private void validateRegistrationInfo(ServiceRegistrationInfo registrationInfo)
103             throws ServiceException, MalformedURLException {
104         if (registrationInfo.getServiceId().isEmpty()) {
105             throw new ServiceException("Missing mandatory parameter 'service-id'");
106         }
107         if (registrationInfo.getKeepAliveIntervalSeconds() < 0) {
108             throw new ServiceException("Keep alive interval should be greater or equal to 0");
109         }
110         if (!registrationInfo.getCallbackUrl().isEmpty()) {
111             new URL(registrationInfo.getCallbackUrl());
112         }
113     }
114
115     private static final String REGISTER_SERVICE_DETAILS = "Registering a service is needed to:" //
116             + "<ul>" //
117             + "<li>Get callbacks about available NearRT RICs.</li>" //
118             + "<li>Activate supervision of the service. If a service is inactive, its policies will automatically be deleted.</li>"//
119             + "</ul>" //
120             + "Policies can be created even if the service is not registerred. This is a feature which it is optional to use.";
121
122     @Override
123     public Mono<ResponseEntity<Object>> putService(
124             final Mono<ServiceRegistrationInfo> registrationInfo, final ServerWebExchange exchange) {
125             return registrationInfo.flatMap(info -> {
126                 try {
127                     validateRegistrationInfo(info);
128                 } catch(Exception e) {
129                     return ErrorResponse.createMono(e, HttpStatus.BAD_REQUEST);
130                 }
131                 final boolean isCreate = this.services.get(info.getServiceId()) == null;
132                 this.services.put(toService(info));
133                 return Mono.just(new ResponseEntity<>(isCreate ? HttpStatus.CREATED : HttpStatus.OK));
134             }).onErrorResume(Exception.class, e -> ErrorResponse.createMono(e, HttpStatus.BAD_REQUEST));
135     }
136
137     @Override
138     public Mono<ResponseEntity<Object>> deleteService(final String serviceId, final ServerWebExchange exchange) {
139         try {
140             Service service = removeService(serviceId);
141             // Remove the policies from the repo and let the consistency monitoring
142             // do the rest.
143             removePolicies(service);
144             return Mono.just(new ResponseEntity<>(HttpStatus.NO_CONTENT));
145         } catch (ServiceException e) {
146             return ErrorResponse.createMono(e, HttpStatus.NOT_FOUND);
147         }
148     }
149
150     @Override
151     @PutMapping(Consts.V2_API_ROOT + "/services/{service_id}/keepalive")
152     public Mono<ResponseEntity<Object>> keepAliveService(final String serviceId, final ServerWebExchange exchange) {
153         try {
154             services.getService(serviceId).keepAlive();
155             return Mono.just(new ResponseEntity<>(HttpStatus.OK));
156         } catch (ServiceException e) {
157             return ErrorResponse.createMono(e, HttpStatus.NOT_FOUND);
158         }
159     }
160
161     private Service removeService(String name) throws ServiceException {
162         Service service = this.services.getService(name); // Just to verify that it exists
163         this.services.remove(service.getName());
164         return service;
165     }
166
167     private void removePolicies(Service service) {
168         Collection<Policy> policyList = this.policies.getForService(service.getName());
169         for (Policy policy : policyList) {
170             this.policies.remove(policy);
171         }
172     }
173
174     private Service toService(ServiceRegistrationInfo s) {
175         return new Service(s.getServiceId(), Duration.ofSeconds(s.getKeepAliveIntervalSeconds()), s.getCallbackUrl());
176     }
177
178 }