transaction records cleanup
[policy/drools-applications.git] / controlloop / common / controller-usecases / src / main / resources / usecases.drl
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020-2022 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;
22
23 import java.time.Instant;
24 import java.util.Collections;
25 import java.util.stream.Collectors;
26 import org.onap.policy.controlloop.CanonicalOnset;
27 import org.onap.policy.controlloop.VirtualControlLoopEvent;
28 import org.onap.policy.controlloop.VirtualControlLoopNotification;
29 import org.onap.policy.controlloop.ControlLoopNotificationType;
30 import org.onap.policy.controlloop.actor.xacml.XacmlActor;
31 import org.onap.policy.controlloop.actorserviceprovider.Operation;
32 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
33 import org.onap.policy.controlloop.actorserviceprovider.OperationFinalResult;
34 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
35 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
36 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
37 import org.onap.policy.controlloop.eventmanager.ActorConstants;
38 import org.onap.policy.controlloop.eventmanager.Step;
39 import org.onap.policy.controlloop.utils.ControlLoopUtils;
40 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager;
41 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithSteps.State;
42 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithOutcome.OperationOutcome2;
43 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithEvent.NewEventStatus;
44 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
45 import org.onap.policy.controlloop.eventmanager.EventManagerServices;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
47
48 import org.slf4j.LoggerFactory;
49 import org.slf4j.Logger;
50
51 import org.onap.policy.drools.system.PolicyEngineConstants;
52
53
54 /*
55 * Called at initial start-up, to create the event services that will be used by all
56 * event managers in this rule engine instance.
57 */
58 rule "CREATE.EVENT.SERVICES"
59     when
60         not (EventManagerServices())
61     then
62
63     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
64     logger.info("{}", drools.getRule().getName());
65
66     try {
67         insert(new EventManagerServices("event-manager"));
68
69     } catch(RuntimeException e) {
70         logger.warn("{}: cannot create event services", drools.getRule().getName(), e);
71     }
72 end
73
74 /*
75 *
76 * Called when the ControlLoopParams object has been inserted into working memory from the PAP.
77 *
78 */
79 rule "INSERT.PARAMS"
80     when
81         $params : ControlLoopParams()
82     then
83
84     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
85     logger.info("{}: {} : TOSCA-POLICY=[{}]", $params.getClosedLoopControlName(), $params.getPolicyName() + "."
86         + drools.getRule().getName(), $params.getToscaPolicy());
87 end
88
89 /*
90 *
91 * Called when a Tosca Policy is present.
92 *
93 */
94 rule "NEW.TOSCA.POLICY"
95     when
96         $policy : ToscaPolicy()
97     then
98
99     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
100     logger.info("{}: [{}|{}|{}|{}]: CONTENT: {}", drools.getRule().getName(),
101                 $policy.getType(), $policy.getTypeVersion(), $policy.getName(),
102                 $policy.getVersion(), $policy);
103
104     ControlLoopParams params = ControlLoopUtils.toControlLoopParams($policy);
105     if (params != null) {
106         insert(params);
107     }
108 end
109
110 /*
111  * Remove Control Loop Parameters.
112  */
113 rule "REMOVE.PARAMS"
114     when
115         $params : ControlLoopParams( $policyName :  getPolicyName(), $policyVersion : getPolicyVersion() )
116         not ( ToscaPolicy( getName() == $policyName, getVersion() == $policyVersion ) )
117     then
118
119     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
120     logger.info("{}: [{}|{}|{}]", drools.getRule().getName(),
121                 $params.getPolicyScope(), $params.getPolicyName(), $params.getPolicyVersion());
122
123     retract($params);
124 end
125
126 /*
127 *
128 * This rule responds to DCAE Events where there is no manager yet. Either it is
129 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
130 *
131 */
132 rule "EVENT"
133     when
134         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
135         $event : CanonicalOnset( closedLoopControlName == $clName )
136         $services : EventManagerServices()
137         not ( UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
138             getEvent() == $event ) )
139     then
140
141     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
142     logger.info("{}: {}.{}: event={}",
143                 $clName, $params.getPolicyName(), drools.getRule().getName(),
144                 $event);
145     //
146     // Retract the event from memory; it will be managed by the manager from now on
147     //
148     retract($event);
149
150     VirtualControlLoopNotification notification = null;
151
152     try {
153         //
154         // Check the event, because we need it to not be null when
155         // we create the UsecasesEventManager. The UsecasesEventManager
156         // will do extra syntax checking as well as check if the closed loop is disabled.
157         //
158         if ($event.getRequestId() == null) {
159             notification = new VirtualControlLoopNotification($event);
160             notification.setNotification(ControlLoopNotificationType.REJECTED);
161             notification.setFrom("policy");
162             notification.setMessage("Missing requestId");
163             notification.setPolicyScope(drools.getRule().getName());
164             notification.setPolicyName($params.getPolicyName());
165             notification.setPolicyVersion($params.getPolicyVersion());
166
167         } else {
168             UsecasesEventManager manager =
169                 new UsecasesEventManager($services, $params, $event, drools.getWorkingMemory());
170             insert(manager);
171             try {
172                 // load the first policy/step
173                 manager.start();
174
175                 if (manager.getSteps().isEmpty()) {
176                     // no steps implies no policies, thus go straight to DONE state
177                     manager.setState(State.DONE);
178
179                     manager.setAccepted(true);
180
181                     notification = manager.makeNotification();
182                     notification.setNotification(ControlLoopNotificationType.ACTIVE);
183                     notification.setPolicyScope(drools.getRule().getName());
184                     notification.setPolicyName($params.getPolicyName());
185                     notification.setPolicyVersion($params.getPolicyVersion());
186
187                 } else {
188                     // Note: the notification will be generated lazily
189                     manager.setState(State.POLICY_LOADED);
190                 }
191
192             } catch(Exception e) {
193                 retract(manager);
194                 throw e;
195             }
196         }
197     } catch (Exception e) {
198         logger.warn("{}: {}.{}: error starting manager", $clName, $params.getPolicyName(),
199                         drools.getRule().getName(), e);
200         notification = new VirtualControlLoopNotification($event);
201         notification.setNotification(ControlLoopNotificationType.REJECTED);
202         notification.setMessage("Exception occurred: " + e.getMessage());
203         notification.setPolicyScope(drools.getRule().getName());
204         notification.setPolicyName($params.getPolicyName());
205         notification.setPolicyVersion($params.getPolicyVersion());
206     }
207     //
208     // Generate notification
209     //
210     try {
211         if (notification != null) {
212             PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
213         }
214
215     } catch(RuntimeException e) {
216         logger.warn("{}: {}.{}: event={} exception generating notification",
217                 $clName, $params.getPolicyName(), drools.getRule().getName(),
218                 $event, e);
219     }
220 end
221
222 /*
223 *
224 * This rule fires when we get a subsequent event.
225 *
226 */
227 rule "EVENT.MANAGER.NEW.EVENT"
228     when
229         $event : VirtualControlLoopEvent( )
230         $manager : UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
231             getEvent() == $event )
232     then
233
234     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
235     logger.info("{}: {}.{}: event={} manager={}",
236             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
237             $event, $manager);
238     //
239     // Remove the event from memory
240     //
241     retract($event);
242
243     //
244     // Check what kind of event this is
245     //
246     switch($manager.onNewEvent($event)) {
247         case SYNTAX_ERROR:
248             //
249             // Ignore any bad syntax events
250             //
251             logger.warn("{}: {}.{}: syntax error",
252                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
253             break;
254
255         case FIRST_ABATEMENT:
256         case SUBSEQUENT_ABATEMENT:
257             //
258             // TODO: handle the abatement.  Currently, it's just discarded.
259             //
260             logger.info("{}: {}.{}: abatement",
261                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
262             break;
263
264         case FIRST_ONSET:
265         case SUBSEQUENT_ONSET:
266         default:
267             //
268             // We don't care about subsequent onsets
269             //
270             logger.warn("{}: {}.{}: subsequent onset",
271                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
272             break;
273     }
274 end
275
276 /*
277 *
278 * All steps have been executed, load the next policy.
279 *
280 */
281 rule "EVENT.MANAGER.LOAD.NEXT.POLICY"
282     when
283         $manager : UsecasesEventManager(
284                         isActive(),
285                         getState() == State.POLICY_LOADED,
286                         getSteps().isEmpty() )
287     then
288
289     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
290     logger.info("{}: {}.{}: manager={}",
291             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
292             $manager);
293
294     try {
295         $manager.loadNextPolicy($manager.getResult());
296
297         if ($manager.getSteps().isEmpty()) {
298             // no steps - must be the final policy
299             $manager.setState(State.DONE);
300         }
301
302     } catch(RuntimeException e) {
303         logger.warn("{}: {}.{}: manager={} exception loading next policy",
304                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
305                 $manager, e);
306         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to load next policy");
307     }
308
309     update($manager);
310 end
311
312 /*
313 *
314 * Policy loaded, identify any preprocessor steps that need to be run first.
315 *
316 */
317 rule "EVENT.MANAGER.PREPROCESS"
318     when
319         $manager : UsecasesEventManager(
320                         isActive(),
321                         getState() == State.POLICY_LOADED,
322                         $step : getSteps().peek(),
323                         $step != null,
324                         !$step.isPreprocessed() )
325     then
326
327     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
328     logger.info("{}: {}.{}: {} manager={}",
329             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
330             $step, $manager);
331
332     try {
333         /*
334          * Load any preprocessor steps.
335          *
336          * Note: this will not change the state of the manager, but it may change the
337          * state of the step.
338          */
339         $step.setPreprocessed(true);
340         $manager.loadPreprocessorSteps();
341
342     } catch(RuntimeException e) {
343         logger.warn("{}: {}.{}: manager={} exception loading preprocessor steps",
344                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
345                 $manager, e);
346         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to load preprocessing steps");
347     }
348
349     update($manager);
350 end
351
352 /*
353 *
354 * Accepts the event, when ready to execute a step of interest.  Does not change the
355 * state of the manager, leaving that to be done by rule "EVENT.MANAGER.EXECUTE.STEP".
356 *
357 */
358 rule "EVENT.MANAGER.ACCEPT"
359     salience 200
360     when
361         $manager : UsecasesEventManager(
362                         isActive(),
363                         !isAccepted(),
364                         getState() == State.POLICY_LOADED,
365                         $step : getSteps().peek(),
366                         $step != null,
367                         $step.isPreprocessed(),
368                         $step.acceptsEvent() )
369     then
370
371     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
372     logger.info("{}: {}.{}: manager={}",
373             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
374             $step, $manager);
375
376     try {
377         $manager.setAccepted(true);
378
379         VirtualControlLoopNotification notification = $manager.makeNotification();
380         notification.setNotification(ControlLoopNotificationType.ACTIVE);
381         notification.setPolicyScope(drools.getRule().getName());
382         notification.setPolicyName($manager.getPolicyName());
383         notification.setPolicyVersion($manager.getPolicyVersion());
384         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
385
386     } catch(RuntimeException e) {
387         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
388                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
389                 $manager, e);
390         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to accept the event");
391     }
392
393     update($manager);
394 end
395
396 /*
397 *
398 * Ready to execute the step.
399 *
400 */
401 rule "EVENT.MANAGER.EXECUTE.STEP"
402     when
403         $manager : UsecasesEventManager(
404                         isActive(),
405                         getState() == State.POLICY_LOADED,
406                         $step : getSteps().peek(),
407                         $step != null,
408                         $step.isPreprocessed() )
409     then
410
411     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
412     logger.info("{}: {}.{}: {} manager={}",
413             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
414             $step, $manager);
415
416     try {
417         $step.init();
418         $step.setProperties();
419
420         boolean guardDisabled = "true".equalsIgnoreCase(
421                     PolicyEngineConstants.getManager().getEnvironmentProperty(
422                         ControlLoopEventManager.GUARD_DISABLED_PROPERTY));
423
424         if (guardDisabled && XacmlActor.NAME.equals($step.getActorName())) {
425             // guard is disabled - just enqueue a "SUCCESS" (i.e., "Permit")
426             OperationOutcome outcome = $step.getParams().makeOutcome();
427             outcome.setStart(Instant.now());
428             outcome.setEnd(outcome.getStart());
429
430             $manager.getOutcomes().add(outcome);
431             $manager.setState(State.AWAITING_OUTCOME);
432
433         } else if ($manager.executeStep()) {
434             $manager.setState(State.AWAITING_OUTCOME);
435
436         } else {
437             // this step is no longer necessary - try the next one
438             $manager.nextStep();
439         }
440
441     } catch(RuntimeException e) {
442         logger.warn("{}: {}.{}: manager={} exception executing a step",
443                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
444                 $manager, e);
445         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to execute the next step");
446     }
447
448     update($manager);
449 end
450
451 /*
452 *
453 * Generate SDNR notification.  Does not discard the outcome from the queue, leaving it to be
454 * handled by rule "EVENT.MANAGER.PROCESS.OUTCOME".
455 *
456 */
457 rule "EVENT.MANAGER.GENERATE.SDNR.NOTIFICATION"
458     // this should fire BEFORE the "EVENT.MANAGER.PROCESS.OUTCOME" rule
459     salience 100
460     when
461         $manager : UsecasesEventManager(
462                         isActive(),
463                         getState() == State.AWAITING_OUTCOME,
464                         $outcome : getOutcomes().peek(),
465                         $outcome != null,
466                         $outcome.getEnd() != null,
467                         !isAbort($outcome),
468                         $step : getSteps().peek(),
469                         "SDNR".equals($step.getActorName()),
470                         $outcome.isFor("SDNR", $step.getOperationName()) )
471     then
472
473     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
474     logger.info("{}: {}.{}: {} manager={}",
475             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
476             $step, $manager);
477
478     try {
479         ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome);
480         $manager.deliver("DCAE_CL_RSP", clResponse, "SDNR notification", drools.getRule().getName());
481
482     } catch(RuntimeException e) {
483         logger.warn("{}: {}.{}: manager={} exception generating SDNR Response notification",
484                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
485                 $manager, e);
486     }
487 end
488
489 /*
490 *
491 * Process a GUARD outcome.  Does not discard the outcome from the queue, leaving it to be
492 * handled by rule "EVENT.MANAGER.PROCESS.OUTCOME".
493 *
494 */
495 rule "EVENT.MANAGER.PROCESS.GUARD.OUTCOME"
496     salience 100
497     when
498         $manager : UsecasesEventManager(
499                         isActive(),
500                         getState() == State.AWAITING_OUTCOME,
501                         $outcome : getOutcomes().peek(),
502                         $outcome != null,
503                         !isAbort($outcome),
504                         $step : getSteps().peek(),
505                         XacmlActor.NAME.equals($step.getActorName()),
506                         $outcome.isFor($step.getActorName(), $step.getOperationName()) )
507     then
508
509     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
510     logger.info("{}: {}.{}: {} manager={}",
511             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
512             $step, $manager);
513
514     try {
515         VirtualControlLoopNotification notification = $manager.makeNotification();
516         notification.setNotification(ControlLoopNotificationType.OPERATION);
517         notification.setPolicyScope(drools.getRule().getName());
518         notification.setPolicyName($manager.getPolicyName());
519         notification.setPolicyVersion($manager.getPolicyVersion());
520         notification.setHistory(Collections.emptyList());
521
522         // get actor/operation name from the policy step, not from the guard step
523         Step step2 = $step.getParentStep();
524
525         if ($outcome.getEnd() == null) {
526             // it's a "start" operation
527             notification.setMessage("Sending guard query for " + step2.getActorName() + " " + step2.getOperationName());
528
529         } else if ($outcome.getResult() == OperationResult.SUCCESS) {
530             notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName()
531                                         + " is Permit");
532         } else {
533             // it's a failure
534             notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName()
535                                         + " is Deny");
536         }
537
538         $manager.deliver("POLICY-CL-MGT", notification, "GUARD notification", drools.getRule().getName());
539
540     } catch(RuntimeException e) {
541         logger.warn("{}: {}.{}: manager={} exception generating GUARD notification",
542                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
543                 $manager, e);
544     }
545 end
546
547 /*
548 *
549 * Process an outcome when the policy's operation starts.
550 *
551 */
552 rule "EVENT.MANAGER.PROCESS.POLICY.STARTED"
553     when
554         $manager : UsecasesEventManager(
555                         isActive(),
556                         getState() == State.AWAITING_OUTCOME,
557                         $outcome : getOutcomes().peek(),
558                         $outcome != null,
559                         $outcome.getEnd() == null,
560                         $step : getSteps().peek(),
561                         $step.isPolicyStep(),
562                         $outcome.isFor($step.getActorName(), $step.getOperationName()) )
563     then
564
565     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
566     logger.info("{}: {}.{}: {} manager={}",
567             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
568             $step, $manager);
569
570     try {
571         $manager.getOutcomes().remove();
572
573         // it's a "start" operation for the step
574         $manager.bumpAttempts();
575
576         $manager.addToHistory($outcome);
577         $manager.storeInDataBase($manager.getPartialHistory().peekLast());
578
579         VirtualControlLoopNotification notification = $manager.makeNotification();
580         notification.setNotification(ControlLoopNotificationType.OPERATION);
581         notification.setPolicyScope(drools.getRule().getName());
582         notification.setPolicyName($manager.getPolicyName());
583         notification.setPolicyVersion($manager.getPolicyVersion());
584         notification.setHistory(Collections.emptyList());
585         notification.setMessage($manager.getOperationMessage());
586
587         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
588
589     } catch(RuntimeException e) {
590         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
591                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
592                 $manager, e);
593         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'start' outcome");
594     }
595
596     update($manager);
597 end
598
599 /*
600 *
601 * Process an outcome when an arbitrary Preprocessor step starts.
602 *
603 */
604 rule "EVENT.MANAGER.PROCESS.PREPROCESSOR.STARTED"
605     when
606         $manager : UsecasesEventManager(
607                         isActive(),
608                         getState() == State.AWAITING_OUTCOME,
609                         $outcome : getOutcomes().peek(),
610                         $outcome != null,
611                         $outcome.getEnd() == null,
612                         $step : getSteps().peek(),
613                         !$step.isPolicyStep(),
614                         $outcome.isFor($step.getActorName(), $step.getOperationName()) )
615     then
616
617     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
618     logger.info("{}: {}.{}: {} manager={}",
619             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
620             $step, $manager);
621
622     try {
623         $manager.getOutcomes().remove();
624
625         // it's a "start" operation for the step
626         $manager.bumpAttempts();
627
628     } catch(RuntimeException e) {
629         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
630                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
631                 $manager, e);
632         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle 'start' outcome");
633     }
634
635     update($manager);
636 end
637
638 /*
639 *
640 * Process an outcome when the policy's operation succeeds.
641 *
642 */
643 rule "EVENT.MANAGER.PROCESS.POLICY.SUCCESS"
644     when
645         $manager : UsecasesEventManager(
646                         isActive(),
647                         getState() == State.AWAITING_OUTCOME,
648                         $outcome : getOutcomes().peek(),
649                         $outcome != null,
650                         $outcome.getEnd() != null,
651                         $outcome.getResult() == OperationResult.SUCCESS,
652                         $step : getSteps().peek(),
653                         $step.isPolicyStep(),
654                         $outcome.isFor($step.getActorName(), $step.getOperationName()) )
655     then
656
657     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
658     logger.info("{}: {}.{}: {} manager={}",
659             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
660             $step, $manager);
661
662     try {
663         $manager.getOutcomes().remove();
664
665         // let the step record the response that's contained within the outcome
666         $step.success($outcome);
667
668         $manager.addToHistory($outcome);
669         $manager.storeInDataBase($manager.getPartialHistory().peekLast());
670
671         $manager.setResult($outcome.getResult());
672
673         VirtualControlLoopNotification notification = $manager.makeNotification();
674         notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
675         notification.setPolicyScope(drools.getRule().getName());
676         notification.setPolicyName($manager.getPolicyName());
677         notification.setPolicyVersion($manager.getPolicyVersion());
678         notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
679                                 .collect(Collectors.toList()));
680
681         // this step is complete - discard it
682         $manager.getSteps().remove();
683
684         $manager.setState(State.POLICY_LOADED);
685
686         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
687
688     } catch(RuntimeException e) {
689         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
690                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
691                 $manager, e);
692         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'success' outcome");
693     }
694
695     update($manager);
696 end
697
698 /*
699 *
700 * Process a final failure outcome, when the event has been accepted.
701 *
702 */
703 rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.ACCEPTED"
704     when
705         $manager : UsecasesEventManager(
706                         isActive(),
707                         isAccepted(),
708                         getState() == State.AWAITING_OUTCOME,
709                         $outcome : getOutcomes().peek(),
710                         $outcome != null,
711                         !isAbort($outcome),
712                         $outcome.getEnd() != null,
713                         $outcome.isFinalOutcome(),
714                         $outcome.getResult() != OperationResult.SUCCESS,
715                         $step : getSteps().peek() )
716     then
717
718     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
719     logger.info("{}: {}.{}: {} manager={}",
720             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
721             $step, $manager);
722
723     try {
724         $manager.getOutcomes().remove();
725
726         if (!$outcome.isFor($step.getActorName(), $step.getOperationName())) {
727             $outcome.setResult(OperationResult.FAILURE_GUARD);
728             $outcome.setMessage("Operation denied by " + $outcome.getActor());
729         }
730
731         // final failure for this policy
732         $manager.addToHistory($outcome);
733         $manager.storeInDataBase($manager.getPartialHistory().peekLast());
734
735         $manager.setResult($outcome.getResult());
736
737         VirtualControlLoopNotification notification = $manager.makeNotification();
738         notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
739         notification.setPolicyScope(drools.getRule().getName());
740         notification.setPolicyName($manager.getPolicyName());
741         notification.setPolicyVersion($manager.getPolicyVersion());
742         notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
743                                 .collect(Collectors.toList()));
744
745         // trigger move to the next policy - clear all steps
746         $manager.getSteps().clear();
747         $manager.setState(State.POLICY_LOADED);
748
749         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
750
751     } catch(RuntimeException e) {
752         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
753                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
754                 $manager, e);
755         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome");
756     }
757
758     update($manager);
759 end
760
761 /*
762 *
763 * Process a final failure outcome, when the event has NOT been accepted.  This typically
764 * occurs when an A&AI query fails BEFORE the first lock has been requested (and thus
765 * before the first policy's operation has been started).
766 *
767 */
768 rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.REJECTED"
769     when
770         $manager : UsecasesEventManager(
771                         isActive(),
772                         !isAccepted(),
773                         getState() == State.AWAITING_OUTCOME,
774                         $outcome : getOutcomes().peek(),
775                         $outcome != null,
776                         !isAbort($outcome),
777                         $outcome.getEnd() != null,
778                         $outcome.isFinalOutcome(),
779                         $outcome.getResult() != OperationResult.SUCCESS,
780                         $step : getSteps().peek() )
781     then
782
783     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
784     logger.info("{}: {}.{}: {} manager={}",
785             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
786             $step, $manager);
787
788     retract($manager);
789
790     try {
791         // final failure for this policy
792         $manager.addToHistory($outcome);
793
794         $manager.setResult($outcome.getResult());
795
796         VirtualControlLoopNotification notification = $manager.makeNotification();
797         notification.setNotification(ControlLoopNotificationType.REJECTED);
798         notification.setPolicyScope(drools.getRule().getName());
799         notification.setPolicyName($manager.getPolicyName());
800         notification.setPolicyVersion($manager.getPolicyVersion());
801         notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
802                                 .collect(Collectors.toList()));
803
804         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
805
806     } catch(RuntimeException e) {
807         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
808                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
809                 $manager, e);
810         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to reject event");
811     }
812
813     $manager.destroy();
814 end
815
816 /*
817 *
818 * Process an outcome when the policy's operation fails.
819 *
820 */
821 rule "EVENT.MANAGER.PROCESS.POLICY.FAILURE"
822     when
823         $manager : UsecasesEventManager(
824                         isActive(),
825                         getState() == State.AWAITING_OUTCOME,
826                         $outcome : getOutcomes().peek(),
827                         $outcome != null,
828                         !isAbort($outcome),
829                         $outcome.getEnd() != null,
830                         !$outcome.isFinalOutcome(),
831                         $outcome.getResult() != OperationResult.SUCCESS,
832                         $step : getSteps().peek(),
833                         $step.isPolicyStep(),
834                         $outcome.isFor($step.getActorName(), $step.getOperationName()) )
835     then
836
837     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
838     logger.info("{}: {}.{}: {} manager={}",
839             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
840             $step, $manager);
841
842     try {
843         // not a final failure, thus it will be retried automatically
844
845         $manager.getOutcomes().remove();
846
847         // do NOT invoke manager.setResult()
848
849         $manager.addToHistory($outcome);
850         $manager.storeInDataBase($manager.getPartialHistory().peekLast());
851
852         VirtualControlLoopNotification notification = $manager.makeNotification();
853         notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
854         notification.setPolicyScope(drools.getRule().getName());
855         notification.setPolicyName($manager.getPolicyName());
856         notification.setPolicyVersion($manager.getPolicyVersion());
857
858         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
859
860     } catch(RuntimeException e) {
861         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
862                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
863                 $manager, e);
864         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome");
865     }
866
867     update($manager);
868 end
869
870 /*
871 *
872 * Discard an outcome that was not handled by any other rule.
873 *
874 */
875 rule "EVENT.MANAGER.DISCARD.OUTCOME"
876     salience -10
877     when
878         $manager : UsecasesEventManager(
879                         isActive(),
880                         getState() == State.AWAITING_OUTCOME,
881                         $outcome : getOutcomes().peek(),
882                         $outcome != null,
883                         $step : getSteps().peek() )
884     then
885
886     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
887     logger.info("{}: {}.{}: {} {} manager={}",
888             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
889             $step, $outcome.getResult(), $manager);
890
891     try {
892         $manager.getOutcomes().remove();
893
894         if ($outcome.getEnd() != null && $outcome.isFor($step.getActorName(), $step.getOperationName())) {
895             // it's a completion for the step
896
897             // let the step record the response that's contained within the outcome
898             if ($outcome.getResult() == OperationResult.SUCCESS) {
899                 $step.success($outcome);
900             }
901
902             // this step is complete - discard it
903             $manager.getSteps().remove();
904
905             $manager.setState(State.POLICY_LOADED);
906         }
907
908     } catch(RuntimeException e) {
909         logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
910                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
911                 $manager, e);
912         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle outcome");
913     }
914
915     update($manager);
916 end
917
918 /*
919 *
920 * Abort processing.  This can happen in any state (once the manager has been started).
921 *
922 */
923 rule "EVENT.MANAGER.ABORT"
924     when
925         $manager : UsecasesEventManager(
926                         isActive(),
927                         getState() != State.DONE,
928                         $outcome : getOutcomes().peek(),
929                         $outcome != null,
930                         isAbort($outcome),
931                         $step : getSteps().peek() )
932     then
933
934     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
935     logger.info("{}: {}.{}: {} manager={}",
936             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
937             $step, $manager);
938
939     try {
940         // determine the final message
941         String msg;
942         switch ($outcome.getActor()) {
943             case ActorConstants.CL_TIMEOUT_ACTOR:
944                 msg = "Control Loop timed out";
945                 break;
946             case ActorConstants.LOCK_ACTOR:
947                 msg = "Target Lock was lost";
948                 break;
949             default:
950                 msg = "Processing aborted by " + $outcome.getActor();
951                 break;
952         }
953
954         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE, msg);
955
956         if ($step != null && "SDNR".equals($step.getActorName())
957                 && $outcome.isFor($step.getActorName(), $step.getOperationName())) {
958
959             // aborted while processing the SDNR step - generate a notification
960             ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome);
961             $manager.deliver("DCAE_CL_RSP", clResponse, "SDNR notification", drools.getRule().getName());
962         }
963
964         if ($step != null) {
965             $outcome.setActor($step.getActorName());
966             $outcome.setOperation($step.getOperationName());
967
968             $manager.addToHistory($outcome);
969             $manager.storeInDataBase($manager.getPartialHistory().peekLast());
970         }
971
972     } catch(RuntimeException e) {
973         logger.warn("{}: {}.{}: manager={} exception handling ABORT outcome",
974                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
975                 $manager, e);
976         $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle ABORT");
977     }
978
979     update($manager);
980 end
981
982 /*
983 *
984 * Done processing.  Arriving here implies that the event has been accepted.
985 *
986 */
987 rule "EVENT.MANAGER.FINAL"
988     when
989         $manager : UsecasesEventManager(
990                         !isActive() || getState() == State.DONE )
991     then
992
993     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
994     logger.info("{}: {}.{}: manager={}",
995             $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
996             $manager);
997
998     retract($manager);
999
1000     try {
1001         VirtualControlLoopNotification notification = $manager.makeNotification();
1002         notification.setPolicyScope(drools.getRule().getName());
1003         notification.setPolicyName($manager.getPolicyName());
1004         notification.setPolicyVersion($manager.getPolicyVersion());
1005         notification.setHistory($manager.getFullHistory().stream().map(OperationOutcome2::getClOperation)
1006                                     .collect(Collectors.toList()));
1007
1008         OperationFinalResult finalResult = $manager.getFinalResult();
1009         if (finalResult == null) {
1010             finalResult = ($manager.isActive() ? OperationFinalResult.FINAL_SUCCESS : OperationFinalResult.FINAL_FAILURE);
1011         }
1012
1013         switch (finalResult) {
1014             case FINAL_FAILURE_EXCEPTION:
1015                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
1016                 notification.setMessage("Exception in processing closed loop");
1017                 break;
1018             case FINAL_SUCCESS:
1019                 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
1020                 break;
1021             case FINAL_OPENLOOP:
1022                 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
1023                 break;
1024             case FINAL_FAILURE:
1025             default:
1026                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
1027                 break;
1028         }
1029
1030         if ($manager.getFinalMessage() != null) {
1031             notification.setMessage($manager.getFinalMessage());
1032         }
1033
1034         $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
1035
1036     } catch(RuntimeException e) {
1037         logger.warn("{}: {}.{}: manager={} exception generating final notification",
1038                 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
1039                 $manager, e);
1040     }
1041
1042     $manager.destroy();
1043 end
1044
1045 /*
1046 *
1047 * This rule will clean up any rogue events where there is no
1048 * ControlLoopParams object corresponding to the onset event.
1049 *
1050 */
1051 rule "EVENT.CLEANUP"
1052     salience -100
1053     when
1054         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1055     then
1056
1057     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1058     logger.info("{}: {}", $clName, drools.getRule().getName());
1059     logger.debug("{}: {}: orphan event={}",
1060                 $clName, drools.getRule().getName(), $event);
1061     //
1062     // Retract the event
1063     //
1064     retract($event);
1065 end
1066
1067 /*
1068 *
1069 * At this point, it appears that if we prevent the rules from getting messages from
1070 * topics, then that will also prevent the actors from getting them.  So the following
1071 * rules are here just to discard those messages.
1072 *
1073 * These have a higher salience so the objects are removed before the "FINAL" message
1074 * is processed, so that the junit test can assume things are done once they see the
1075 * "FINAL" message.  Otherwise, tests might fail sporadically.
1076 *
1077 */
1078 rule "APPC.Response.CLEANUP"
1079     salience 1
1080     when
1081         $msg : org.onap.policy.appc.Response( )
1082     then
1083         retract($msg);
1084 end
1085
1086 rule "APPC.Request.CLEANUP"
1087     salience 1
1088     when
1089         $msg : org.onap.policy.appc.Request( )
1090     then
1091         retract($msg);
1092 end
1093
1094 rule "APPC-LCM.Response.CLEANUP"
1095     salience 1
1096     when
1097         $msg : org.onap.policy.appclcm.AppcLcmDmaapWrapper( )
1098     then
1099         retract($msg);
1100 end
1101
1102 rule "SDNR.Response.CLEANUP"
1103     salience 1
1104     when
1105         $msg : org.onap.policy.sdnr.PciResponseWrapper( )
1106     then
1107         retract($msg);
1108 end