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