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