3dc984dd24cebd176d5a1223b920752c0a68e632
[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.getOperationRequest();
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     // We are starting the operation but the actor won't be contacted until Guard is queried and permitted.
598     //
599     $operation.startOperation($event);
600     
601     //
602     // Sending notification that we are about to query Guard ("DB write - start operation")
603     //
604     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
605     notification.notification = ControlLoopNotificationType.OPERATION;
606     notification.message = $operation.getOperationMessage();
607     notification.history = $operation.getHistory();
608     notification.from = "policy";
609     notification.policyName = drools.getRule().getName();
610     notification.policyScope = "${policyScope}";
611     notification.policyVersion = "${policyVersion}";
612     
613     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
614         
615     //
616     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard, 
617     // just change guardEnabled to false.
618     // 
619     // In order to use REST XACML, provide a URL instead of "" as a second argument 
620     // to the CallGuardTask() and set the first argument to null 
621     // (instead of XacmlPdpEngine).
622     //
623     boolean guardEnabled = false;
624     
625     if(guardEnabled){
626     
627         Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
628                                                         drools.getWorkingMemory(),
629                                                         $event.closedLoopControlName,
630                                                         $operation.policy.getActor().toString(),
631                                                         $operation.policy.getRecipe(),
632                                                         $manager.getTargetInstance($operation.policy),
633                                                         //$event.target,
634                                                         $event.requestID.toString()
635                                                         ));
636         t.start();
637     }
638     else{
639         insert(new PolicyGuardResponse("Permit", $event.requestID, $operation.policy.getRecipe()));
640     }
641
642 end
643
644 //
645 // This rule will be triggered when a thread talking to the XACML Guard inserts a 
646 // guardResponse object into the working memory
647 //
648 rule "${policyName}.GUARD.RESPONSE"
649     when
650         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
651         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
652         $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID ) 
653         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
654         $lock : TargetLock (requestID == $event.requestID)
655         $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
656         $guardResponse : PolicyGuardResponse(requestID == $event.requestID, $operation.policy.recipe == operation)
657     then
658
659     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
660     logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}", 
661                  $params.getClosedLoopControlName(), drools.getRule().getName(),
662                  $event, $manager, $operation, $lock, $opTimer, $guardResponse);
663         
664         
665     //we will permit the operation if there was no Guard for it
666     if("Indeterminate".equals($guardResponse.result)){
667         $guardResponse.result = "Permit";
668     }
669     
670     //
671     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
672     //
673     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
674     notification.notification = ControlLoopNotificationType.OPERATION;
675     notification.message = $operation.getOperationMessage($guardResponse.result);
676     notification.history = $operation.getHistory();
677     notification.from = "policy";
678     notification.policyName = drools.getRule().getName();
679     notification.policyScope = "${policyScope}";
680     notification.policyVersion = "${policyVersion}";
681     
682     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
683     
684     if("Permit".equalsIgnoreCase($guardResponse.result)){
685     
686         modify($operation){setGuardApprovalStatus($guardResponse.result)};
687     }
688     else {
689         //This is the Deny case
690         $operation.setOperationHasGuardDeny();
691         retract($opTimer);
692         retract($operation);
693         modify($manager) {finishOperation($operation)};
694     }
695     
696     retract($guardResponse);
697             
698 end
699
700 /*
701 *
702 * This rule responds to APPC Response Events
703 *
704 * I would have like to be consistent and write the Response like this:
705 * $response : Response( CommonHeader.RequestID == $onset.requestID )
706 *
707 * However, no compile error was given. But a runtime error was given. I think
708 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
709 *
710 */
711 rule "${policyName}.APPC.RESPONSE"
712     when
713         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
714         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
715         $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
716         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
717         $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
718         $lock : TargetLock (requestID == $event.requestID)
719         $response : Response( getCommonHeader().RequestID == $event.requestID )
720     then
721
722     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
723     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
724     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
725                  $params.getClosedLoopControlName(), drools.getRule().getName(),
726                  $event, $manager, $operation, $lock, $opTimer, $response);
727     //
728     // Get the result of the operation
729     //
730     PolicyResult policyResult = $operation.onResponse($response);
731     if (policyResult != null) {
732         logger.debug("{}: {}: operation finished - result={}", 
733                     $params.getClosedLoopControlName(), drools.getRule().getName(),
734                     policyResult);
735         //
736         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
737         //
738         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
739         notification.from = "policy";
740         notification.policyName = drools.getRule().getName();
741         notification.policyScope = "${policyScope}";
742         notification.policyVersion = "${policyVersion}";
743         notification.message = $operation.getOperationHistory();
744         notification.history = $operation.getHistory();
745         if (policyResult.equals(PolicyResult.SUCCESS)) {
746             notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS;
747             //
748             // Let interested parties know
749             //
750             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
751         } else {
752             notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
753             //
754             // Let interested parties know
755             //
756             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
757         }
758         //
759         // Ensure the operation is complete
760         //
761         if ($operation.isOperationComplete() == true) {
762             //
763             // It is complete, remove it from memory
764             //
765             retract($operation);
766             //
767             // We must also retract the timer object
768             // NOTE: We could write a Rule to do this
769             //
770             retract($opTimer);
771             //
772             // Complete the operation
773             //
774             modify($manager) {finishOperation($operation)};
775         } else {
776             //
777             // Just doing this will kick off the LOCKED rule again
778             //
779             modify($operation) {};
780         }
781     } else {
782         //
783         // Its not finished yet (i.e. expecting more Response objects)
784         //
785         // Or possibly it is a leftover response that we timed the request out previously
786         //
787     }
788     //
789     // We are going to retract these objects from memory
790     //
791     retract($response);
792 end
793
794 /*
795 *
796 * The problem with Responses is that they don't have a controlLoopControlName
797 * field in them, so the only way to attach them is via RequestID. If we have multiple
798 * control loop .drl's loaded in the same container, we need to be sure the cleanup
799 * rules don't remove Responses for other control loops.
800 *
801 */
802 rule "${policyName}.APPC.RESPONSE.CLEANUP"
803     when
804         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
805         $response : Response($id : getCommonHeader().RequestID )
806         not ( VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), requestID == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
807     then
808
809     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
810     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
811     logger.debug("{}: {}: orphan appc response={}", 
812                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
813         
814     //
815     // Retract it
816     //
817     retract($response);
818 end
819
820 /*
821 *
822 * This rule responds to APPC Response Events using the new LCM interface provided by appc
823 *
824 */
825 rule "${policyName}.APPC.LCM.RESPONSE"
826     when
827         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
828         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
829         $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
830         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
831         $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
832         $lock : TargetLock (requestID == $event.requestID)
833         $response : LCMResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.requestID )
834     then
835
836     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
837     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
838     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
839                 $params.getClosedLoopControlName(), drools.getRule().getName(),
840                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
841     
842     //
843     // Get the result of the operation
844     //
845     PolicyResult policyResult = $operation.onResponse($response);
846     if (policyResult != null) {
847       logger.debug("{}: {}: operation finished - result={}", 
848                   $params.getClosedLoopControlName(), drools.getRule().getName(),
849                   policyResult);
850       
851       //
852       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
853       //
854       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
855       notification.from = "policy";
856       notification.policyName = drools.getRule().getName();
857       notification.policyScope = "${policyScope}";
858       notification.policyVersion = "${policyVersion}";
859       notification.message = $operation.getOperationHistory();
860       notification.history = $operation.getHistory();
861       if (policyResult.equals(PolicyResult.SUCCESS)) {
862           notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS;
863       } else {
864           notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
865       }
866       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
867       //
868       // Ensure the operation is complete
869       //
870       if ($operation.isOperationComplete() == true) {
871           //
872           // It is complete, remove it from memory
873           //
874           retract($operation);
875           //
876           // We must also retract the timer object
877           // NOTE: We could write a Rule to do this
878           //
879           retract($opTimer);
880           //
881           // Complete the operation
882           //
883           modify($manager) {finishOperation($operation)};
884       } else {
885           //
886           // Just doing this will kick off the LOCKED rule again
887           //
888           modify($operation) {};
889       }
890     } else {
891         //
892         // Its not finished yet (i.e. expecting more Response objects)
893         //
894         // Or possibly it is a leftover response that we timed the request out previously
895         //
896     }
897     //
898     // We are going to retract these objects from memory
899     //
900     retract($response);
901 end
902
903 /*
904 *
905 * Clean Up any lingering LCM reponses
906 *
907 */
908 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
909     when
910         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
911         $response : LCMResponseWrapper($id : getBody().getCommonHeader().getRequestId )
912         not ( VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), requestID == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
913     then
914     
915     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
916     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
917     logger.debug("{}: {}: orphan appc response={}", 
918                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
919     //
920     // Retract it
921     //
922     retract($response);
923 end
924
925 /*
926 *
927 * This rule responds to SO Response Events
928 *
929 */
930 rule "${policyName}.SO.RESPONSE"
931     when
932         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
933         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
934         $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName )
935         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
936         $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
937         $lock : TargetLock (requestID == $event.requestID)
938         $response : SOResponse( request.requestId == $event.requestID.toString() )  
939     then
940         
941     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
942     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
943     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
944                 $params.getClosedLoopControlName(), drools.getRule().getName(),
945                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
946         
947     // Get the result of the operation
948     //
949     PolicyResult policyResult = $operation.onResponse($response);
950     if (policyResult != null) {
951         logger.debug("{}: {}: operation finished - result={}", 
952                     $params.getClosedLoopControlName(), drools.getRule().getName(),
953                     policyResult);
954       
955         //
956         // This Operation has completed, construct a notification showing our results
957         //
958         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
959         notification.from = "policy";
960         notification.policyName = drools.getRule().getName();
961         notification.policyScope = "${policyScope}";
962         notification.policyVersion = "${policyVersion}";
963         notification.message = $operation.getOperationHistory();
964         notification.history = $operation.getHistory();
965         if (policyResult.equals(PolicyResult.SUCCESS)) {
966             notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS;
967         } else {
968             notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
969
970         }
971         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
972         //
973         // Ensure the operation is complete
974         //
975         if ($operation.isOperationComplete() == true) {
976             //
977             // It is complete, remove it from memory
978             //
979             retract($operation);
980             //
981             // We must also retract the timer object
982             // NOTE: We could write a Rule to do this
983             //
984             retract($opTimer);
985             //
986             // Complete the operation
987             //
988             modify($manager) {finishOperation($operation)};
989         } else {
990             //
991             // Just doing this will kick off the LOCKED rule again
992             //
993             modify($operation) {};
994         }
995     } else {
996         //
997         // Its not finished yet (i.e. expecting more Response objects)
998         //
999         // Or possibly it is a leftover response that we timed the request out previously
1000         //
1001     }
1002     //
1003     // We are going to retract these objects from memory
1004     //
1005     retract($response);
1006
1007 end
1008
1009 /*
1010 *
1011 * This rule responds to VFC Response Events
1012 *
1013 */
1014 rule "${policyName}.VFC.RESPONSE"
1015         when
1016                 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1017                 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1018                 $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName )
1019                 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
1020                 $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
1021         $lock : TargetLock (requestID == $event.requestID)
1022                 $response : VFCResponse( requestId.toString() == $event.requestID.toString() )  
1023         then
1024                 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1025         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1026         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1027                         $params.getClosedLoopControlName(), drools.getRule().getName(),
1028                         $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1029                 
1030                 // Get the result of the operation
1031                 //
1032                 PolicyResult policyResult = $operation.onResponse($response);
1033                 if (policyResult != null) {
1034                         //
1035                         // This Operation has completed, construct a notification showing our results
1036                         //
1037                         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1038                         notification.from = "policy";
1039                         notification.policyName = drools.getRule().getName();
1040                         notification.policyScope = "${policyScope}";
1041                         notification.policyVersion = "${policyVersion}";
1042                         notification.message = $operation.getOperationHistory();
1043                         notification.history = $operation.getHistory();
1044                         //
1045                         // Ensure the operation is complete
1046                         //
1047                         if ($operation.isOperationComplete() == true) {
1048                                 //
1049                                 // It is complete, remove it from memory
1050                                 //
1051                                 retract($operation);
1052                                 //
1053                                 // We must also retract the timer object
1054                                 // NOTE: We could write a Rule to do this
1055                                 //
1056                                 retract($opTimer);
1057                                 //
1058                                 // Complete the operation
1059                                 //
1060                                 modify($manager) {finishOperation($operation)};
1061                         } else {
1062                                 //
1063                                 // Just doing this will kick off the LOCKED rule again
1064                                 //
1065                                 modify($operation) {};
1066                         }
1067                 } else {
1068                         //
1069                         // Its not finished yet (i.e. expecting more Response objects)
1070                         //
1071                         // Or possibly it is a leftover response that we timed the request out previously
1072                         //
1073                 }
1074                 //
1075                 // We are going to retract these objects from memory
1076                 //
1077                 retract($response);
1078
1079 end
1080
1081 /*
1082 *
1083 * This is the timer that manages the timeout for an individual operation.
1084 *
1085 */
1086 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1087     timer (expr: $to )
1088     when
1089         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1090         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1091         $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
1092         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
1093         $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString(), $to : getDelay() )
1094         $lock : TargetLock (requestID == $event.requestID)
1095     then
1096     
1097     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1098     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1099     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}", 
1100                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1101                 $event, $manager, $operation, $lock, $operation, $opTimer);
1102     
1103     //
1104     // Tell it its timed out
1105     //
1106     $operation.setOperationHasTimedOut();
1107     //
1108     // Create a notification for it ("DB Write - end operation")
1109     //
1110     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1111     notification.from = "policy";
1112     notification.policyName = drools.getRule().getName();
1113     notification.policyScope = "${policyScope}";
1114     notification.policyVersion = "${policyVersion}";
1115     notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
1116     notification.message = $operation.getOperationHistory();
1117     notification.history = $operation.getHistory();
1118     //
1119     // Let interested parties know
1120     //
1121     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1122     //
1123     // Get rid of the timer
1124     //
1125     retract($opTimer);
1126     //
1127     // Ensure the operation is complete
1128     //
1129     if ($operation.isOperationComplete() == true) {
1130         //
1131         // It is complete, remove it from memory
1132         //
1133         retract($operation);
1134         //
1135         // Complete the operation
1136         //
1137         modify($manager) {finishOperation($operation)};
1138     } else {
1139         //
1140         // Just doing this will kick off the LOCKED rule again
1141         //
1142         modify($operation) {};
1143     }
1144 end
1145
1146 /*
1147 *
1148 * This is the timer that manages the overall control loop timeout.
1149 *
1150 */
1151 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1152     timer (expr: $to )
1153     when
1154         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1155         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1156         $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
1157         $clTimer : ControlLoopTimer ( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString(), $to : getDelay() )
1158         $operations : LinkedList()
1159                         from collect( ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID ) )
1160         $opTimers : LinkedList()
1161                         from collect( OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() ) )
1162         $locks : LinkedList()
1163                         from collect( TargetLock (requestID == $event.requestID) )
1164     then
1165     
1166     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1167     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1168
1169     if ($operations == null) {
1170       logger.debug("{}: {}: event={} manager={} clTimer={} operations=0", 
1171                   $params.getClosedLoopControlName(), drools.getRule().getName(),
1172                   $event, $manager, $clTimer);
1173     } else {
1174       logger.debug("{}: {}: event={} manager={} clTimer={} operations={}", 
1175                   $params.getClosedLoopControlName(), drools.getRule().getName(),
1176                   $event, $manager, $clTimer, $operations.size());
1177     }
1178     //
1179     // Tell the Event Manager it has timed out
1180     //
1181     VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1182     if (notification != null) {
1183         notification.from = "policy";
1184         notification.policyName = drools.getRule().getName();
1185         notification.policyScope = "${policyScope}";
1186         notification.policyVersion = "${policyVersion}";
1187         //
1188         // Let interested parties know
1189         //
1190         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1191     }
1192     //
1193     // Retract EVERYTHING
1194     //
1195     retract($event);
1196     retract($manager);
1197     retract($clTimer);
1198     if ($operations != null && $operations.size() > 0) {
1199         Iterator<ControlLoopOperationManager> iter = $operations.iterator();
1200         while (iter.hasNext()) {
1201             ControlLoopOperationManager manager = iter.next();
1202             retract(manager);
1203         }
1204     }
1205     if ($opTimers != null && $opTimers.size() > 0) {
1206         Iterator<OperationTimer> iter = $opTimers.iterator();
1207         while (iter.hasNext()) {
1208             OperationTimer opTimer = iter.next();
1209             retract(opTimer);
1210         }
1211     }
1212     if ($locks != null && $locks.size() > 0) {
1213         Iterator<TargetLock> iter = $locks.iterator();
1214         while (iter.hasNext()) {
1215             TargetLock lock = iter.next();
1216             //
1217             // Ensure we release the lock
1218             //
1219             PolicyGuard.unlockTarget(lock);
1220             //
1221             //
1222             //
1223             retract(lock);
1224         }
1225     }
1226 end