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