Merge "Upgrade new tcagen2 policy type"
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / main / java / org / onap / policy / controlloop / actorserviceprovider / parameters / ControlLoopOperationParams.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. 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.policy.controlloop.actorserviceprovider.parameters;
22
23 import java.util.Map;
24 import java.util.UUID;
25 import java.util.concurrent.CompletableFuture;
26 import java.util.concurrent.Executor;
27 import java.util.concurrent.ForkJoinPool;
28 import java.util.function.Consumer;
29 import lombok.AllArgsConstructor;
30 import lombok.Builder;
31 import lombok.EqualsAndHashCode;
32 import lombok.Getter;
33 import org.onap.policy.common.parameters.BeanValidationResult;
34 import org.onap.policy.common.parameters.BeanValidator;
35 import org.onap.policy.common.parameters.annotations.NotNull;
36 import org.onap.policy.controlloop.VirtualControlLoopEvent;
37 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
38 import org.onap.policy.controlloop.actorserviceprovider.Operation;
39 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
40 import org.onap.policy.controlloop.actorserviceprovider.Util;
41 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
42 import org.onap.policy.controlloop.policy.Target;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * Parameters for control loop operations. The executor defaults to
48  * {@link ForkJoinPool#commonPool()}, but may be overridden.
49  */
50 @Getter
51 @Builder(toBuilder = true)
52 @AllArgsConstructor
53 @EqualsAndHashCode
54 public class ControlLoopOperationParams {
55     private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationParams.class);
56
57     /**
58      * Actor name.
59      */
60     @NotNull
61     private String actor;
62
63     /**
64      * Actor service in which to find the actor/operation.
65      */
66     @NotNull
67     private ActorService actorService;
68
69     /**
70      * Event for which the operation applies.
71      */
72     // TODO to be removed
73     private ControlLoopEventContext context;
74
75     /**
76      * If {@code null}, this value is extracted from the context.
77      */
78     private UUID requestId;
79
80     /**
81      * Executor to use to run the operation.
82      */
83     @NotNull
84     @Builder.Default
85     private Executor executor = ForkJoinPool.commonPool();
86
87     /**
88      * Operation name.
89      */
90     @NotNull
91     private String operation;
92
93     /**
94      * Payload data for the request.
95      */
96     private Map<String, Object> payload;
97
98     /**
99      * {@code True} if the preprocessing steps have already been executed, {@code false}
100      * otherwise.
101      */
102     private boolean preprocessed;
103
104     /**
105      * Number of retries allowed, or {@code null} if no retries.
106      */
107     private Integer retry;
108
109     /**
110      * The Target information, extracted from the Policy. May be {@code null}, depending
111      * on the requirement of the operation to be invoked.
112      */
113     private Target target;
114
115     /**
116      * Target entity.
117      */
118     // TODO to be removed
119     private String targetEntity;
120
121     /**
122      * Timeout, in seconds, or {@code null} if no timeout. Zero and negative values also
123      * imply no timeout.
124      */
125     @Builder.Default
126     private Integer timeoutSec = 300;
127
128     /**
129      * The function to invoke when the operation starts. This is optional.
130      * <p/>
131      * Note: this may be invoked multiple times, but with different actor/operations. That
132      * may happen if the current operation requires other operations to be performed first
133      * (e.g., A&AI queries, guard checks).
134      */
135     private Consumer<OperationOutcome> startCallback;
136
137     /**
138      * The function to invoke when the operation completes. This is optional.
139      * <p/>
140      * Note: this may be invoked multiple times, but with different actor/operations. That
141      * may happen if the current operation requires other operations to be performed first
142      * (e.g., A&AI queries, guard checks).
143      */
144     private Consumer<OperationOutcome> completeCallback;
145
146     /**
147      * Starts the specified operation.
148      *
149      * @return a future that will return the result of the operation
150      * @throws IllegalArgumentException if the parameters are invalid
151      */
152     public CompletableFuture<OperationOutcome> start() {
153         return build().start();
154     }
155
156     /**
157      * Builds the specified operation.
158      *
159      * @return a new operation
160      * @throws IllegalArgumentException if the parameters are invalid
161      */
162     public Operation build() {
163         BeanValidationResult result = validate();
164         if (!result.isValid()) {
165             logger.warn("parameter error in operation {}.{} for {}:\n{}", getActor(), getOperation(), getRequestId(),
166                             result.getResult());
167             throw new IllegalArgumentException("invalid parameters");
168         }
169
170         // @formatter:off
171         return actorService
172                     .getActor(getActor())
173                     .getOperator(getOperation())
174                     .buildOperation(this);
175         // @formatter:on
176     }
177
178     /**
179      * Gets the requested ID of the associated event.
180      *
181      * @return the event's request ID, or {@code null} if no request ID is available
182      */
183     public UUID getRequestId() {
184         if (requestId == null && context != null && context.getEvent() != null) {
185             // cache the request ID
186             requestId = context.getEvent().getRequestId();
187         }
188
189         return requestId;
190     }
191
192     /**
193      * Makes an operation outcome, populating it from the parameters.
194      *
195      * @return a new operation outcome
196      */
197     // TODO to be removed
198     public OperationOutcome makeOutcome() {
199         return makeOutcome(getTargetEntity());
200     }
201
202     /**
203      * Makes an operation outcome, populating it from the parameters.
204      *
205      * @param targetEntity the target entity
206      *
207      * @return a new operation outcome
208      */
209     public OperationOutcome makeOutcome(String targetEntity) {
210         OperationOutcome outcome = new OperationOutcome();
211         outcome.setActor(getActor());
212         outcome.setOperation(getOperation());
213         outcome.setTarget(targetEntity);
214
215         return outcome;
216     }
217
218     /**
219      * Invokes the callback to indicate that the operation has started. Any exceptions
220      * generated by the callback are logged, but not re-thrown.
221      *
222      * @param operation the operation that is being started
223      */
224     public void callbackStarted(OperationOutcome operation) {
225         logger.info("started operation {}.{} for {}", operation.getActor(), operation.getOperation(), getRequestId());
226
227         if (startCallback != null) {
228             Util.runFunction(() -> startCallback.accept(operation), "{}.{}: start-callback threw an exception for {}",
229                             operation.getActor(), operation.getOperation(), getRequestId());
230         }
231     }
232
233     /**
234      * Invokes the callback to indicate that the operation has completed. Any exceptions
235      * generated by the callback are logged, but not re-thrown.
236      *
237      * @param operation the operation that is being started
238      */
239     public void callbackCompleted(OperationOutcome operation) {
240         logger.info("completed operation {}.{} outcome={} for {}", operation.getActor(), operation.getOperation(),
241                         operation.getResult(), getRequestId());
242
243         if (completeCallback != null) {
244             Util.runFunction(() -> completeCallback.accept(operation),
245                             "{}.{}: complete-callback threw an exception for {}", operation.getActor(),
246                             operation.getOperation(), getRequestId());
247         }
248     }
249
250     /**
251      * Validates the parameters.
252      *
253      * @return the validation result
254      */
255     public BeanValidationResult validate() {
256         BeanValidationResult result =
257                         new BeanValidator().validateTop(ControlLoopOperationParams.class.getSimpleName(), this);
258
259         // validate that we have a request ID, or that we can get it from the context's
260         // event
261
262         if (context == null) {
263             // no context specified - invoker must provide a request ID then
264             result.validateNotNull("requestId", requestId);
265
266         } else if (requestId == null) {
267             // have a context, but no request ID - check the context's event for the
268             // request ID
269             BeanValidationResult contextResult = new BeanValidationResult("context", context);
270             VirtualControlLoopEvent event = context.getEvent();
271             contextResult.validateNotNull("event", event);
272
273             if (event != null) {
274                 // cache the request id for later use
275                 BeanValidationResult eventResult = new BeanValidationResult("event", event);
276                 eventResult.validateNotNull("requestId", event.getRequestId());
277
278                 contextResult.addResult(eventResult);
279             }
280
281             result.addResult(contextResult);
282         }
283
284         return result;
285     }
286 }