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