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