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