Add Apache license header per file
[externalapi/nbi.git] / src / main / java / org / onap / nbi / apis / serviceorder / workflow / SOTaskProcessor.java
1 /**
2  *
3  *     Copyright (c) 2017 Orange.  All rights reserved.
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 package org.onap.nbi.apis.serviceorder.workflow;
18
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Date;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import org.onap.nbi.apis.serviceorder.SoClient;
26 import org.onap.nbi.apis.serviceorder.model.ServiceCharacteristic;
27 import org.onap.nbi.apis.serviceorder.model.ServiceOrder;
28 import org.onap.nbi.apis.serviceorder.model.ServiceOrderItem;
29 import org.onap.nbi.apis.serviceorder.model.StateType;
30 import org.onap.nbi.apis.serviceorder.model.consumer.CloudConfiguration;
31 import org.onap.nbi.apis.serviceorder.model.consumer.CreateServiceInstanceResponse;
32 import org.onap.nbi.apis.serviceorder.model.consumer.GetRequestStatusResponse;
33 import org.onap.nbi.apis.serviceorder.model.consumer.ModelInfo;
34 import org.onap.nbi.apis.serviceorder.model.consumer.RequestDetails;
35 import org.onap.nbi.apis.serviceorder.model.consumer.RequestInfo;
36 import org.onap.nbi.apis.serviceorder.model.consumer.RequestParameters;
37 import org.onap.nbi.apis.serviceorder.model.consumer.RequestState;
38 import org.onap.nbi.apis.serviceorder.model.consumer.SubscriberInfo;
39 import org.onap.nbi.apis.serviceorder.model.consumer.UserParams;
40 import org.onap.nbi.apis.serviceorder.model.orchestrator.ExecutionTask;
41 import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfo;
42 import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfoJson;
43 import org.onap.nbi.apis.serviceorder.repositories.ExecutionTaskRepository;
44 import org.onap.nbi.apis.serviceorder.repositories.ServiceOrderRepository;
45 import org.onap.nbi.apis.serviceorder.utils.JsonEntityConverter;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.beans.factory.annotation.Value;
50 import org.springframework.http.HttpStatus;
51 import org.springframework.http.ResponseEntity;
52 import org.springframework.stereotype.Service;
53 import org.springframework.util.CollectionUtils;
54
55 @Service
56 public class SOTaskProcessor {
57
58     @Value("${nbi.callForVNF}")
59     private boolean enableCallForVNF;
60
61     @Value("${onap.lcpCloudRegionId}")
62     private String lcpCloudRegionId;
63
64     @Value("${onap.tenantId}")
65     private String tenantId;
66
67     @Autowired
68     private ServiceOrderRepository serviceOrderRepository;
69
70     @Autowired
71     private ExecutionTaskRepository executionTaskRepository;
72
73     @Autowired
74     private SoClient soClient;
75
76
77     private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
78
79     /**
80      * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
81      */
82     public void processOrderItem(ExecutionTask executionTask) {
83
84
85         ServiceOrderInfoJson serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
86         ServiceOrder serviceOrder = serviceOrderRepository.findOne(serviceOrderInfoJson.getServiceOrderId());
87         ServiceOrderItem serviceOrderItem = null;
88         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
89             if (item.getId().equals(executionTask.getOrderItemId())) {
90                 serviceOrderItem = item;
91             }
92         }
93
94         ServiceOrderInfo serviceOrderInfo = null;
95         try {
96             serviceOrderInfo =
97                     JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson.getServiceOrderInfoJson());
98         } catch (IOException e) {
99             LOGGER.error("Unable to read ServiceOrderInfo Json for serviceOrderId " + serviceOrder.getId() + ", "
100                     + e.getMessage());
101         }
102
103         if (StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
104
105             ResponseEntity<CreateServiceInstanceResponse> response = postSORequest(serviceOrderItem, serviceOrderInfo);
106
107             updateServiceOrderItem(response.getBody(), serviceOrderItem);
108
109             if (response.getStatusCode() != HttpStatus.CREATED || response.getBody() == null
110                     || response.getBody().getRequestReference() == null) {
111                 serviceOrderItem.setState(StateType.FAILED);
112             } else {
113                 serviceOrderItem.setState(StateType.INPROGRESS);
114             }
115         }
116
117         if (executionTask.getNbRetries() > 0) {
118             // TODO lancer en asynchrone
119             pollSoRequestStatus(serviceOrderItem);
120             if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
121                 updateSuccessTask(executionTask);
122             } else {
123                 int nbRetries = executionTask.getNbRetries();
124                 executionTask.setNbRetries(--nbRetries);
125                 executionTask.setLastAttemptDate(new Date());
126                 executionTaskRepository.save(executionTask);
127             }
128         } else {
129             updateFailedTask(executionTask, serviceOrder);
130         }
131
132
133         updateServiceOrder(serviceOrder);
134     }
135
136     private ResponseEntity<CreateServiceInstanceResponse> postSORequest(ServiceOrderItem serviceOrderItem,
137             ServiceOrderInfo serviceOrderInfo) {
138         RequestDetails requestDetails = buildSoRequest(serviceOrderItem,
139                 serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()).getCatalogResponse(),
140                 serviceOrderInfo.getSubscriberInfo());
141         ResponseEntity<CreateServiceInstanceResponse> response = null;
142
143         switch (serviceOrderItem.getAction()) {
144             case ADD:
145                 response = soClient.callCreateServiceInstance(requestDetails);
146                 break;
147             case DELETE:
148                 response = soClient.callDeleteServiceInstance(requestDetails, serviceOrderItem.getService().getId());
149                 break;
150             default:
151                 break;
152         }
153         return response;
154     }
155
156     private void updateServiceOrder(ServiceOrder serviceOrder) {
157         boolean atLeastOneCompleted = false;
158         boolean atLeastOneNotFinished = false;
159         boolean atLeastOneFailed = false;
160
161
162         for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
163             switch (serviceOrderItem.getState()) {
164                 case COMPLETED:
165                     atLeastOneCompleted = true;
166                     break;
167                 case INPROGRESS:
168                 case ACKNOWLEDGED:
169                     atLeastOneNotFinished = true;
170                     break;
171                 case FAILED:
172                     atLeastOneFailed = true;
173                     break;
174                 default:
175                     break;
176
177             }
178         }
179
180         if (atLeastOneNotFinished) {
181             serviceOrder.setState(StateType.INPROGRESS);
182         } else {
183             serviceOrder.setCompletionDateTime(new Date());
184             if (atLeastOneFailed) {
185                 if (!atLeastOneCompleted) {
186                     serviceOrder.setState(StateType.FAILED);
187                 } else {
188                     serviceOrder.setState(StateType.PARTIAL);
189                 }
190             } else {
191                 serviceOrder.setState(StateType.COMPLETED);
192             }
193         }
194         serviceOrderRepository.save(serviceOrder);
195     }
196
197
198     /**
199      * * @param orderItem
200      */
201     private void pollSoRequestStatus(ServiceOrderItem orderItem) {
202         boolean stopPolling = false;
203         String requestId = orderItem.getRequestId();
204         GetRequestStatusResponse response = null;
205         int nbRetries = 0;
206
207         while (!stopPolling) {
208             response = soClient.callGetRequestStatus(requestId);
209             if (response != null) {
210                 if (response.getRequest().getRequestStatus().getPercentProgress() != 100) {
211                     nbRetries++;
212                     orderItem.setState(StateType.INPROGRESS);
213                     try {
214                         Thread.sleep(1000);
215                     } catch (InterruptedException e) {
216                         e.printStackTrace();
217                     }
218                 } else if (RequestState.COMPLETE != response.getRequest().getRequestStatus().getRequestState()) {
219                     orderItem.setState(StateType.FAILED);
220                     stopPolling = true;
221                 } else {
222                     orderItem.setState(StateType.COMPLETED);
223                     stopPolling = true;
224                 }
225             } else {
226                 orderItem.setState(StateType.INPROGRESS);
227                 stopPolling = true;
228             }
229             if (nbRetries == 3) {
230                 stopPolling = true;
231             }
232         }
233     }
234
235     /**
236      * Build SO CREATE request from the ServiceOrder and catalog informations from SDC
237      *
238      * @param orderItem
239      * @param sdcInfos
240      * @param subscriberInfo
241      * @return
242      */
243     private RequestDetails buildSoRequest(ServiceOrderItem orderItem, LinkedHashMap<String, Object> sdcInfos,
244             SubscriberInfo subscriberInfo) {
245         RequestDetails requestDetails = new RequestDetails();
246
247         requestDetails.setSubscriberInfo(subscriberInfo);
248
249         ModelInfo modelInfo = new ModelInfo();
250         modelInfo.setModelType("service");
251         modelInfo.setModelInvariantId((String) sdcInfos.get("invariantUUID"));
252         modelInfo.setModelNameVersionId(orderItem.getService().getServiceSpecification().getId());
253         modelInfo.setModelName((String) sdcInfos.get("name"));
254         modelInfo.setModelVersion((String) sdcInfos.get("version"));
255         requestDetails.setModelInfo(modelInfo);
256
257         RequestInfo requestInfo = new RequestInfo();
258         requestInfo.setInstanceName(orderItem.getService().getName());
259         requestInfo.setSource("VID");
260         requestInfo.setSuppressRollback(false);
261         requestDetails.setRequestInfo(requestInfo);
262
263         RequestParameters requestParameters = new RequestParameters();
264         requestParameters.setSubscriptionServiceType((String) sdcInfos.get("name"));
265         requestParameters.setUserParams(
266                 retrieveUserParamsFromServiceCharacteristics(orderItem.getService().getServiceCharacteristic()));
267         requestParameters.setaLaCarte(true);
268         requestDetails.setRequestParameters(requestParameters);
269
270         CloudConfiguration cloudConfiguration = new CloudConfiguration(lcpCloudRegionId, tenantId);
271         requestDetails.setCloudConfiguration(cloudConfiguration);
272         return requestDetails;
273     }
274
275     /**
276      * Build a list of UserParams for the SO request by browsing a list of ServiceCharacteristics
277      * from SDC
278      *
279      * @param characteristics
280      * @return
281      */
282     private List<UserParams> retrieveUserParamsFromServiceCharacteristics(List<ServiceCharacteristic> characteristics) {
283         List<UserParams> userParams = new ArrayList<UserParams>();
284
285         if (!CollectionUtils.isEmpty(characteristics)) {
286             for (ServiceCharacteristic characteristic : characteristics) {
287                 UserParams userParam = new UserParams(characteristic.getName(),
288                         characteristic.getValue().getServiceCharacteristicValue());
289                 userParams.add(userParam);
290             }
291         }
292
293         return userParams;
294     }
295
296
297     /**
298      * Update ServiceOrderItem with SO response by using serviceOrderRepository with the
299      * serviceOrderId
300      *
301      * @param createServiceInstanceResponse
302      * @param orderItem
303      */
304     private void updateServiceOrderItem(CreateServiceInstanceResponse createServiceInstanceResponse,
305             ServiceOrderItem orderItem) {
306
307         if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
308             orderItem.getService().setId(createServiceInstanceResponse.getRequestReference().getInstanceId());
309             orderItem.setRequestId(createServiceInstanceResponse.getRequestReference().getRequestId());
310         }
311     }
312
313     /**
314      * Update an executionTask in database when it's process with a success
315      *
316      * @param executionTask
317      */
318     private void updateSuccessTask(ExecutionTask executionTask) {
319         executionTaskRepository.delete(executionTask.getInternalId());
320         executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
321     }
322
323     /**
324      * @param executionTask
325      * @param serviceOrder
326      */
327     private void updateFailedTask(ExecutionTask executionTask, ServiceOrder serviceOrder) {
328         List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
329         for (ExecutionTask taskId : executionTasksToDelete) {
330             executionTaskRepository.delete(taskId);
331         }
332
333         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
334             for (ExecutionTask taskToDelete : executionTasksToDelete) {
335                 if (taskToDelete.getOrderItemId().equals(item.getId())) {
336                     item.setState(StateType.FAILED);
337                 }
338             }
339         }
340     }
341
342     /**
343      * @param executionTask
344      * @return
345      */
346     private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
347
348         List<ExecutionTask> executionTasks = new ArrayList<>();
349
350         List<ExecutionTask> tasksReliedToAnOrderItemId =
351                 executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
352
353         if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
354             return Arrays.asList(executionTask);
355         } else {
356             for (ExecutionTask task : tasksReliedToAnOrderItemId) {
357                 executionTasks.addAll(findExecutionTasksRecursively(task));
358             }
359         }
360         executionTasks.add(executionTask);
361         return executionTasks;
362     }
363
364
365 }