84389b8c5d4e5101315f0b3813364de3c792a6e7
[policy/drools-applications.git] / controlloop / common / eventmanager / src / main / java / org / onap / policy / controlloop / eventmanager / ClEventManagerWithOutcome.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2023 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.controlloop.eventmanager;
23
24 import java.io.Serial;
25 import java.util.Deque;
26 import java.util.LinkedList;
27 import java.util.UUID;
28 import java.util.stream.Collectors;
29 import lombok.Getter;
30 import lombok.ToString;
31 import org.drools.core.WorkingMemory;
32 import org.onap.policy.controlloop.ControlLoopException;
33 import org.onap.policy.controlloop.ControlLoopNotificationType;
34 import org.onap.policy.controlloop.ControlLoopOperation;
35 import org.onap.policy.controlloop.ControlLoopResponse;
36 import org.onap.policy.controlloop.VirtualControlLoopNotification;
37 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
38 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
39 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
40 import org.onap.policy.drools.domain.models.operational.OperationalTarget;
41
42 /**
43  * Manager for a single control loop event, with operation outcomes.
44  */
45 @Getter
46 public abstract class ClEventManagerWithOutcome<T extends Step> extends ClEventManagerWithSteps<T>
47                 implements StepContext {
48
49     @Serial
50     private static final long serialVersionUID = -1216568161322872641L;
51
52     /**
53      * Number of attempts, so far, for the current step.
54      */
55     private int attempts;
56
57     /**
58      * Full history of operations that have been processed by the rules. This includes the
59      * items in {@link #partialHistory}.
60      */
61     private final transient Deque<OperationOutcome2> fullHistory = new LinkedList<>();
62
63     /**
64      * History of operations that have been processed by the rules for the current policy.
65      * When a step is started, its "start" outcome is added. However, once it completes,
66      * its "start" outcome is removed and the "completed" outcome is added.
67      */
68     private final transient Deque<OperationOutcome2> partialHistory = new LinkedList<>();
69
70
71     /**
72      * Constructs the object.
73      *
74      * @param services services the manager should use when processing the event
75      * @param params control loop parameters
76      * @param requestId event request ID
77      * @param workMem working memory to update if this changes
78      * @throws ControlLoopException if the event is invalid or if a YAML processor cannot
79      *         be created
80      */
81     protected ClEventManagerWithOutcome(EventManagerServices services, ControlLoopParams params, UUID requestId,
82                     WorkingMemory workMem) throws ControlLoopException {
83
84         super(services, params, requestId, workMem);
85     }
86
87     @Override
88     protected void loadPolicy() throws ControlLoopException {
89         partialHistory.clear();
90         super.loadPolicy();
91     }
92
93     @Override
94     public boolean executeStep() {
95         attempts = 0;
96         return super.executeStep();
97     }
98
99     /**
100      * Increments the number of attempts.
101      */
102     public void bumpAttempts() {
103         ++attempts;
104     }
105
106     /**
107      * Determines if the TOSCA should be aborted due to the given outcome.
108      *
109      * @param outcome outcome to examine
110      * @return {@code true} if the TOSCA should be aborted, {@code false} otherwise
111      */
112     public boolean isAbort(OperationOutcome outcome) {
113         return (outcome.getResult() != OperationResult.SUCCESS);
114     }
115
116     /**
117      * Adds the outcome to the history.
118      *
119      * @param outcome outcome to add
120      */
121     public void addToHistory(OperationOutcome outcome) {
122         OperationOutcome2 last = partialHistory.peekLast();
123
124         if (last != null && last.getOutcome().getEnd() == null
125                         && last.getOutcome().isFor(outcome.getActor(), outcome.getOperation())) {
126             // last item was a "start" - remove it
127             partialHistory.removeLast();
128
129             if (fullHistory.peekLast() == last) {
130                 fullHistory.removeLast();
131             }
132         }
133
134         var outcome2 = makeOperationOutcome2(outcome);
135         partialHistory.add(outcome2);
136         fullHistory.add(outcome2);
137     }
138
139     /**
140      * Makes a notification message for the current operation.
141      *
142      * @return a new notification
143      */
144     public VirtualControlLoopNotification makeNotification() {
145         var notif = new VirtualControlLoopNotification();
146         populateNotification(notif);
147
148         if (getFinalResult() != null) {
149             return notif;
150         }
151
152         OperationOutcome2 last = partialHistory.peekLast();
153         if (last == null) {
154             return notif;
155         }
156
157         notif.setMessage(last.getClOperation().toHistory());
158         notif.setHistory(partialHistory.stream().map(OperationOutcome2::getClOperation).collect(Collectors.toList()));
159
160         return notif;
161     }
162
163     /**
164      * Populates a notification structure.
165      *
166      * @param notif the notification to populate
167      */
168     protected void populateNotification(VirtualControlLoopNotification notif) {
169         notif.setNotification(ControlLoopNotificationType.OPERATION);
170         notif.setFrom("policy");
171         notif.setPolicyVersion(getPolicyVersion());
172     }
173
174     /**
175      * Get the last operation, as a message.
176      *
177      * @return the last operation, as a message
178      */
179     public String getOperationMessage() {
180         OperationOutcome2 last = fullHistory.peekLast();
181         return (last == null ? null : last.getClOperation().toMessage());
182     }
183
184     /**
185      * Makes a control loop response.
186      *
187      * @param outcome operation outcome
188      * @return a new control loop response, or {@code null} if none is required
189      */
190     public ControlLoopResponse makeControlLoopResponse(OperationOutcome outcome) {
191         var clRsp = new ControlLoopResponse();
192         clRsp.setFrom(outcome.getActor());
193
194         return clRsp;
195     }
196
197     @Getter
198     @ToString
199     public class OperationOutcome2 {
200         private final int attempt;
201         private final OperationOutcome outcome;
202         private final ControlLoopOperation clOperation;
203
204         /**
205          * Constructs the object.
206          *
207          * @param outcome outcome of the operation
208          */
209         public OperationOutcome2(OperationOutcome outcome) {
210             this.outcome = outcome;
211             this.attempt = attempts;
212
213             clOperation = outcome.toControlLoopOperation();
214
215             // TODO encode()?
216             OperationalTarget target = getPolicy().getActorOperation().getTarget();
217             String targetStr = (target != null ? target.toString() : null);
218             clOperation.setTarget(targetStr);
219
220             if (outcome.getEnd() == null) {
221                 clOperation.setOutcome("Started");
222             } else if (clOperation.getOutcome() == null) {
223                 clOperation.setOutcome("");
224             }
225         }
226     }
227
228     protected OperationOutcome2 makeOperationOutcome2(OperationOutcome outcome) {
229         return new OperationOutcome2(outcome);
230     }
231 }