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