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