88bf6141fb9d80e280a68cfd4b00a6974a8d3720
[policy/drools-applications.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019 Bell Canada.
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 org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
25
26 import org.onap.policy.controlloop.VirtualControlLoopEvent;
27 import org.onap.policy.controlloop.VirtualControlLoopNotification;
28 import org.onap.policy.controlloop.ControlLoopEventStatus;
29 import org.onap.policy.controlloop.ControlLoopException;
30 import org.onap.policy.controlloop.ControlLoopNotificationType;
31 import org.onap.policy.controlloop.policy.PolicyResult;
32 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
33 import org.onap.policy.controlloop.policy.Policy;
34 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
35 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NewEventStatus;
36 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
37 import org.onap.policy.controlloop.eventmanager.LockCallbackWorkingMemory;
38 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
39 import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider;
40 import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider.CdsActorServiceManager;
41 import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants;
42 import org.onap.policy.aai.AaiCqResponse;
43 import org.onap.policy.appc.Request;
44 import org.onap.policy.appc.Response;
45 import org.onap.policy.appc.CommonHeader;
46 import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
47 import org.onap.policy.cds.CdsResponse;
48 import org.onap.policy.cds.client.CdsProcessorGrpcClient;
49 import org.onap.policy.cds.properties.CdsServerProperties;
50 import org.onap.policy.drools.utils.Pair;
51 import org.onap.policy.sdnr.PciRequestWrapper;
52 import org.onap.policy.sdnr.PciResponseWrapper;
53 import org.onap.policy.sdnr.PciRequest;
54 import org.onap.policy.sdnr.PciResponse;
55 import org.onap.policy.vfc.VfcRequest;
56 import org.onap.policy.vfc.VfcResponse;
57 import org.onap.policy.vfc.VfcManager;
58 import org.onap.policy.so.SoManager;
59 import org.onap.policy.so.SoRequest;
60 import org.onap.policy.so.SoResponseWrapper;
61 import org.onap.policy.sdnc.SdncRequest;
62 import org.onap.policy.sdnc.SdncManager;
63 import org.onap.policy.sdnc.SdncResponse;
64 import org.onap.policy.drools.core.lock.Lock;
65 import org.onap.policy.guard.PolicyGuardRequest;
66 import org.onap.policy.guard.PolicyGuardResponse;
67 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
68 import org.onap.policy.guard.PolicyGuardXacmlHelper;
69
70 import org.yaml.snakeyaml.Yaml;
71 import org.yaml.snakeyaml.constructor.Constructor;
72
73 import org.slf4j.LoggerFactory;
74 import org.slf4j.Logger;
75
76 import java.time.Instant;
77 import java.util.LinkedList;
78 import java.util.Iterator;
79
80 import org.onap.policy.drools.system.PolicyEngineConstants;
81
82 /*
83  * This structure mimics the Params structure.
84  * Its only purpose is to allow management of
85  * rules by the PAP component..
86  * It has no use at runtime since the rules go by
87  * Params for matching purposes.
88  */
89 declare PapParams
90   closedLoopControlName : String
91   controlLoopYaml : String
92 end
93
94 /*
95  * Control Loop Identity
96  */
97 declare Params
98   closedLoopControlName : String
99   controlLoopYaml : String
100 end
101
102 /*
103  * Used to trigger clean up Params that no longer have associated rules.
104  */
105 declare ParamsInitCleaner
106   closedLoopControlName : String    // only used when logging
107 end
108
109 /*
110  * Used to clean up Params that no longer have associated rules.
111  */
112 declare ParamsCleaner
113   closedLoopControlName : String
114   controlLoopYaml : String
115 end
116
117 /*
118  * This object is to provide support for timeouts
119  * due to a bug in drools' built-in timers
120  */
121 declare ControlLoopTimer
122     closedLoopControlName : String
123     requestId : String
124     delay : String
125     expired : boolean
126     //timerType is the type of timer: either "ClosedLoop" or "Operation"
127     timerType : String
128 end
129
130 /*
131 *
132 * Called to insert the parameters into working memory for this Closed Loop policy.  This is called
133 * once each time a closed loop is added or its YAML is updated.
134 * This has a higher salience so we can ensure that the Params is created before we have a chance to
135 * discard any events.
136 *
137 */
138 rule "${policyName}.SETUP"
139     salience 1
140     when
141         not( Params( getClosedLoopControlName() == "${closedLoopControlName}",
142             getControlLoopYaml() == "${controlLoopYaml}" ) )
143     then
144
145     Params params = new Params();
146     params.setClosedLoopControlName("${closedLoopControlName}");
147     params.setControlLoopYaml("${controlLoopYaml}");
148     insert(params);
149
150     ParamsInitCleaner initCleaner = new ParamsInitCleaner();
151     initCleaner.setClosedLoopControlName("${closedLoopControlName}");
152     insert(initCleaner);
153
154     // Note: globals have bad behavior when persistence is used,
155     //       hence explicitly getting the logger vs using a global
156
157     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
158     logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(),
159         params.getControlLoopYaml());
160 end
161
162 /*
163 *
164 * This rule responds to DCAE Events where there is no manager yet. Either it is
165 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
166 *
167 */
168 rule "${policyName}.EVENT"
169     when
170         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
171         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
172         not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
173             requestId == $event.getRequestId() ) )
174     then
175
176     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
177     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
178
179     try {
180
181         //
182         // Check the event, because we need it to not be null when
183         // we create the ControlLoopEventManager. The ControlLoopEventManager
184         // will do extra syntax checking as well check if the closed loop is disabled.
185         //
186         if ($event.getRequestId() == null) {
187             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
188             notification.setNotification(ControlLoopNotificationType.REJECTED);
189             notification.setFrom("policy");
190             notification.setMessage("Missing requestId");
191             notification.setPolicyName(drools.getRule().getName());
192             notification.setPolicyScope("${policyScope}");
193             notification.setPolicyVersion("${policyVersion}");
194
195             //
196             // Let interested parties know
197             //
198             PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
199
200             //
201             // Retract it from memory
202             //
203             retract($event);
204         } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
205             throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
206         } else {
207             //
208             // Create an EventManager
209             //
210             ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(),
211                 $event.getRequestId());
212             //
213             // Determine if EventManager can actively process the event
214             // (i.e. syntax, is_closed_loop_disabled checks etc.)
215             //
216             VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
217             notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
218             notification.setPolicyName(drools.getRule().getName());
219             notification.setPolicyScope("${policyScope}");
220             notification.setPolicyVersion("${policyVersion}");
221             //
222             // Are we actively pursuing this event?
223             //
224             if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
225                 //
226                 // Insert Event Manager into memory, this will now kick off processing.
227                 //
228                 insert(manager);
229                 //
230                 // Let interested parties know
231                 //
232                 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
233                 //
234                 // Setup the Overall Control Loop timer
235                 //
236                 ControlLoopTimer clTimer = new ControlLoopTimer();
237                 clTimer.setTimerType("ClosedLoop");
238                 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
239                 clTimer.setRequestId($event.getRequestId().toString());
240                 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
241                 //
242                 // Insert it
243                 //
244                 insert(clTimer);
245             } else {
246                 //
247                 // Let interested parties know
248                 //
249                 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
250                 //
251                 // Retract it from memory
252                 //
253                 retract($event);
254             }
255
256             //
257             // Now that the manager is inserted into Drools working memory, we'll wait for
258             // another rule to fire in order to continue processing. This way we can also
259             // then screen for additional ONSET and ABATED events for this RequestId.
260             //
261         }
262     } catch (Exception e) {
263         logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
264
265         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
266         notification.setNotification(ControlLoopNotificationType.REJECTED);
267         notification.setMessage("Exception occurred: " + e.getMessage());
268         notification.setPolicyName(drools.getRule().getName());
269         notification.setPolicyScope("${policyScope}");
270         notification.setPolicyVersion("${policyVersion}");
271         //
272         //
273         //
274         PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
275         //
276         // Retract the event
277         //
278         retract($event);
279     }
280 end
281
282 /*
283 *
284 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
285 * is now created. We can start processing the yaml specification via the Event Manager.
286 *
287 */
288 rule "${policyName}.EVENT.MANAGER"
289     when
290         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
291         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
292         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
293             requestId == $event.getRequestId() )
294         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
295             requestId == $event.getRequestId().toString(), timerType == "ClosedLoop", !expired )
296     then
297
298     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
299     logger.info("{}: {}: event={} manager={} clTimer={}",
300                 $params.getClosedLoopControlName(), drools.getRule().getName(),
301                 $event, $manager, $clTimer);
302
303     try {
304         //
305         // Check which event this is.
306         //
307         ControlLoopEventManager.NewEventStatus eventStatus = $manager.onNewEvent($event);
308         //
309         // Check what kind of event this is
310         //
311         if (eventStatus == NewEventStatus.SUBSEQUENT_ONSET) {
312             //
313             // We don't care about subsequent onsets
314             //
315             logger.info("{}: {}: subsequent onset",
316                         $params.getClosedLoopControlName(), drools.getRule().getName());
317             retract($event);
318             return;
319         }
320         if (eventStatus == NewEventStatus.SYNTAX_ERROR) {
321             //
322             // Ignore any bad syntax events
323             //
324             logger.warn("{}: {}: syntax error",
325                         $params.getClosedLoopControlName(), drools.getRule().getName());
326             retract($event);
327             return;
328         }
329         //
330         // We only want the initial ONSET event in memory,
331         // all the other events need to be retracted to support
332         // cleanup and avoid the other rules being fired for this event.
333         //
334         if (eventStatus != NewEventStatus.FIRST_ONSET) {
335             logger.warn("{}: {}: not first onset",
336                         $params.getClosedLoopControlName(), drools.getRule().getName());
337             retract($event);
338         }
339
340         logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(),
341                      drools.getRule().getName(), $event.getTarget());
342         //
343         // Now start seeing if we need to process this event
344         //
345
346         //
347         // Check if this is a Final Event
348         //
349         VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
350
351
352         if (notification != null) {
353             //
354             // Its final, but are we waiting for abatement?
355             //
356             if ($manager.getNumAbatements() > 0) {
357                 logger.info("{}: {}: abatement received for {}.  Closing the control loop",
358                             $params.getClosedLoopControlName(), drools.getRule().getName(),
359                             $event.getRequestId());
360
361                 /// DB Write---end event processing for this RequestId()
362                 $manager.commitAbatement("Event Abated","Closed");
363
364                 notification.setFrom("policy");
365                 notification.setPolicyName(drools.getRule().getName());
366                 notification.setPolicyScope("${policyScope}");
367                 notification.setPolicyVersion("${policyVersion}");
368                 //
369                 // In this case, we are done
370                 //
371                 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
372                 //
373                 // Unlock the target
374                 //
375                 Lock lock = $manager.unlockCurrentOperation();
376                 if(lock != null) {
377                     logger.debug("{}: {}: retracting lock={}", $params.getClosedLoopControlName(),
378                                 drools.getRule().getName(), lock);
379                     retract(lock);
380                 }
381                 //
382                 // Retract everything from memory
383                 //
384                 logger.info("{}: {}: retracting onset, manager, and timer",
385                             $params.getClosedLoopControlName(), drools.getRule().getName());
386
387                 retract($manager.getOnsetEvent());
388
389                 // don't retract manager, etc. - a clean-up rule will do that
390
391                 //
392                 // TODO - what if we get subsequent Events for this RequestId?
393                 // By default, it will all start over again. May be confusing for Ruby.
394                 // Or, we could track this and then subsequently ignore the events
395                 //
396             } else {
397                 //
398                 // Check whether we need to wait for abatement
399                 //
400                 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
401                   logger.info("{}: {}: waiting for abatement ..",
402                               $params.getClosedLoopControlName(), drools.getRule().getName());
403                 } else {
404                   logger.info("{}: {}: no abatement expect for {}.  Closing the control loop",
405                               $params.getClosedLoopControlName(), drools.getRule().getName(),
406                               $event.getRequestId());
407
408                   notification.setFrom("policy");
409                   notification.setPolicyName(drools.getRule().getName());
410                   notification.setPolicyScope("${policyScope}");
411                   notification.setPolicyVersion("${policyVersion}");
412
413                   //
414                   // In this case, we are done
415                   //
416                   PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
417                   //
418                   // Unlock the target
419                   //
420                   Lock lock = $manager.unlockCurrentOperation();
421                   if(lock != null) {
422                       logger.debug("{}: {}: retracting lock={}", $params.getClosedLoopControlName(),
423                                   drools.getRule().getName(), lock);
424                       retract(lock);
425                   }
426                   //
427                   // Retract everything from memory
428                   //
429                   logger.info("{}: {}: retracting onset, manager, and timer",
430                               $params.getClosedLoopControlName(), drools.getRule().getName());
431
432                   retract($manager.getOnsetEvent());
433
434                 // don't retract manager, etc. - a clean-up rule will do that
435                 }
436             }
437         } else {
438             //
439             // NOT final, so let's ask for the next operation
440             //
441             ControlLoopOperationManager operation = $manager.processControlLoop();
442             if (operation != null) {
443               //
444               // Let's ask for a lock right away
445               //
446               logger.info("{}: {}: requesting lock for operation={}",
447                             $params.getClosedLoopControlName(), drools.getRule().getName(),
448                             operation);
449
450               Pair<Lock,Lock> oldNew = $manager.lockCurrentOperation(
451                         new LockCallbackWorkingMemory($params.getClosedLoopControlName(), drools.getWorkingMemory()));
452               if(oldNew.first() != null) {
453                   logger.debug("{}: {}: retracting lock={}", $params.getClosedLoopControlName(),
454                               drools.getRule().getName(), oldNew.first());
455                   retract(oldNew.first());
456               }
457               if(oldNew.second() != null) {
458                   logger.debug("{}: {}: inserting lock={}", $params.getClosedLoopControlName(),
459                               drools.getRule().getName(), oldNew.second());
460                   insert(oldNew.second());
461               }
462
463               //
464               // insert the operation into memory
465               //
466               insert(operation);
467               //
468               // insert operation timeout object
469               //
470               ControlLoopTimer opTimer = new ControlLoopTimer();
471               opTimer.setTimerType("Operation");
472               opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
473               opTimer.setRequestId($event.getRequestId().toString());
474               Integer timeout = operation.getOperationTimeout();
475               opTimer.setDelay(timeout > 0 ? timeout.toString() + "s" : $clTimer.getDelay());
476               insert(opTimer);
477
478             } else {
479                 //
480                 // Probably waiting for abatement
481                 //
482               logger.info("{}: {}: no operation, probably waiting for abatement",
483                           $params.getClosedLoopControlName(), drools.getRule().getName());
484             }
485         }
486     } catch (Exception e) {
487          logger.warn("{}: {}: unexpected",
488                   $params.getClosedLoopControlName(),
489                   drools.getRule().getName(), e);
490
491          VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
492          notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
493          notification.setMessage(e.getMessage());
494          notification.setFrom("policy");
495          notification.setPolicyName(drools.getRule().getName());
496          notification.setPolicyScope("${policyScope}");
497          notification.setPolicyVersion("${policyVersion}");
498
499          PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
500
501          retract($event);
502
503          // don't retract manager, etc. - a clean-up rule will do that
504     }
505
506 end
507
508 /*
509 *
510 * Lock denied
511 *
512 */
513 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCK.DENIED"
514     when
515         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
516         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
517         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
518             requestId == $event.getRequestId() )
519         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
520             onset.getRequestId() == $event.getRequestId(), "None".equalsIgnoreCase(getGuardApprovalStatus()) )
521         $lock : Lock (ownerKey == $event.getRequestId().toString(), isUnavailable())
522     then
523
524     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
525     logger.info("{}: {}: event={} manager={} operation={} lock={}",
526                 $params.getClosedLoopControlName(), drools.getRule().getName(),
527                 $event, $manager, $operation, $lock);
528
529     logger.debug("The target resource {} is already processing",
530                         $event.getAai().get($event.getTarget()));
531     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
532     notification.setNotification(ControlLoopNotificationType.REJECTED);
533     notification.setMessage("The target " + $event.getAai().get($event.getTarget())
534                         + " is already locked");
535     notification.setFrom("policy");
536     notification.setPolicyName(drools.getRule().getName());
537     notification.setPolicyScope("${policyScope}");
538     notification.setPolicyVersion("${policyVersion}");
539
540     PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
541
542     retract($event);
543
544     // don't retract manager, etc. - a clean-up rule will do that
545 end
546
547 /*
548 *
549 * Guard Permitted, let's send request to the actor.
550 *
551 */
552 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
553     when
554         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
555         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
556         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
557             requestId == $event.getRequestId() )
558         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
559             onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
560         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
561             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
562     then
563
564     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
565     logger.info("{}: {}: event={} manager={} operation={}",
566                 $params.getClosedLoopControlName(), drools.getRule().getName(),
567                 $event, $manager, $operation);
568
569     Object request = null;
570     boolean caughtException = false;
571
572     try {
573         request = $operation.startOperation($event);
574
575         if (request != null) {
576           logger.debug("{}: {}: starting operation ..",
577                        $params.getClosedLoopControlName(), drools.getRule().getName());
578           //
579           // Tell interested parties we are performing this Operation
580           //
581           VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
582           notification.setNotification(ControlLoopNotificationType.OPERATION);
583           notification.setMessage($operation.getOperationMessage());
584           notification.setHistory($operation.getHistory());
585           notification.setFrom("policy");
586           notification.setPolicyName(drools.getRule().getName());
587           notification.setPolicyScope("${policyScope}");
588           notification.setPolicyVersion("${policyVersion}");
589
590           PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
591
592           switch ($operation.policy.getActor()){
593
594               case "APPC":
595                   if (request instanceof Request) {
596                       PolicyEngineConstants.getManager().deliver("APPC-CL", request);
597                   }
598                   else if (request instanceof AppcLcmDmaapWrapper) {
599                       PolicyEngineConstants.getManager().deliver("APPC-LCM-READ", request);
600                   }
601                   break;
602               case "SO":
603                   // at this point the AAI named query request should have already been made,
604                   // the response recieved and used
605                   // in the construction of the SO Request which is stored in operationRequest
606
607                   if(request instanceof SoRequest) {
608                       // Call SO. The response will be inserted into memory once it's received
609                       class mySoCallback implements SoManager.SoCallback {
610                           public void onSoResponseWrapper(SoResponseWrapper wrapper) {
611                               drools.getWorkingMemory().insert(wrapper);
612                           }
613                       }
614                       SoActorServiceProvider.sendRequest($event.getRequestId().toString(),
615                           new mySoCallback(),
616                           request,
617                           PolicyEngineConstants.getManager().getEnvironmentProperty("so.url"),
618                           PolicyEngineConstants.getManager().getEnvironmentProperty("so.username"),
619                           PolicyEngineConstants.getManager().getEnvironmentProperty("so.password"));
620                   }
621                   break;
622               case "VFC":
623                   if (request instanceof VfcRequest) {
624                       // Start VFC thread
625                       class myVfcCallback implements VfcManager.VfcCallback {
626
627                           public void onResponse(VfcResponse responseError) {
628                               drools.getWorkingMemory().insert(responseError);
629                           }
630                       };
631                       // Start VFC thread
632                       Thread t = new Thread(new VfcManager(new myVfcCallback(),
633                           (VfcRequest)request,
634                           PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.url"),
635                           PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.username"),
636                           PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.password")));
637                       t.start();
638                   }
639                   break;
640
641               case "SDNC":
642                   if (request instanceof SdncRequest) {
643                      // Start SDNC thread
644                       class mySdncCallback implements SdncManager.SdncCallback {
645                           public void onCallback(SdncResponse response) {
646                               drools.getWorkingMemory().insert(response);
647                           }
648                       }
649                       // Start SDNC thread
650                       Thread t = new Thread(new SdncManager(new mySdncCallback(),
651                           (SdncRequest)request,
652                           PolicyEngineConstants.getManager().getEnvironmentProperty("sdnc.url"),
653                           PolicyEngineConstants.getManager().getEnvironmentProperty("sdnc.username"),
654                           PolicyEngineConstants.getManager().getEnvironmentProperty("sdnc.password")));
655                       t.start();
656                   }
657                   break;
658               case "SDNR":
659                   if (request instanceof PciRequestWrapper) {
660                       PolicyEngineConstants.getManager().deliver("SDNR-CL", request);
661                   }
662                   break;
663
664              case "CDS":
665
666                   if(request instanceof ExecutionServiceInput) {
667
668                       // Instantiate cds actor, service manager and grpc properties
669
670                       CdsActorServiceProvider cdsActor = new CdsActorServiceProvider();
671                       CdsActorServiceProvider.CdsActorServiceManager cdsActorServiceManager = cdsActor.new CdsActorServiceManager();
672
673                       CdsServerProperties props = new CdsServerProperties();
674                       props.setHost(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcHost"));
675                       props.setPort(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPort")));
676                       props.setUsername(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcUsername"));
677                       props.setPassword(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPassword"));
678                       props.setTimeout(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcTimeout")));
679
680                       // Send cds grpc request
681                       try (CdsProcessorGrpcClient client = new CdsProcessorGrpcClient(cdsActorServiceManager, props)) {
682                           CdsResponse response =
683                                 cdsActorServiceManager.sendRequestToCds(client, props, (ExecutionServiceInput) request);
684                           logger.info("CDS response: {}", response);
685                           insert(response);
686                       }
687
688                   }
689                   break;
690
691           }
692         } else {
693           //
694           // What happens if its null?
695           //
696             logger.warn("{}: {}: unexpected null operation request",
697                       $params.getClosedLoopControlName(),
698                       drools.getRule().getName());
699             if ("SO".equals($operation.policy.getActor())) {
700                 retract($opTimer);
701                 retract($operation);
702                 modify($manager) {finishOperation($operation)};
703             }
704             else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
705                 retract($opTimer);
706                 retract($operation);
707                 modify($manager) {finishOperation($operation)};
708             }
709             else if ("sdnc".equalsIgnoreCase($operation.policy.getActor())) {
710                 retract($opTimer);
711                 retract($operation);
712                 modify($manager) {finishOperation($operation)};
713             }
714         }
715
716     } catch (Exception e) {
717         String msg = e.getMessage();
718         logger.warn("{}: {}: operation={}:  AAI failure: {}",
719                     $params.getClosedLoopControlName(), drools.getRule().getName(),
720                     $operation, msg, e);
721         $operation.setOperationHasException(msg);
722
723         if(request != null) {
724             //
725             // Create a notification for it ("DB Write - end operation")
726             //
727             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
728             notification.setFrom("policy");
729             notification.setPolicyName(drools.getRule().getName());
730             notification.setPolicyScope("${policyScope}");
731             notification.setPolicyVersion("${policyVersion}");
732             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
733             notification.setMessage($operation.getOperationHistory());
734             notification.setHistory($operation.getHistory());
735
736             PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
737         }
738
739         retract($opTimer);
740         retract($operation);
741         caughtException = true;
742     }
743
744     // Having the modify statement in the catch clause doesn't work for whatever reason
745     if (caughtException) {
746         modify($manager) {finishOperation($operation)};
747     }
748 end
749
750
751 /*
752 *
753 * We were able to acquire a lock so now let's ask Xacml Guard whether
754 * we are allowed to proceed with the request to the actor.
755 *
756 */
757 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
758     when
759         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
760         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
761         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
762             requestId == $event.getRequestId() )
763         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
764             onset.getRequestId() == $event.getRequestId(), "None".equalsIgnoreCase(getGuardApprovalStatus()) )
765         $lock : Lock (ownerKey == $event.getRequestId().toString(), isActive())
766     then
767
768     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
769     logger.info("{}: {}: event={} manager={} operation={} lock={}",
770                 $params.getClosedLoopControlName(), drools.getRule().getName(),
771                 $event, $manager, $operation, $lock);
772
773     //
774     // Sending notification that we are about to query Guard ("DB write - start operation")
775     //
776     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
777     notification.setNotification(ControlLoopNotificationType.OPERATION);
778     notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " "
779         + $operation.policy.getRecipe());
780     notification.setHistory($operation.getHistory());
781     notification.setFrom("policy");
782     notification.setPolicyName(drools.getRule().getName());
783     notification.setPolicyScope("${policyScope}");
784     notification.setPolicyVersion("${policyVersion}");
785
786     PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
787
788     //
789     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
790     // just change guardEnabled to false.
791     //
792     // In order to use REST XACML, provide a URL instead of "" as a second argument
793     // to the CallGuardTask() and set the first argument to null
794     // (instead of XacmlPdpEngine).
795     //
796
797     // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
798     boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngineConstants.getManager().getEnvironmentProperty("guard.disabled"));
799
800     if(guardEnabled){
801
802         Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
803                                                         drools.getWorkingMemory(),
804                                                         $event.getClosedLoopControlName(),
805                                                         $operation.policy.getActor().toString(),
806                                                         $operation.policy.getRecipe(),
807                                                         $operation.getTargetEntity(),
808                                                         $event.getRequestId().toString(),
809                                                         () -> {
810                                                              try {
811                                                                  AaiCqResponse resp_cq  = $manager.getCqResponse($event);
812                                                                  if (resp_cq == null){
813                                                                      return null;
814                                                                  } else {
815                                                                      String custId = $operation.policy.getTarget().getModelCustomizationId();
816                                                                      String invId = $operation.policy.getTarget().getModelInvariantId();
817                                                                      String verId = $operation.policy.getTarget().getModelVersionId();
818                                                                      return resp_cq.getVfModuleCount(custId, invId, verId);
819                                                                  }
820                                                              } catch (Exception e){
821                                                                  logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
822                                                              }
823                                                              return null;
824                                                         }));
825         t.start();
826     }
827     else{
828         insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
829     }
830
831 end
832
833 //
834 // This rule will be triggered when a thread talking to the XACML Guard inserts a
835 // guardResponse object into the working memory
836 //
837 rule "${policyName}.GUARD.RESPONSE"
838     when
839         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
840         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
841             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
842         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
843             requestId == $event.getRequestId() )
844         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
845             onset.getRequestId() == $event.getRequestId() )
846         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
847             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
848         $guardResponse : PolicyGuardResponse(requestId == $event.getRequestId(), $operation.policy.recipe == operation)
849     then
850
851     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
852     logger.info("{}: {}: event={} manager={} operation={} opTimer={} guardResponse={}",
853                  $params.getClosedLoopControlName(), drools.getRule().getName(),
854                  $event, $manager, $operation, $opTimer, $guardResponse);
855
856
857     //we will permit the operation if there was no Guard for it
858     if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
859         $guardResponse.setResult("Permit");
860     }
861
862     //
863     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
864     //
865     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
866     notification.setNotification(ControlLoopNotificationType.OPERATION);
867     notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe()
868         + " is " + $guardResponse.getResult());
869     notification.setHistory($operation.getHistory());
870     notification.setFrom("policy");
871     notification.setPolicyName(drools.getRule().getName());
872     notification.setPolicyScope("${policyScope}");
873     notification.setPolicyVersion("${policyVersion}");
874
875     PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
876
877     if("Permit".equalsIgnoreCase($guardResponse.getResult())){
878
879         modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
880     }
881     else {
882         //This is the Deny case
883         $operation.startOperation($event);
884         $operation.setOperationHasGuardDeny();
885         retract($opTimer);
886         retract($operation);
887         modify($manager) {finishOperation($operation)};
888     }
889
890     retract($guardResponse);
891
892 end
893
894 /*
895 *
896 * This rule responds to APPC Response Events
897 *
898 * I would have like to be consistent and write the Response like this:
899 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
900 *
901 * However, no compile error was given. But a runtime error was given. I think
902 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
903 *
904 */
905 rule "${policyName}.APPC.RESPONSE"
906     when
907         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
908         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
909             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
910         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
911             requestId == $event.getRequestId() )
912         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
913             onset.getRequestId() == $event.getRequestId() )
914         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
915             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
916         $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
917     then
918
919     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
920     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
921     logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
922                  $params.getClosedLoopControlName(), drools.getRule().getName(),
923                  $event, $manager, $operation, $opTimer, $response);
924     //
925     // Get the result of the operation
926     //
927     PolicyResult policyResult = $operation.onResponse($response);
928     if (policyResult != null) {
929         logger.debug("{}: {}: operation finished - result={}",
930                     $params.getClosedLoopControlName(), drools.getRule().getName(),
931                     policyResult);
932         //
933         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
934         //
935         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
936         notification.setFrom("policy");
937         notification.setPolicyName(drools.getRule().getName());
938         notification.setPolicyScope("${policyScope}");
939         notification.setPolicyVersion("${policyVersion}");
940         notification.setMessage($operation.getOperationHistory());
941         notification.setHistory($operation.getHistory());
942         if (policyResult.equals(PolicyResult.SUCCESS)) {
943             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
944             //
945             // Let interested parties know
946             //
947             PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
948         } else {
949             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
950             //
951             // Let interested parties know
952             //
953             PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
954         }
955         //
956         // Ensure the operation is complete
957         //
958         if ($operation.isOperationComplete() == true) {
959             //
960             // It is complete, remove it from memory
961             //
962             retract($operation);
963             //
964             // We must also retract the timer object
965             // NOTE: We could write a Rule to do this
966             //
967             retract($opTimer);
968             //
969             // Complete the operation
970             //
971             modify($manager) {finishOperation($operation)};
972         } else {
973             //
974             // Just doing this will kick off the LOCKED rule again
975             //
976             modify($operation) {};
977         }
978     } else {
979         //
980         // Its not finished yet (i.e. expecting more Response objects)
981         //
982         // Or possibly it is a leftover response that we timed the request out previously
983         //
984     }
985     //
986     // We are going to retract these objects from memory
987     //
988     retract($response);
989 end
990
991 /*
992 *
993 * The problem with Responses is that they don't have a controlLoopControlName
994 * field in them, so the only way to attach them is via RequestId. If we have multiple
995 * control loop .drl's loaded in the same container, we need to be sure the cleanup
996 * rules don't remove Responses for other control loops.
997 *
998 */
999 rule "${policyName}.APPC.RESPONSE.CLEANUP"
1000     when
1001         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1002         $response : Response($id : getCommonHeader().RequestId )
1003         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1004     then
1005
1006     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1007     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1008     logger.debug("{}: {}: orphan appc response={}",
1009                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1010
1011     //
1012     // Retract it
1013     //
1014     retract($response);
1015 end
1016
1017 /*
1018 *
1019 * This rule responds to APPC Response Events using the new LCM interface provided by appc
1020 *
1021 */
1022 rule "${policyName}.APPC.LCM.RESPONSE"
1023     when
1024         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1025         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1026             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1027         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1028             requestId == $event.getRequestId() )
1029         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1030             onset.getRequestId() == $event.getRequestId() )
1031         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1032             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1033         $response : AppcLcmDmaapWrapper( getBody().getOutput().getCommonHeader().getRequestId() == $event.getRequestId() )
1034     then
1035
1036     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1037     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1038     logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
1039                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1040                 $event, $manager, $operation, $operation, $opTimer, $response);
1041
1042     //
1043     // Get the result of the operation
1044     //
1045     PolicyResult policyResult = $operation.onResponse($response);
1046     if (policyResult != null) {
1047       logger.debug("{}: {}: operation finished - result={}",
1048                   $params.getClosedLoopControlName(), drools.getRule().getName(),
1049                   policyResult);
1050
1051       //
1052       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1053       //
1054       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1055       notification.setFrom("policy");
1056       notification.setPolicyName(drools.getRule().getName());
1057       notification.setPolicyScope("${policyScope}");
1058       notification.setPolicyVersion("${policyVersion}");
1059       notification.setMessage($operation.getOperationHistory());
1060       notification.setHistory($operation.getHistory());
1061       if (policyResult.equals(PolicyResult.SUCCESS)) {
1062           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1063       } else {
1064           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1065       }
1066       PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1067       //
1068       // Ensure the operation is complete
1069       //
1070       if ($operation.isOperationComplete() == true) {
1071           //
1072           // It is complete, remove it from memory
1073           //
1074           retract($operation);
1075           //
1076           // We must also retract the timer object
1077           // NOTE: We could write a Rule to do this
1078           //
1079           retract($opTimer);
1080           //
1081           // Complete the operation
1082           //
1083           modify($manager) {finishOperation($operation)};
1084       } else {
1085           //
1086           // Just doing this will kick off the LOCKED rule again
1087           //
1088           modify($operation) {};
1089       }
1090     } else {
1091         //
1092         // Its not finished yet (i.e. expecting more Response objects)
1093         //
1094         // Or possibly it is a leftover response that we timed the request out previously
1095         //
1096     }
1097     //
1098     // We are going to retract these objects from memory
1099     //
1100     retract($response);
1101 end
1102
1103 /*
1104 *
1105 * Clean Up any lingering LCM reponses
1106 *
1107 */
1108 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
1109     when
1110         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1111         $response : AppcLcmDmaapWrapper($id : getBody().getOutput().getCommonHeader().getRequestId() )
1112         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
1113     then
1114
1115     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1116     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1117     logger.debug("{}: {}: orphan appc response={}",
1118                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1119     //
1120     // Retract it
1121     //
1122     retract($response);
1123 end
1124
1125 /*
1126 *
1127 * This rule responds to SDNR Response Events using the new interface provided by SDNR
1128 *
1129 */
1130 rule "${policyName}.SDNR.RESPONSE"
1131     when
1132         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1133         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1134             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1135         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1136             requestId == $event.getRequestId() )
1137         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1138             onset.getRequestId() == $event.getRequestId() )
1139         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1140             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1141         $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1142     then
1143
1144     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1145     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1146     logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
1147                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1148                 $event, $manager, $operation, $operation, $opTimer, $response);
1149
1150     //
1151     // Get the result of the operation
1152     //
1153     PolicyResult policyResult = $operation.onResponse($response);
1154     if (policyResult != null) {
1155       logger.debug("{}: {}: operation finished - result={}",
1156                   $params.getClosedLoopControlName(), drools.getRule().getName(),
1157                   policyResult);
1158
1159       //
1160       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1161       //
1162       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1163       notification.setFrom("policy");
1164       notification.setPolicyName(drools.getRule().getName());
1165       notification.setPolicyScope("${policyScope}");
1166       notification.setPolicyVersion("${policyVersion}");
1167       notification.setMessage($operation.getOperationHistory());
1168       notification.setHistory($operation.getHistory());
1169       if (policyResult.equals(PolicyResult.SUCCESS)) {
1170           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1171       } else {
1172           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1173       }
1174       PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1175       //
1176       // Ensure the operation is complete
1177       //
1178       if ($operation.isOperationComplete()) {
1179           //
1180           // It is complete, remove it from memory
1181           //
1182           retract($operation);
1183           //
1184           // We must also retract the timer object
1185           // NOTE: We could write a Rule to do this
1186           //
1187           retract($opTimer);
1188           //
1189           // Complete the operation
1190           //
1191           modify($manager) {finishOperation($operation)};
1192       } else {
1193           //
1194           // Just doing this will kick off the LOCKED rule again
1195           //
1196           modify($operation) {};
1197       }
1198     } else {
1199         //
1200         // Its not finished yet (i.e. expecting more Response objects)
1201         //
1202         // Or possibly it is a leftover response that we timed the request out previously
1203         //
1204     }
1205     //
1206     // We are going to retract these objects from memory
1207     //
1208     retract($response);
1209 end
1210
1211 /*
1212 *
1213 * Clean Up any lingering SDNR reponses
1214 *
1215 */
1216 rule "${policyName}.SDNR.RESPONSE.CLEANUP"
1217     when
1218         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1219         $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1220         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1221     then
1222
1223     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1224     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1225     logger.debug("{}: {}: orphan SDNR response={}",
1226                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1227     //
1228     // Retract it
1229     //
1230     retract($response);
1231 end
1232
1233 /*
1234 *
1235 * This rule responds to SO Response Events
1236 *
1237 */
1238 rule "${policyName}.SO.RESPONSE"
1239     when
1240         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1241         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1242             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1243         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1244             requestId == $event.getRequestId() )
1245         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1246             onset.getRequestId() == $event.getRequestId() )
1247         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1248             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1249         $response : SoResponseWrapper(requestId.toString() == $event.getRequestId().toString() )
1250     then
1251
1252     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1253     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1254     logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
1255                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1256                 $event, $manager, $operation, $operation, $opTimer, $response);
1257
1258     // Get the result of the operation
1259     //
1260     PolicyResult policyResult = $operation.onResponse($response);
1261     if (policyResult != null) {
1262         logger.debug("{}: {}: operation finished - result={}",
1263                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1264                     policyResult);
1265
1266         //
1267         // This Operation has completed, construct a notification showing our results
1268         //
1269         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1270         notification.setFrom("policy");
1271         notification.setPolicyName(drools.getRule().getName());
1272         notification.setPolicyScope("${policyScope}");
1273         notification.setPolicyVersion("${policyVersion}");
1274         notification.setMessage($operation.getOperationHistory());
1275         notification.setHistory($operation.getHistory());
1276         if (policyResult.equals(PolicyResult.SUCCESS)) {
1277             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1278         } else {
1279             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1280
1281         }
1282         PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1283         //
1284         // Ensure the operation is complete
1285         //
1286         if ($operation.isOperationComplete() == true) {
1287             //
1288             // It is complete, remove it from memory
1289             //
1290             retract($operation);
1291             //
1292             // We must also retract the timer object
1293             // NOTE: We could write a Rule to do this
1294             //
1295             retract($opTimer);
1296             //
1297             // Complete the operation
1298             //
1299             modify($manager) {finishOperation($operation)};
1300         } else {
1301             //
1302             // Just doing this will kick off the LOCKED rule again
1303             //
1304             modify($operation) {};
1305         }
1306     } else {
1307         //
1308         // Its not finished yet (i.e. expecting more Response objects)
1309         //
1310         // Or possibly it is a leftover response that we timed the request out previously
1311         //
1312     }
1313     //
1314     // We are going to retract these objects from memory
1315     //
1316     retract($response);
1317
1318 end
1319
1320 /*
1321 *
1322 * This rule responds to VFC Response Events
1323 *
1324 */
1325 rule "${policyName}.VFC.RESPONSE"
1326     when
1327         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1328         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1329             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1330         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1331             requestId == $event.getRequestId() )
1332         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1333             onset.getRequestId() == $event.getRequestId() )
1334         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1335             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1336         $response : VfcResponse( requestId.toString() == $event.getRequestId().toString() )
1337     then
1338         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1339         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1340         logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
1341                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1342                     $event, $manager, $operation, $operation, $opTimer, $response);
1343
1344         // Get the result of the operation
1345         //
1346         PolicyResult policyResult = $operation.onResponse($response);
1347         if (policyResult != null) {
1348             //
1349             // This Operation has completed, construct a notification showing our results
1350             //
1351             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1352             notification.setFrom("policy");
1353             notification.setPolicyName(drools.getRule().getName());
1354             notification.setPolicyScope("${policyScope}");
1355             notification.setPolicyVersion("${policyVersion}");
1356             notification.setMessage($operation.getOperationHistory());
1357             notification.setHistory($operation.getHistory());
1358             //
1359             // Ensure the operation is complete
1360             //
1361             if ($operation.isOperationComplete() == true) {
1362                 //
1363                 // It is complete, remove it from memory
1364                 //
1365                 retract($operation);
1366                 //
1367                 // We must also retract the timer object
1368                 // NOTE: We could write a Rule to do this
1369                 //
1370                 retract($opTimer);
1371                 //
1372                 // Complete the operation
1373                 //
1374                 modify($manager) {finishOperation($operation)};
1375             } else {
1376                 //
1377                 // Just doing this will kick off the LOCKED rule again
1378                 //
1379                 modify($operation) {};
1380             }
1381         } else {
1382             //
1383             // Its not finished yet (i.e. expecting more Response objects)
1384             //
1385             // Or possibly it is a leftover response that we timed the request out previously
1386             //
1387         }
1388         //
1389         // We are going to retract these objects from memory
1390         //
1391         retract($response);
1392
1393 end
1394
1395 /*
1396 *
1397 * This rule responds to SDNC Response Events
1398 *
1399 */
1400
1401 rule "${policyName}.SDNC.RESPONSE"
1402     when
1403         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1404         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1405             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1406         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1407             requestId == $event.getRequestId() )
1408         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1409             onset.getRequestId() == $event.getRequestId() )
1410         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1411             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1412         $response : SdncResponse( requestId.toString() == $event.getRequestId().toString() )
1413     then
1414         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1415         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1416         logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
1417                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1418                     $event, $manager, $operation, $operation, $opTimer, $response);
1419
1420         // Get the result of the operation
1421         //
1422         PolicyResult policyResult = $operation.onResponse($response);
1423         if (policyResult != null) {
1424             //
1425             // This Operation has completed, construct a notification showing our results
1426             //
1427             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1428             notification.setFrom("policy");
1429             notification.setPolicyName(drools.getRule().getName());
1430             notification.setPolicyScope("${policyScope}");
1431             notification.setPolicyVersion("${policyVersion}");
1432             notification.setMessage($operation.getOperationHistory());
1433             notification.setHistory($operation.getHistory());
1434             //
1435             // Ensure the operation is complete
1436             //
1437             if ($operation.isOperationComplete()) {
1438                 //
1439                 // It is complete, remove it from memory
1440                 //
1441                 retract($operation);
1442                 //
1443                 // We must also retract the timer object
1444                 // NOTE: We could write a Rule to do this
1445                 //
1446                 retract($opTimer);
1447                 //
1448                 // Complete the operation
1449                 //
1450                 modify($manager) {finishOperation($operation)};
1451             } else {
1452                 //
1453                 // Just doing this will kick off the LOCKED rule again
1454                 //
1455                 modify($operation) {};
1456             }
1457         } else {
1458             //
1459             // Its not finished yet (i.e. expecting more Response objects)
1460             //
1461             // Or possibly it is a leftover response that we timed the request out previously
1462             //
1463         }
1464         //
1465         // We are going to retract these objects from memory
1466         //
1467         retract($response);
1468
1469 end
1470
1471
1472 /**
1473  * This rule responds to CDS Response Events
1474  */
1475 rule "${policyName}.CDS.RESPONSE"
1476     when
1477         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1478         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1479             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1480         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1481             requestId == $event.getRequestId() )
1482         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1483             onset.getRequestId() == $event.getRequestId() )
1484         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1485             requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1486         $response : CdsResponse( requestId == $event.getRequestId().toString() )
1487
1488     then
1489
1490         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1491         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1492         logger.debug("{}: {}: event={} manager={} operation={} opTimer={} response={}",
1493                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1494                     $event, $manager, $operation, $operation, $opTimer, $response);
1495
1496         // Get the result of the operation
1497         PolicyResult policyResult = $operation.onResponse($response);
1498
1499         if (policyResult != null) {
1500             logger.debug("{}: {}: operation finished - result={}",
1501                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1502                     policyResult);
1503
1504             // The operation has completed, construct a notification showing our results
1505             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1506             notification.setFrom("policy");
1507             notification.setPolicyName(drools.getRule().getName());
1508             notification.setPolicyScope("${policyScope}");
1509             notification.setPolicyVersion("${policyVersion}");
1510             notification.setMessage($operation.getOperationHistory());
1511             notification.setHistory($operation.getHistory());
1512             notification.setNotification(
1513                 ($response != null && CdsActorConstants.SUCCESS.equals($response.getStatus()))
1514                     ? ControlLoopNotificationType.OPERATION_SUCCESS : ControlLoopNotificationType.OPERATION_FAILURE);
1515
1516             // Send the notification
1517             PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1518
1519             // Ensure the operation is complete
1520             if ($operation.isOperationComplete()) {
1521
1522                 // It is complete, remove it from memory
1523                 retract($operation);
1524
1525                 // We must also retract the timer object
1526                 // NOTE: We could write a Rule to do this
1527                 retract($opTimer);
1528
1529                 // Complete the operation
1530                 modify($manager) {finishOperation($operation)};
1531
1532             } else {
1533                 // Just doing this will kick off the LOCKED rule again
1534                 modify($operation) {};
1535             }
1536         } else {
1537             // Its not finished yet (i.e. expecting more Response objects)
1538             // Or possibly it is a leftover response that we timed the request out previously
1539             logger.info(
1540                 "policyResult is null"
1541                     + "\nIt's not finished yet (i.e. expecting more Response objects)"
1542                     + "\nOr possibly it is a leftover response that we timed the request out previously");
1543         }
1544
1545         // We are going to retract these objects from memory
1546         retract($response);
1547
1548 end
1549
1550 /*
1551 *
1552 * This manages a single timer.
1553 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1554 *
1555 */
1556 rule "${policyName}.TIMER.FIRED"
1557     timer (expr: $timeout)
1558     when
1559         $timer : ControlLoopTimer($timeout : delay, !expired)
1560     then
1561         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1562         logger.info("This is ${policyName}.TIMER.FIRED");
1563         modify($timer){setExpired(true)};
1564     end
1565
1566 /*
1567 *
1568 * This is the timer that manages the timeout for an individual operation.
1569 *
1570 */
1571 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1572     when
1573         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1574         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1575         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1576             requestId == $event.getRequestId() )
1577         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1578             onset.getRequestId() == $event.getRequestId() )
1579         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1580             requestId == $event.getRequestId().toString(), expired, timerType == "Operation" )
1581     then
1582
1583     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1584     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1585     logger.debug("{}: {}: event={} manager={} operation={} opTimer={}",
1586                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1587                 $event, $manager, $operation, $operation, $opTimer);
1588
1589     //
1590     // Tell it it has timed out
1591     //
1592     $operation.setOperationHasTimedOut();
1593     //
1594     // Create a notification for it ("DB Write - end operation")
1595     //
1596     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1597     notification.setFrom("policy");
1598     notification.setPolicyName(drools.getRule().getName());
1599     notification.setPolicyScope("${policyScope}");
1600     notification.setPolicyVersion("${policyVersion}");
1601     notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1602     notification.setMessage($operation.getOperationHistory());
1603     notification.setHistory($operation.getHistory());
1604     //
1605     // Let interested parties know
1606     //
1607     PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1608     //
1609     // Get rid of the timer
1610     //
1611     retract($opTimer);
1612     //
1613     // Ensure the operation is complete
1614     //
1615     if ($operation.isOperationComplete() == true) {
1616         //
1617         // It is complete, remove it from memory
1618         //
1619         retract($operation);
1620         //
1621         // Complete the operation
1622         //
1623         modify($manager) {finishOperation($operation)};
1624     } else {
1625         //
1626         // Just doing this will kick off the LOCKED rule again
1627         //
1628         modify($operation) {};
1629     }
1630 end
1631
1632 /*
1633 *
1634 * This is the timer that manages the overall control loop timeout.
1635 *
1636 */
1637 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1638     when
1639         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1640         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1641         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1642             requestId == $event.getRequestId() )
1643         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1644             requestId == $event.getRequestId().toString(), expired, timerType == "ClosedLoop" )
1645     then
1646
1647     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1648     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1649
1650     logger.debug("{}: {}: event={}",
1651               $params.getClosedLoopControlName(), drools.getRule().getName(),
1652               $event);
1653     //
1654     // Tell the Event Manager it has timed out
1655     //
1656     VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1657     if (notification != null) {
1658         notification.setFrom("policy");
1659         notification.setPolicyName(drools.getRule().getName());
1660         notification.setPolicyScope("${policyScope}");
1661         notification.setPolicyVersion("${policyVersion}");
1662         //
1663         // Let interested parties know
1664         //
1665         PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1666     }
1667     //
1668     // Retract the event
1669     //
1670     retract($event);
1671 end
1672
1673 /*
1674 *
1675 * This rule cleans up the manager and other objects after an event has
1676 * been retracted.
1677 *
1678 */
1679 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1680     when
1681         $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestId() )
1682         $operations : LinkedList()
1683                         from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName,
1684                             onset.getRequestId() == $requestId ) )
1685         $timers : LinkedList()
1686                         from collect( ControlLoopTimer( closedLoopControlName == $clName,
1687                             requestId == $requestId.toString() ) )
1688         not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1689     then
1690
1691     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1692     logger.info("{}: {}", $clName, drools.getRule().getName());
1693
1694     logger.debug("{}: {}: manager={} timers={} operations={}",
1695               $clName, drools.getRule().getName(),
1696               $manager, $timers.size(), $operations.size());
1697
1698     //
1699     // Retract lock by invoking unlock()
1700     //
1701     Lock lock = $manager.unlockCurrentOperation();
1702     if(lock != null) {
1703         retract(lock);
1704     }
1705
1706     //
1707     // Retract EVERYTHING
1708     //
1709
1710     retract($manager);
1711
1712     for(Object manager: $operations) {
1713         retract((ControlLoopOperationManager) manager);
1714     }
1715     for(Object timer: $timers) {
1716         retract((ControlLoopTimer) timer);
1717     }
1718 end
1719
1720 /*
1721 *
1722 * This rule will clean up any rogue onsets where there is no
1723 * ControlLoopParams object corresponding to the onset event.
1724 *
1725 */
1726 rule "${policyName}.EVENT.CLEANUP"
1727     when
1728         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1729         not ( Params( getClosedLoopControlName() == $clName) )
1730     then
1731
1732     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1733     logger.info("{}: {}", $clName, drools.getRule().getName());
1734     logger.debug("{}: {}: orphan onset event={}",
1735                 $clName, drools.getRule().getName(), $event);
1736
1737     retract($event);
1738 end
1739
1740 /*
1741 * Creates a cleaner for every Params object.
1742 * This has a higher salience so that it is fired before PARAMS.FINISHED in ANY policy.
1743 */
1744 rule "${policyName}.PARAMS.CLEANING"
1745     salience 2
1746     when
1747         $params: Params( )
1748         ParamsInitCleaner( )
1749     then
1750
1751     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1752     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1753         $params.getControlLoopYaml());
1754
1755     ParamsCleaner cleaner = new ParamsCleaner();
1756     cleaner.setClosedLoopControlName($params.getClosedLoopControlName());
1757     cleaner.setControlLoopYaml($params.getControlLoopYaml());
1758     insert(cleaner);
1759 end
1760
1761 /*
1762 * Finished creating cleaner objects, so remove the trigger.
1763 * This has a higher salience so that it is fired before processing any events.
1764 */
1765 rule "${policyName}.PARAMS.FINISHED"
1766     salience 1
1767     when
1768         $initCleaner: ParamsInitCleaner( )
1769     then
1770
1771     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1772     logger.info("{}: {}", $initCleaner.getClosedLoopControlName(), drools.getRule().getName());
1773
1774     retract($initCleaner);
1775 end
1776
1777 /*
1778 * Identifies Params objects that are still active, removing their associated cleaners.
1779 * This should only leave one active Params object for each policy.
1780 * This has a higher salience so that it is fired before PARAMS.DELETE in ANY policy.
1781 */
1782 rule "${policyName}.PARAMS.ACTIVE"
1783     salience 3
1784     when
1785         $params: Params( getClosedLoopControlName() == "${closedLoopControlName}",
1786                             getControlLoopYaml() == "${controlLoopYaml}" )
1787         $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}",
1788                             getControlLoopYaml() == "${controlLoopYaml}"  )
1789     then
1790
1791     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1792     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1793         $params.getControlLoopYaml());
1794
1795     retract($cleaner);
1796 end
1797
1798 /*
1799 * Delete Params objects that are not active (i.e., those that still have an associated
1800 * cleaner object).
1801 * This has a higher salience so that it is fired before PARAMS.CLEANED in ANY policy.
1802 */
1803 rule "${policyName}.PARAMS.DELETE"
1804     salience 2
1805     when
1806         $params: Params( )
1807         $cleaner: ParamsCleaner( getClosedLoopControlName() == $params.getClosedLoopControlName(),
1808                             getControlLoopYaml() == $params.getControlLoopYaml()  )
1809     then
1810
1811     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1812     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1813         $params.getControlLoopYaml());
1814
1815     retract($params);
1816 end
1817
1818 /*
1819 * Finished clean-up, so delete the cleaner objects.
1820 * This has a higher salience so that it is fired before processing any events.
1821 */
1822 rule "${policyName}.PARAMS.CLEANED"
1823     salience 1
1824     when
1825         $cleaner: ParamsCleaner( )
1826     then
1827
1828     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1829     logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(),
1830         $cleaner.getControlLoopYaml());
1831
1832     retract($cleaner);
1833 end