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