Fix checkstyle declarations
[policy/drools-applications.git] / controlloop / templates / template.demo.clc / src / main / resources / __closedLoopControlName__.drl
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.controlloop;
22
23 import org.onap.policy.controlloop.VirtualControlLoopEvent;
24 import org.onap.policy.controlloop.VirtualControlLoopNotification;
25 import org.onap.policy.controlloop.ControlLoopEventStatus;
26 import org.onap.policy.controlloop.ControlLoopException;
27 import org.onap.policy.controlloop.ControlLoopNotificationType;
28 import org.onap.policy.controlloop.ControlLoopLogger;
29 import org.onap.policy.controlloop.policy.PolicyResult;
30 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
31 import org.onap.policy.controlloop.policy.Policy;
32 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
33 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NEW_EVENT_STATUS;
34 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
35 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
36 import org.onap.policy.aai.AaiNqResponseWrapper;
37 import org.onap.policy.appc.Request;
38 import org.onap.policy.appc.Response;
39 import org.onap.policy.appc.CommonHeader;
40 import org.onap.policy.appclcm.LcmRequestWrapper;
41 import org.onap.policy.appclcm.LcmResponseWrapper;
42 import org.onap.policy.appclcm.LcmRequest;
43 import org.onap.policy.appclcm.LcmResponse;
44 import org.onap.policy.appclcm.LcmCommonHeader;
45 import org.onap.policy.vfc.VFCRequest;
46 import org.onap.policy.vfc.VFCResponse;
47 import org.onap.policy.vfc.VFCManager;
48 import org.onap.policy.so.SOManager;
49 import org.onap.policy.so.SORequest;
50 import org.onap.policy.so.SORequestStatus;
51 import org.onap.policy.so.SORequestDetails;
52 import org.onap.policy.so.SOModelInfo;
53 import org.onap.policy.so.SOCloudConfiguration;
54 import org.onap.policy.so.SORequestInfo;
55 import org.onap.policy.so.SORequestParameters;
56 import org.onap.policy.so.SORelatedInstanceListElement;
57 import org.onap.policy.so.SORelatedInstance;
58 import org.onap.policy.so.SOResponse;
59 import org.onap.policy.so.SOResponseWrapper;
60 import org.onap.policy.guard.PolicyGuard;
61 import org.onap.policy.guard.PolicyGuard.LockResult;
62 import org.onap.policy.guard.TargetLock;
63 import org.onap.policy.guard.GuardResult;
64 import org.onap.policy.guard.PolicyGuardRequest;
65 import org.onap.policy.guard.PolicyGuardResponse;
66 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
67 import org.onap.policy.guard.CallGuardTaskEmbedded;
68
69 import org.yaml.snakeyaml.Yaml;
70 import org.yaml.snakeyaml.constructor.Constructor;
71
72 import org.slf4j.LoggerFactory;
73 import org.slf4j.Logger;
74
75 import java.time.Instant;
76 import java.util.LinkedList;
77 import java.util.Iterator;
78
79 import org.onap.policy.drools.system.PolicyEngine;
80
81 /*
82  * This structure mimics the Params structure.
83  * Its only purpose is to allow management of
84  * rules by the PAP component..
85  * It has no use at runtime since the rules go by
86  * Params for matching purposes.
87  */
88 declare PapParams
89   closedLoopControlName : String
90   controlLoopYaml : String
91 end
92
93 /*
94  * Control Loop Identity
95  */
96 declare Params
97   closedLoopControlName : String
98   controlLoopYaml : String
99 end
100
101 /*
102  * Used to clean up Params that no longer have associated rules.
103  */
104 declare ParamsCleaner
105   closedLoopControlName : String
106   controlLoopYaml : String
107 end
108
109
110 /*
111  * Operation Timer
112  */
113 declare OperationTimer
114   closedLoopControlName : String
115   requestID : String
116   delay : String
117 end
118
119 /*
120  * Control Loop Timer
121  */
122 declare ControlLoopTimer
123   closedLoopControlName : String
124   requestID : String
125   delay : String
126 end
127
128 /*
129 *
130 * Called once and only once to insert the parameters into working memory for this Closed Loop policy.
131 * This has a higher salience so we can ensure that the Params is created before we have a chance to
132 * discard any events.
133 *
134 */
135 rule "${policyName}.SETUP"
136     salience 1
137     when
138         not( Params( getClosedLoopControlName() == "${closedLoopControlName}", getControlLoopYaml() == "${controlLoopYaml}" ) )
139     then
140     
141     Params params = new Params();
142     params.setClosedLoopControlName("${closedLoopControlName}");
143     params.setControlLoopYaml("${controlLoopYaml}");
144     insert(params);
145
146     // Note: globals have bad behavior when persistence is used,
147     //       hence explicitly getting the logger vs using a global
148     
149     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
150     logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), params.getControlLoopYaml());
151 end
152
153 /*
154 *
155 * This rule responds to DCAE Events where there is no manager yet. Either it is
156 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
157 *
158 */
159 rule "${policyName}.EVENT"
160     when
161         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
162         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
163         not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() ) )
164     then
165  
166     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
167     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
168     
169     try {
170       
171         //
172         // Check the event, because we need it to not be null when
173         // we create the ControlLoopEventManager. The ControlLoopEventManager
174         // will do extra syntax checking as well check if the closed loop is disabled.
175         //
176         if ($event.getRequestId() == null) {
177             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
178             notification.setNotification(ControlLoopNotificationType.REJECTED);
179             notification.setFrom("policy");
180             notification.setMessage("Missing requestId");
181             notification.setPolicyName(drools.getRule().getName());
182             notification.setPolicyScope("${policyScope}");
183             notification.setPolicyVersion("${policyVersion}");
184             
185             //
186             // Let interested parties know
187             //
188             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
189             
190             //
191             // Retract it from memory
192             //
193             retract($event);
194         } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
195             throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
196         } else {
197             //
198             // Create an EventManager
199             //
200             ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(), $event.getRequestId());
201             //
202             // Disable target locking
203             //
204             manager.setUseTargetLock(false);
205             //
206             // Determine if EventManager can actively process the event (i.e. syntax, is_closed_loop_disabled checks etc.)
207             //
208             VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
209             notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
210             notification.setPolicyName(drools.getRule().getName());
211             notification.setPolicyScope("${policyScope}");
212             notification.setPolicyVersion("${policyVersion}");
213             //
214             // Are we actively pursuing this event?
215             //
216             if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
217                 //
218                 // Insert Event Manager into memory, this will now kick off processing.
219                 //
220                 insert(manager);
221                 //
222                 // Let interested parties know
223                 //
224                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
225                 //
226                 // Setup the Overall Control Loop timer
227                 //
228                 ControlLoopTimer clTimer = new ControlLoopTimer();
229                 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
230                 clTimer.setRequestID($event.getRequestId().toString());
231                 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
232                 //
233                 // Insert it
234                 //
235                 insert(clTimer);
236             } else {
237                 //
238                 // Let interested parties know
239                 //
240                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
241                 //
242                 // Retract it from memory
243                 //
244                 retract($event);
245             }
246             
247             //
248             // Now that the manager is inserted into Drools working memory, we'll wait for
249             // another rule to fire in order to continue processing. This way we can also
250             // then screen for additional ONSET and ABATED events for this RequestId.
251             //
252         }
253     } catch (Exception e) {
254         logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
255         
256         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
257         notification.setNotification(ControlLoopNotificationType.REJECTED);
258         notification.setMessage("Exception occurred: " + e.getMessage());
259         notification.setPolicyName(drools.getRule().getName());
260         notification.setPolicyScope("${policyScope}");
261         notification.setPolicyVersion("${policyVersion}");
262         //
263         //
264         //
265         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
266         //
267         // Retract the event
268         //
269         retract($event);
270     }
271 end
272
273 /*
274 *
275 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
276 * is now created. We can start processing the yaml specification via the Event Manager.
277 *
278 */
279 rule "${policyName}.EVENT.MANAGER"
280     when
281         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
282         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
283         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
284         $clTimer : ControlLoopTimer ( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
285     then
286
287     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
288     logger.info("{}: {}: event={} manager={} clTimer={}", 
289                 $params.getClosedLoopControlName(), drools.getRule().getName(),
290                 $event, $manager, $clTimer);
291     
292     try {
293         //
294         // Check which event this is.
295         //
296         ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
297         //
298         // Check what kind of event this is
299         //
300         if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
301             //
302             // We don't care about subsequent onsets
303             //
304             logger.info("{}: {}: subsequent onset", 
305                         $params.getClosedLoopControlName(), drools.getRule().getName());
306             retract($event);
307             return;
308         }
309         if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
310             //
311             // Ignore any bad syntax events
312             //
313             logger.warn("{}: {}: syntax error", 
314                         $params.getClosedLoopControlName(), drools.getRule().getName());
315             retract($event);
316             return;
317         }
318         //
319         // We only want the initial ONSET event in memory,
320         // all the other events need to be retracted to support
321         // cleanup and avoid the other rules being fired for this event.
322         //
323         if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
324             logger.warn("{}: {}: not first onset", 
325                         $params.getClosedLoopControlName(), drools.getRule().getName());
326             retract($event);
327         }
328         
329         logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(), 
330                      drools.getRule().getName(), $event.getTarget());
331         //
332         // Now start seeing if we need to process this event
333         //
334
335         //
336         // Check if this is a Final Event
337         //
338         VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
339     
340         if (notification != null) {
341             //
342             // Set common notification fields
343             //
344             notification.setFrom("policy");
345             notification.setPolicyName(drools.getRule().getName());
346             notification.setPolicyScope("${policyScope}");
347             notification.setPolicyVersion("${policyVersion}");
348             //
349             // Its final, but are we waiting for abatement?
350             //
351             if ($manager.getNumAbatements() > 0) {
352                 //
353                 // We have received an abatement and are done
354                 //
355                 logger.info("{}: {}: abatement received for {}.  Closing the control loop", 
356                             $params.getClosedLoopControlName(), drools.getRule().getName(), 
357                             $event.getRequestId());
358                 //
359                 // Set notification message
360                 //
361                 notification.setMessage("Abatement received. Closing the control loop.");
362                 //
363                 /// DB Write---end event processing for this RequestId()
364                 //
365                 $manager.commitAbatement("Event Abated","Closed");
366                 //
367                 // Unlock the target
368                 //
369                 TargetLock lock = $manager.unlockCurrentOperation();
370                 if (lock != null) {
371                     logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(), 
372                                  drools.getRule().getName(), lock);
373                     retract(lock);
374                 }
375                 //
376                 // Retract everything from memory
377                 //
378                 logger.info("{}: {}: retracting onset, manager, and timer", 
379                             $params.getClosedLoopControlName(), drools.getRule().getName());
380                 
381                 retract($manager.getOnsetEvent());
382                 retract($manager);
383                 retract($clTimer);
384                 //
385                 // TODO - what if we get subsequent Events for this RequestId?
386                 // By default, it will all start over again. May be confusing for Ruby.
387                 // Or, we could track this and then subsequently ignore the events
388                 //
389             } else {
390                 //
391                 // Check whether we need to wait for abatement
392                 //
393                 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
394                   //
395                   // We will wait
396                   //
397                   logger.info("{}: {}: waiting for abatement ..", 
398                               $params.getClosedLoopControlName(), drools.getRule().getName());
399                   //
400                   // Set notification message
401                   //
402                   notification.setMessage("Waiting for abatement");
403                 } else {
404                   //
405                   // We are done
406                   //
407                   logger.info("{}: {}: no abatement expected for {}.  Closing the control loop", 
408                               $params.getClosedLoopControlName(), drools.getRule().getName(), 
409                               $event.getRequestId());
410                   //
411                   // Set notification message
412                   //
413                   notification.setMessage("No abatement expected. Closing the control loop.");
414                   //
415                   // Unlock the target
416                   //
417                   TargetLock lock = $manager.unlockCurrentOperation();
418                   if (lock != null) {
419                       logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(), 
420                                   drools.getRule().getName(), lock);
421                       retract(lock);
422                   }
423                   //
424                   // Retract everything from memory
425                   //
426                   logger.info("{}: {}: retracting onset, manager, and timer", 
427                               $params.getClosedLoopControlName(), drools.getRule().getName());
428                   
429                   retract($manager.getOnsetEvent());
430                   retract($manager);
431                   retract($clTimer);
432                 }
433             }
434             //
435             // Send the notification
436             //
437             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
438         } else {
439             //
440             // NOT final, so let's ask for the next operation
441             //
442             ControlLoopOperationManager operation = $manager.processControlLoop();
443             if (operation != null) {
444               //
445               // Let's ask for a lock right away
446               //
447               LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
448               logger.info("{}: {}: guard lock acquired={}", 
449                             $params.getClosedLoopControlName(), drools.getRule().getName(), 
450                             result.getB());
451               if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
452                 //
453                 // insert the operation into memory
454                 //
455                 insert(operation);
456                 
457                 //
458                 // insert operation timeout object
459                 //
460                 OperationTimer opTimer = new OperationTimer();
461                 opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
462                 opTimer.setRequestID($event.getRequestId().toString());
463                 opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
464                 insert(opTimer);
465               
466                 //
467                 // Insert lock into memory
468                 //
469                 insert(result.getB());
470               }
471               else {
472                 logger.debug("The target resource {} is already processing",
473                               $event.getAai().get($event.getTarget()));
474                 notification = new VirtualControlLoopNotification($event);
475                 notification.setNotification(ControlLoopNotificationType.REJECTED);
476                 notification.setMessage("The target " + $event.getAai().get($event.getTarget()) + " is already locked");
477                 notification.setFrom("policy");
478                 notification.setPolicyName(drools.getRule().getName());
479                 notification.setPolicyScope("${policyScope}");
480                 notification.setPolicyVersion("${policyVersion}");
481       
482                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);              
483                 
484                 retract($event);
485                 retract($manager);
486                 retract($clTimer);
487                 
488                 if(result.getB() != null) {
489                      retract(result.getB());
490                 }
491               }
492               logger.info("{}: {}: starting operation={}", 
493                           $params.getClosedLoopControlName(), drools.getRule().getName(), 
494                           operation);
495             } else {
496                 //
497                 // Probably waiting for abatement
498                 //
499               logger.info("{}: {}: no operation, probably waiting for abatement", 
500                           $params.getClosedLoopControlName(), drools.getRule().getName());
501             }
502         }
503     } catch (Exception e) {
504         logger.warn("{}: {}: unexpected", 
505                   $params.getClosedLoopControlName(), 
506                   drools.getRule().getName(), e);
507
508         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
509         notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
510         notification.setMessage(e.getMessage());
511         notification.setFrom("policy");
512         notification.setPolicyName(drools.getRule().getName());
513         notification.setPolicyScope("${policyScope}");
514         notification.setPolicyVersion("${policyVersion}");
515   
516         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);              
517             
518         retract($event);
519         retract($manager);
520         retract($clTimer);
521     }
522         
523 end
524
525 /*
526 *
527 * Guard Permitted, let's send request to the actor.
528 *
529 */
530 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
531     when
532         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
533         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
534         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
535         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
536         $lock : TargetLock (requestID == $event.getRequestId())
537         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
538     then
539
540     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
541     logger.info("{}: {}: event={} manager={} operation={} lock={}", 
542                 $params.getClosedLoopControlName(), drools.getRule().getName(),
543                 $event, $manager, $operation, $lock);    
544
545     Object request = null;
546     boolean caughtException = false;
547     
548     try {
549         request = $operation.startOperation($event);
550         
551         if (request != null) {
552           logger.debug("{}: {}: starting operation ..", 
553                        $params.getClosedLoopControlName(), drools.getRule().getName());
554           //
555           // Tell interested parties we are performing this Operation
556           //
557           VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
558           notification.setNotification(ControlLoopNotificationType.OPERATION);
559           notification.setMessage($operation.getOperationMessage());
560           notification.setHistory($operation.getHistory());
561           notification.setFrom("policy");
562           notification.setPolicyName(drools.getRule().getName());
563           notification.setPolicyScope("${policyScope}");
564           notification.setPolicyVersion("${policyVersion}");
565           
566           PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
567           
568           switch ($operation.policy.getActor()){
569               
570               case "APPC":
571           
572                   if (request instanceof Request) {
573                       PolicyEngine.manager.deliver("APPC-CL", request);
574                   }
575                   else if (request instanceof LcmRequestWrapper) {
576                       PolicyEngine.manager.deliver("APPC-LCM-READ", request);
577                   }
578                   break;
579               case "SO":
580                   // at this point the AAI named query request should have already been made, the response received
581                   // and used in the construction of the SO Request which is stored in operationRequest
582                   
583                   if(request instanceof SORequest) {
584                       // Call SO. The response will be inserted into memory once it's received 
585                       SoActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(), 
586                           request);                        
587                   }
588                   break;
589               case "VFC":
590                   if (request instanceof VFCRequest) {
591                       // Start VFC thread
592                       Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
593                       t.start();
594                   }          
595                   break;
596           }
597         } else {
598           //
599           // What happens if its null?
600           //
601             logger.warn("{}: {}: unexpected null operation request", 
602                       $params.getClosedLoopControlName(), 
603                       drools.getRule().getName());
604             if ("SO".equals($operation.policy.getActor())) {
605                 retract($opTimer);
606                 retract($operation);
607                 modify($manager) {finishOperation($operation)};
608             }
609             else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
610                 retract($opTimer);
611                 retract($operation);
612                 modify($manager) {finishOperation($operation)};
613             }
614         }
615         
616     } catch (Exception e) {
617         String msg = e.getMessage();
618         logger.warn("{}: {}: operation={}:  AAI failure: {}", 
619                     $params.getClosedLoopControlName(), drools.getRule().getName(),
620                     $operation, msg, e);
621         $operation.setOperationHasException(msg);
622         
623         if(request != null) {
624             //
625             // Create a notification for it ("DB Write - end operation")
626             //
627             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
628             notification.setFrom("policy");
629             notification.setPolicyName(drools.getRule().getName());
630             notification.setPolicyScope("${policyScope}");
631             notification.setPolicyVersion("${policyVersion}");
632             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
633             notification.setMessage($operation.getOperationHistory());
634             notification.setHistory($operation.getHistory());
635           
636             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
637         }
638     
639         retract($opTimer);
640         retract($operation);
641         caughtException = true;
642     }
643     
644     // Having the modify statement in the catch clause doesn't work for whatever reason
645     if (caughtException) {
646         modify($manager) {finishOperation($operation)};
647     }
648 end
649
650
651 /*
652 *
653 * We were able to acquire a lock so now let's ask Xacml Guard whether 
654 * we are allowed to proceed with the request to the actor.
655 *
656 */
657 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
658     when
659         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
660         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
661         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
662         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
663         $lock : TargetLock (requestID == $event.getRequestId())
664     then
665
666     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
667     logger.info("{}: {}: event={} manager={} operation={} lock={}", 
668                 $params.getClosedLoopControlName(), drools.getRule().getName(),
669                 $event, $manager, $operation, $lock);
670     
671     //
672     // Sending notification that we are about to query Guard ("DB write - start operation")
673     //
674     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
675     notification.setNotification(ControlLoopNotificationType.OPERATION);
676     notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe());
677     notification.setHistory($operation.getHistory());
678     notification.setFrom("policy");
679     notification.setPolicyName(drools.getRule().getName());
680     notification.setPolicyScope("${policyScope}");
681     notification.setPolicyVersion("${policyVersion}");
682     
683     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
684         
685     //
686     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard, 
687     // just change guardEnabled to false.
688     // 
689     //
690     
691     // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
692     boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
693     
694     if(guardEnabled){
695     
696         Thread t = new Thread(new CallGuardTaskEmbedded(
697             drools.getWorkingMemory(),
698             $event.getClosedLoopControlName(),
699             $operation.policy.getActor().toString(),
700             $operation.policy.getRecipe(),
701             $operation.getTargetEntity(),
702             $event.getRequestId().toString(),
703             () -> {
704                 AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
705                 return(resp == null ? null : resp.countVfModules());
706             }));
707         t.start();
708     }
709     else{
710         insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
711     }
712
713 end
714
715 //
716 // This rule will be triggered when a thread talking to the XACML Guard inserts a 
717 // guardResponse object into the working memory
718 //
719 rule "${policyName}.GUARD.RESPONSE"
720     when
721         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
722         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
723         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() ) 
724         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
725         $lock : TargetLock (requestID == $event.getRequestId())
726         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
727         $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
728     then
729
730     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
731     logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}", 
732                  $params.getClosedLoopControlName(), drools.getRule().getName(),
733                  $event, $manager, $operation, $lock, $opTimer, $guardResponse);
734         
735         
736     //we will permit the operation if there was no Guard for it
737     if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
738         $guardResponse.setResult("Permit");
739     }
740     
741     //
742     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
743     //
744     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
745     notification.setNotification(ControlLoopNotificationType.OPERATION);
746     notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe() + " is " + $guardResponse.getResult());
747     notification.setHistory($operation.getHistory());
748     notification.setFrom("policy");
749     notification.setPolicyName(drools.getRule().getName());
750     notification.setPolicyScope("${policyScope}");
751     notification.setPolicyVersion("${policyVersion}");
752     
753     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
754     
755     if("Permit".equalsIgnoreCase($guardResponse.getResult())){
756     
757         modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
758     }
759     else {
760         //This is the Deny case
761         $operation.startOperation($event);
762         $operation.setOperationHasGuardDeny();
763         retract($opTimer);
764         retract($operation);
765         modify($manager) {finishOperation($operation)};
766     }
767     
768     retract($guardResponse);
769             
770 end
771
772 /*
773 *
774 * This rule responds to APPC Response Events
775 *
776 * I would have like to be consistent and write the Response like this:
777 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
778 *
779 * However, no compile error was given. But a runtime error was given. I think
780 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
781 *
782 */
783 rule "${policyName}.APPC.RESPONSE"
784     when
785         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
786         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
787         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
788         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
789         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
790         $lock : TargetLock (requestID == $event.getRequestId())
791         $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
792     then
793
794     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
795     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
796     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
797                  $params.getClosedLoopControlName(), drools.getRule().getName(),
798                  $event, $manager, $operation, $lock, $opTimer, $response);
799     //
800     // Get the result of the operation
801     //
802     PolicyResult policyResult = $operation.onResponse($response);
803     if (policyResult != null) {
804         logger.debug("{}: {}: operation finished - result={}", 
805                     $params.getClosedLoopControlName(), drools.getRule().getName(),
806                     policyResult);
807         //
808         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
809         //
810         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
811         notification.setFrom("policy");
812         notification.setPolicyName(drools.getRule().getName());
813         notification.setPolicyScope("${policyScope}");
814         notification.setPolicyVersion("${policyVersion}");
815         notification.setMessage($operation.getOperationHistory());
816         notification.setHistory($operation.getHistory());
817         if (policyResult.equals(PolicyResult.SUCCESS)) {
818             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
819             //
820             // Let interested parties know
821             //
822             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
823         } else {
824             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
825             //
826             // Let interested parties know
827             //
828             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
829         }
830         //
831         // Ensure the operation is complete
832         //
833         if ($operation.isOperationComplete() == true) {
834             //
835             // It is complete, remove it from memory
836             //
837             retract($operation);
838             //
839             // We must also retract the timer object
840             // NOTE: We could write a Rule to do this
841             //
842             retract($opTimer);
843             //
844             // Complete the operation
845             //
846             modify($manager) {finishOperation($operation)};
847         } else {
848             //
849             // Just doing this will kick off the LOCKED rule again
850             //
851             modify($operation) {};
852         }
853     } else {
854         //
855         // Its not finished yet (i.e. expecting more Response objects)
856         //
857         // Or possibly it is a leftover response that we timed the request out previously
858         //
859     }
860     //
861     // We are going to retract these objects from memory
862     //
863     retract($response);
864 end
865
866 /*
867 *
868 * The problem with Responses is that they don't have a controlLoopControlName
869 * field in them, so the only way to attach them is via RequestId. If we have multiple
870 * control loop .drl's loaded in the same container, we need to be sure the cleanup
871 * rules don't remove Responses for other control loops.
872 *
873 */
874 rule "${policyName}.APPC.RESPONSE.CLEANUP"
875     when
876         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
877         $response : Response($id : getCommonHeader().RequestId )
878         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
879     then
880
881     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
882     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
883     logger.debug("{}: {}: orphan appc response={}", 
884                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
885         
886     //
887     // Retract it
888     //
889     retract($response);
890 end
891
892 /*
893 *
894 * This rule responds to APPC Response Events using the new LCM interface provided by appc
895 *
896 */
897 rule "${policyName}.APPC.LCM.RESPONSE"
898     when
899         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
900         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
901         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
902         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
903         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
904         $lock : TargetLock (requestID == $event.getRequestId())
905         $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
906     then
907
908     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
909     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
910     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
911                 $params.getClosedLoopControlName(), drools.getRule().getName(),
912                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
913     
914     //
915     // Get the result of the operation
916     //
917     PolicyResult policyResult = $operation.onResponse($response);
918     if (policyResult != null) {
919       logger.debug("{}: {}: operation finished - result={}", 
920                   $params.getClosedLoopControlName(), drools.getRule().getName(),
921                   policyResult);
922       
923       //
924       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
925       //
926       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
927       notification.setFrom("policy");
928       notification.setPolicyName(drools.getRule().getName());
929       notification.setPolicyScope("${policyScope}");
930       notification.setPolicyVersion("${policyVersion}");
931       notification.setMessage($operation.getOperationHistory());
932       notification.setHistory($operation.getHistory());
933       if (policyResult.equals(PolicyResult.SUCCESS)) {
934           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
935       } else {
936           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
937       }
938       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
939       //
940       // Ensure the operation is complete
941       //
942       if ($operation.isOperationComplete() == true) {
943           //
944           // It is complete, remove it from memory
945           //
946           retract($operation);
947           //
948           // We must also retract the timer object
949           // NOTE: We could write a Rule to do this
950           //
951           retract($opTimer);
952           //
953           // Complete the operation
954           //
955           modify($manager) {finishOperation($operation)};
956       } else {
957           //
958           // Just doing this will kick off the LOCKED rule again
959           //
960           modify($operation) {};
961       }
962     } else {
963         //
964         // Its not finished yet (i.e. expecting more Response objects)
965         //
966         // Or possibly it is a leftover response that we timed the request out previously
967         //
968     }
969     //
970     // We are going to retract these objects from memory
971     //
972     retract($response);
973 end
974
975 /*
976 *
977 * Clean Up any lingering LCM reponses
978 *
979 */
980 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
981     when
982         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
983         $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
984         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
985     then
986     
987     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
988     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
989     logger.debug("{}: {}: orphan appc response={}", 
990                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
991     //
992     // Retract it
993     //
994     retract($response);
995 end
996
997 /*
998 *
999 * This rule responds to SO Response Events
1000 *
1001 */
1002 rule "${policyName}.SO.RESPONSE"
1003     when
1004         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1005         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1006         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1007         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1008         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
1009         $lock : TargetLock (requestID == $event.getRequestId())
1010         $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
1011     then
1012                 
1013     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1014     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1015     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1016                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1017                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1018         
1019     // Get the result of the operation
1020     //
1021     PolicyResult policyResult = $operation.onResponse($response);
1022     if (policyResult != null) {
1023         logger.debug("{}: {}: operation finished - result={}", 
1024                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1025                     policyResult);
1026       
1027         //
1028         // This Operation has completed, construct a notification showing our results
1029         //
1030         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1031         notification.setFrom("policy");
1032         notification.setPolicyName(drools.getRule().getName());
1033         notification.setPolicyScope("${policyScope}");
1034         notification.setPolicyVersion("${policyVersion}");
1035         notification.setMessage($operation.getOperationHistory());
1036         notification.setHistory($operation.getHistory());
1037         if (policyResult.equals(PolicyResult.SUCCESS)) {
1038             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1039         } else {
1040             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1041
1042         }
1043         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1044         //
1045         // Ensure the operation is complete
1046         //
1047         if ($operation.isOperationComplete() == true) {
1048             //
1049             // It is complete, remove it from memory
1050             //
1051             retract($operation);
1052             //
1053             // We must also retract the timer object
1054             // NOTE: We could write a Rule to do this
1055             //
1056             retract($opTimer);
1057             //
1058             // Complete the operation
1059             //
1060             modify($manager) {finishOperation($operation)};
1061         } else {
1062             //
1063             // Just doing this will kick off the LOCKED rule again
1064             //
1065             modify($operation) {};
1066         }
1067     } else {
1068         //
1069         // Its not finished yet (i.e. expecting more Response objects)
1070         //
1071         // Or possibly it is a leftover response that we timed the request out previously
1072         //
1073     }
1074     //
1075     // We are going to retract these objects from memory
1076     //
1077     retract($response);
1078
1079 end
1080
1081 /*
1082 *
1083 * This rule responds to VFC Response Events
1084 *
1085 */
1086 rule "${policyName}.VFC.RESPONSE"
1087     when
1088         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1089         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1090         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1091         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1092         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
1093         $lock : TargetLock (requestID == $event.getRequestId())
1094         $response : VFCResponse( requestId.toString() == $event.getRequestId().toString() ) 
1095     then
1096         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1097         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1098         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1099                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1100                     $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1101         
1102         // Get the result of the operation
1103         //
1104         PolicyResult policyResult = $operation.onResponse($response);
1105         if (policyResult != null) {
1106             //
1107             // This Operation has completed, construct a notification showing our results
1108             //
1109             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1110             notification.setFrom("policy");
1111             notification.setPolicyName(drools.getRule().getName());
1112             notification.setPolicyScope("${policyScope}");
1113             notification.setPolicyVersion("${policyVersion}");
1114             notification.setMessage($operation.getOperationHistory());
1115             notification.setHistory($operation.getHistory());
1116             //
1117             // Ensure the operation is complete
1118             //
1119             if ($operation.isOperationComplete() == true) {
1120                 //
1121                 // It is complete, remove it from memory
1122                 //
1123                 retract($operation);
1124                 //
1125                 // We must also retract the timer object
1126                 // NOTE: We could write a Rule to do this
1127                 //
1128                 retract($opTimer);
1129                 //
1130                 // Complete the operation
1131                 //
1132                 modify($manager) {finishOperation($operation)};
1133             } else {
1134                 //
1135                 // Just doing this will kick off the LOCKED rule again
1136                 //
1137                 modify($operation) {};
1138             }
1139         } else {
1140             //
1141             // Its not finished yet (i.e. expecting more Response objects)
1142             //
1143             // Or possibly it is a leftover response that we timed the request out previously
1144             //
1145         }
1146         //
1147         // We are going to retract these objects from memory
1148         //
1149         retract($response);
1150
1151 end
1152
1153 /*
1154 *
1155 * This is the timer that manages the timeout for an individual operation.
1156 *
1157 */
1158 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1159     timer (expr: $to )
1160     when
1161         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1162         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1163         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1164         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1165         $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), $to : getDelay() )
1166         $lock : TargetLock (requestID == $event.getRequestId())
1167     then
1168     
1169     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1170     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1171     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}", 
1172                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1173                 $event, $manager, $operation, $lock, $operation, $opTimer);
1174     
1175     //
1176     // Tell it its timed out
1177     //
1178     $operation.setOperationHasTimedOut();
1179     //
1180     // Create a notification for it ("DB Write - end operation")
1181     //
1182     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1183     notification.setFrom("policy");
1184     notification.setPolicyName(drools.getRule().getName());
1185     notification.setPolicyScope("${policyScope}");
1186     notification.setPolicyVersion("${policyVersion}");
1187     notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1188     notification.setMessage($operation.getOperationHistory());
1189     notification.setHistory($operation.getHistory());
1190     //
1191     // Let interested parties know
1192     //
1193     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1194     //
1195     // Get rid of the timer
1196     //
1197     retract($opTimer);
1198     //
1199     // Ensure the operation is complete
1200     //
1201     if ($operation.isOperationComplete() == true) {
1202         //
1203         // It is complete, remove it from memory
1204         //
1205         retract($operation);
1206         //
1207         // Complete the operation
1208         //
1209         modify($manager) {finishOperation($operation)};
1210     } else {
1211         //
1212         // Just doing this will kick off the LOCKED rule again
1213         //
1214         modify($operation) {};
1215     }
1216 end
1217
1218 /*
1219 *
1220 * This is the timer that manages the overall control loop timeout.
1221 *
1222 */
1223 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1224     timer (expr: $to )
1225     when
1226         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1227         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1228         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1229         $clTimer : ControlLoopTimer ( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), $to : getDelay() )
1230     then
1231     
1232     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1233     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1234
1235     logger.debug("{}: {}: event={}", 
1236               $params.getClosedLoopControlName(), drools.getRule().getName(),
1237               $event);
1238     //
1239     // Tell the Event Manager it has timed out
1240     //
1241     VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1242     if (notification != null) {
1243         notification.setFrom("policy");
1244         notification.setPolicyName(drools.getRule().getName());
1245         notification.setPolicyScope("${policyScope}");
1246         notification.setPolicyVersion("${policyVersion}");
1247         //
1248         // Let interested parties know
1249         //
1250         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1251     }
1252     //
1253     // Retract the event
1254     //
1255     retract($event);
1256 end
1257
1258 /*
1259 *
1260 * This rule cleans up the manager and other objects after an event has
1261 * been retracted.
1262 *
1263 */
1264 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1265     when
1266         $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1267         $clTimer : ControlLoopTimer ( closedLoopControlName == $clName, requestID == $requestId.toString() )
1268         $operations : LinkedList()
1269                         from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, onset.getRequestId() == $requestId ) )
1270         $opTimers : LinkedList()
1271                         from collect( OperationTimer( closedLoopControlName == $clName, requestID == $requestId.toString() ) )
1272         $locks : LinkedList()
1273                         from collect( TargetLock (requestID == $requestId) )
1274         not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1275     then
1276     
1277     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1278     logger.info("{}: {}", $clName, drools.getRule().getName());
1279
1280     logger.debug("{}: {}: manager={} clTimer={} operations={}", 
1281               $clName, drools.getRule().getName(),
1282               $manager, $clTimer, $operations.size());
1283     
1284     //
1285     // Retract EVERYTHING
1286     //
1287     retract($manager);
1288     retract($clTimer);
1289     
1290     for(Object manager: $operations) {
1291         retract((ControlLoopOperationManager) manager);
1292     }
1293     for(Object opTimer: $opTimers) {
1294         retract((OperationTimer) opTimer);
1295     }
1296     for(Object lock: $locks) {
1297         TargetLock tgt = (TargetLock) lock;
1298         //
1299         // Ensure we release the lock
1300         //
1301         PolicyGuard.unlockTarget(tgt);
1302         retract(tgt);
1303     }
1304 end
1305
1306 /*
1307 *
1308 * This rule will clean up any rogue onsets where there is no 
1309 * ControlLoopParams object corresponding to the onset event.
1310 *
1311 */
1312 rule "${policyName}.EVENT.CLEANUP"
1313     when
1314         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1315         not ( Params( getClosedLoopControlName() == $clName) )
1316     then
1317  
1318     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1319     logger.info("{}: {}", $clName, drools.getRule().getName());
1320     logger.debug("{}: {}: orphan onset event={}", 
1321                 $clName, drools.getRule().getName(), $event);
1322
1323     retract($event);
1324 end
1325
1326 /*
1327 *
1328 * When rules are deleted, the associated Params (and its subordinate objects)
1329 * remain in working memory, because there are no longer any rules to clean
1330 * them up.  However, ANY time new rules are loaded, this rule will trigger
1331 * a clean-up of ALL Params, regardless of their name & yaml, thus removing
1332 * any that no longer have associated rules.
1333 * This has a higher salience so that we immediately check Params when the
1334 * rules change, before processing any events.
1335 *
1336 */
1337 rule "${policyName}.PARAMS.CHECKUP"
1338     salience 2
1339     when
1340         Params( $clName: closedLoopControlName, $yaml: controlLoopYaml )
1341     then
1342  
1343     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1344     logger.info("{}: {} : YAML=[{}]", $clName, drools.getRule().getName(), $yaml);
1345     
1346     ParamsCleaner cleaner = new ParamsCleaner();
1347     cleaner.setClosedLoopControlName($clName);
1348     cleaner.setControlLoopYaml($yaml);
1349     
1350     insert(cleaner);
1351 end
1352
1353 /*
1354 *
1355 * This rule removes "cleaner" objects for rules that are still active, thus
1356 * preventing the associated Params objects from being removed.  Any cleaners
1357 * that are left after this rule has fired will cause their corresponding Params
1358 * to be removed.
1359 * This has a higher salience so that we discard the cleaner before it has
1360 * a chance to force the removal of the associated Params.
1361 *
1362 */
1363 rule "${policyName}.CLEANER.ACTIVE"
1364     salience 2
1365     when
1366         $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}", getControlLoopYaml() == "${controlLoopYaml}" )
1367     then
1368  
1369     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1370     logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(), $cleaner.getControlLoopYaml());
1371     
1372     retract($cleaner);
1373 end
1374
1375 /*
1376 *
1377 * This rule removes Params objects that no longer have associated rules; if a
1378 * Params still had associated rules, then the cleaner would have been removed
1379 * by those rules and thus this rule would not fire.
1380 * This has a higher salience so that we remove old Params before it causes any
1381 * events to be processed.
1382 *
1383 */
1384 rule "${policyName}.PARAMS.CLEANUP"
1385     salience 1
1386     when
1387         $params: Params( $clName: closedLoopControlName, $yaml: controlLoopYaml )
1388         ParamsCleaner( getClosedLoopControlName() == $clName, getControlLoopYaml() == $yaml )
1389     then
1390  
1391     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1392     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(), $params.getControlLoopYaml());
1393     
1394     retract($params);
1395     
1396     // Note: the cleaner may be needed for cleaning additional params, thus
1397     // we do not retract it here - we'll leave that to another rule
1398 end
1399
1400 /*
1401 *
1402 * This rule removes "cleaner" objects when they're no longer needed.
1403 *
1404 */
1405 rule "${policyName}.CLEANER.CLEANUP"
1406     when
1407         $cleaner: ParamsCleaner( )
1408     then
1409  
1410     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1411     logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(), $cleaner.getControlLoopYaml());
1412     
1413     retract($cleaner);
1414 end