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