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