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