3368e9153c7089bf2b83ecef9263fa0cba8a6df9
[policy/drools-applications.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2019 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.NewEventStatus;
33 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
34 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
35 import org.onap.policy.aai.AaiNqResponseWrapper;
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.sdnr.PciRequestWrapper;
45 import org.onap.policy.sdnr.PciResponseWrapper;
46 import org.onap.policy.sdnr.PciRequest;
47 import org.onap.policy.sdnr.PciResponse;
48 import org.onap.policy.vfc.VfcRequest;
49 import org.onap.policy.vfc.VfcResponse;
50 import org.onap.policy.vfc.VfcManager;
51 import org.onap.policy.so.SoRequest;
52 import org.onap.policy.so.SoResponseWrapper;
53 import org.onap.policy.sdnc.SdncRequest;
54 import org.onap.policy.sdnc.SdncManager;
55 import org.onap.policy.sdnc.SdncResponse;
56 import org.onap.policy.guard.PolicyGuard;
57 import org.onap.policy.guard.PolicyGuard.LockResult;
58 import org.onap.policy.guard.TargetLock;
59 import org.onap.policy.guard.GuardResult;
60 import org.onap.policy.guard.PolicyGuardRequest;
61 import org.onap.policy.guard.PolicyGuardResponse;
62 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
63 import org.onap.policy.guard.PolicyGuardXacmlHelper;
64
65 import org.yaml.snakeyaml.Yaml;
66 import org.yaml.snakeyaml.constructor.Constructor;
67
68 import org.slf4j.LoggerFactory;
69 import org.slf4j.Logger;
70
71 import java.time.Instant;
72 import java.util.LinkedList;
73 import java.util.Iterator;
74
75 import org.onap.policy.drools.system.PolicyEngine;
76
77 /*
78  * This structure mimics the Params structure.
79  * Its only purpose is to allow management of
80  * rules by the PAP component..
81  * It has no use at runtime since the rules go by
82  * Params for matching purposes.
83  */
84 declare PapParams
85   closedLoopControlName : String
86   controlLoopYaml : String
87 end
88
89 /*
90  * Control Loop Identity
91  */
92 declare Params
93   closedLoopControlName : String
94   controlLoopYaml : String
95 end
96
97 /*
98  * Used to trigger clean up Params that no longer have associated rules.
99  */
100 declare ParamsInitCleaner
101   closedLoopControlName : String    // only used when logging
102 end
103
104 /*
105  * Used to clean up Params that no longer have associated rules.
106  */
107 declare ParamsCleaner
108   closedLoopControlName : String
109   controlLoopYaml : String
110 end
111
112 /*
113  * This object is to provide support for timeouts
114  * due to a bug in drools' built-in timers
115  */
116 declare ControlLoopTimer
117     closedLoopControlName : String
118     requestID : String
119     delay : String
120     expired : boolean
121     //timerType is the type of timer: either "ClosedLoop" or "Operation"
122     timerType : String
123 end
124
125 /*
126 *
127 * Called to insert the parameters into working memory for this Closed Loop policy.  This is called
128 * once each time a closed loop is added or its YAML is updated.
129 * This has a higher salience so we can ensure that the Params is created before we have a chance to
130 * discard any events.
131 *
132 */
133 rule "${policyName}.SETUP"
134     salience 1
135     when
136         not( Params( getClosedLoopControlName() == "${closedLoopControlName}", 
137             getControlLoopYaml() == "${controlLoopYaml}" ) )
138     then
139     
140     Params params = new Params();
141     params.setClosedLoopControlName("${closedLoopControlName}");
142     params.setControlLoopYaml("${controlLoopYaml}");
143     insert(params);
144     
145     ParamsInitCleaner initCleaner = new ParamsInitCleaner();
146     initCleaner.setClosedLoopControlName("${closedLoopControlName}");
147     insert(initCleaner);
148
149     // Note: globals have bad behavior when persistence is used,
150     //       hence explicitly getting the logger vs using a global
151     
152     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
153     logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), 
154         params.getControlLoopYaml());
155 end
156
157 /*
158 *
159 * This rule responds to DCAE Events where there is no manager yet. Either it is
160 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
161 *
162 */
163 rule "${policyName}.EVENT"
164     when
165         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
166         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
167         not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
168             requestId == $event.getRequestId() ) )
169     then
170  
171     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
172     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
173     
174     try {
175       
176         //
177         // Check the event, because we need it to not be null when
178         // we create the ControlLoopEventManager. The ControlLoopEventManager
179         // will do extra syntax checking as well check if the closed loop is disabled.
180         //
181         if ($event.getRequestId() == null) {
182             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
183             notification.setNotification(ControlLoopNotificationType.REJECTED);
184             notification.setFrom("policy");
185             notification.setMessage("Missing requestId");
186             notification.setPolicyName(drools.getRule().getName());
187             notification.setPolicyScope("${policyScope}");
188             notification.setPolicyVersion("${policyVersion}");
189             
190             //
191             // Let interested parties know
192             //
193             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
194             
195             //
196             // Retract it from memory
197             //
198             retract($event);
199         } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
200             throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
201         } else {
202             //
203             // Create an EventManager
204             //
205             ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(), 
206                 $event.getRequestId());
207             //
208             // Determine if EventManager can actively process the event 
209             // (i.e. syntax, is_closed_loop_disabled checks etc.)
210             //
211             VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
212             notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
213             notification.setPolicyName(drools.getRule().getName());
214             notification.setPolicyScope("${policyScope}");
215             notification.setPolicyVersion("${policyVersion}");
216             //
217             // Are we actively pursuing this event?
218             //
219             if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
220                 //
221                 // Insert Event Manager into memory, this will now kick off processing.
222                 //
223                 insert(manager);
224                 //
225                 // Let interested parties know
226                 //
227                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
228                 //
229                 // Setup the Overall Control Loop timer
230                 //
231                 ControlLoopTimer clTimer = new ControlLoopTimer();
232                 clTimer.setTimerType("ClosedLoop");
233                 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
234                 clTimer.setRequestID($event.getRequestId().toString());
235                 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
236                 //
237                 // Insert it
238                 //
239                 insert(clTimer);
240             } else {
241                 //
242                 // Let interested parties know
243                 //
244                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
245                 //
246                 // Retract it from memory
247                 //
248                 retract($event);
249             }
250             
251             //
252             // Now that the manager is inserted into Drools working memory, we'll wait for
253             // another rule to fire in order to continue processing. This way we can also
254             // then screen for additional ONSET and ABATED events for this RequestId.
255             //
256         }
257     } catch (Exception e) {
258         logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
259         
260         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
261         notification.setNotification(ControlLoopNotificationType.REJECTED);
262         notification.setMessage("Exception occurred: " + e.getMessage());
263         notification.setPolicyName(drools.getRule().getName());
264         notification.setPolicyScope("${policyScope}");
265         notification.setPolicyVersion("${policyVersion}");
266         //
267         //
268         //
269         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
270         //
271         // Retract the event
272         //
273         retract($event);
274     }
275 end
276
277 /*
278 *
279 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
280 * is now created. We can start processing the yaml specification via the Event Manager.
281 *
282 */
283 rule "${policyName}.EVENT.MANAGER"
284     when
285         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
286         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
287         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
288             requestId == $event.getRequestId() )
289         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
290             requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", !expired )
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.NewEventStatus eventStatus = $manager.onNewEvent($event);
303         //
304         // Check what kind of event this is
305         //
306         if (eventStatus == NewEventStatus.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 == NewEventStatus.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 != NewEventStatus.FIRST_ONSET) {
330             logger.warn("{}: {}: not first onset", 
331                         $params.getClosedLoopControlName(), drools.getRule().getName());
332             retract($event);
333         }
334         
335         logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(), 
336                      drools.getRule().getName(), $event.getTarget());
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.getRequestId());
355                 
356                 /// DB Write---end event processing for this RequestId()
357                 $manager.commitAbatement("Event Abated","Closed");
358                 
359                 notification.setFrom("policy");
360                 notification.setPolicyName(drools.getRule().getName());
361                 notification.setPolicyScope("${policyScope}");
362                 notification.setPolicyVersion("${policyVersion}");
363                 //
364                 // In this case, we are done
365                 //
366                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
367                 //
368                 // Unlock the target
369                 //
370                 TargetLock lock = $manager.unlockCurrentOperation();
371                 if (lock != null) {
372                     logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(), 
373                                  drools.getRule().getName(), lock);
374                     retract(lock);
375                 }
376                 //
377                 // Retract everything from memory
378                 //
379                 logger.info("{}: {}: retracting onset, manager, and timer", 
380                             $params.getClosedLoopControlName(), drools.getRule().getName());
381                 
382                 retract($manager.getOnsetEvent());
383                 
384                 // don't retract manager, etc. - a clean-up rule will do that
385                 
386                 //
387                 // TODO - what if we get subsequent Events for this RequestId?
388                 // By default, it will all start over again. May be confusing for Ruby.
389                 // Or, we could track this and then subsequently ignore the events
390                 //
391             } else {
392                 //
393                 // Check whether we need to wait for abatement
394                 //
395                 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
396                   logger.info("{}: {}: waiting for abatement ..", 
397                               $params.getClosedLoopControlName(), drools.getRule().getName());
398                 } else {
399                   logger.info("{}: {}: no abatement expect for {}.  Closing the control loop", 
400                               $params.getClosedLoopControlName(), drools.getRule().getName(), 
401                               $event.getRequestId());
402                   
403                   notification.setFrom("policy");
404                   notification.setPolicyName(drools.getRule().getName());
405                   notification.setPolicyScope("${policyScope}");
406                   notification.setPolicyVersion("${policyVersion}");
407                   
408                   //
409                   // In this case, we are done
410                   //
411                   PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
412                   //
413                   // Unlock the target
414                   //
415                   TargetLock lock = $manager.unlockCurrentOperation();
416                   if (lock != null) {
417                       logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(), 
418                                   drools.getRule().getName(), lock);
419                       retract(lock);
420                   }
421                   //
422                   // Retract everything from memory
423                   //
424                   logger.info("{}: {}: retracting onset, manager, and timer", 
425                               $params.getClosedLoopControlName(), drools.getRule().getName());
426                   
427                   retract($manager.getOnsetEvent());
428                 
429                 // don't retract manager, etc. - a clean-up rule will do that
430                 }
431             }
432         } else {
433             //
434             // NOT final, so let's ask for the next operation
435             //
436             ControlLoopOperationManager operation = $manager.processControlLoop();
437             if (operation != null) {
438               //
439               // Let's ask for a lock right away
440               //
441               LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
442               logger.info("{}: {}: guard lock acquired={}", 
443                             $params.getClosedLoopControlName(), drools.getRule().getName(), 
444                             result.getB());
445               if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
446                   //
447                   // insert the operation into memory
448                   //
449                   insert(operation);
450                   //
451                   // insert operation timeout object
452                   //
453                    ControlLoopTimer opTimer = new ControlLoopTimer();
454                    opTimer.setTimerType("Operation");
455                    opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
456                    opTimer.setRequestID($event.getRequestId().toString());
457                    opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
458                   insert(opTimer);
459               
460                   //
461                   // Insert lock into memory
462                   //
463                   insert(result.getB());
464               } else {
465                    logger.debug("The target resource {} is already processing",
466                             $event.getAai().get($event.getTarget()));
467                   notification = new VirtualControlLoopNotification($event);
468                   notification.setNotification(ControlLoopNotificationType.REJECTED);
469                   notification.setMessage("The target " + $event.getAai().get($event.getTarget()) 
470                       + " is already locked");
471                   notification.setFrom("policy");
472                   notification.setPolicyName(drools.getRule().getName());
473                   notification.setPolicyScope("${policyScope}");
474                   notification.setPolicyVersion("${policyVersion}");
475       
476                   PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
477
478                   retract($event);
479                 
480                   // don't retract manager, etc. - a clean-up rule will do that
481
482                   if (result.getB() != null) {
483                       retract(result.getB());
484                   }
485               }
486               logger.info("{}: {}: starting operation={}", 
487                           $params.getClosedLoopControlName(), drools.getRule().getName(), 
488                           operation);
489             } else {
490                 //
491                 // Probably waiting for abatement
492                 //
493               logger.info("{}: {}: no operation, probably waiting for abatement", 
494                           $params.getClosedLoopControlName(), drools.getRule().getName());
495             }
496         }
497     } catch (Exception e) {
498          logger.warn("{}: {}: unexpected", 
499                   $params.getClosedLoopControlName(), 
500                   drools.getRule().getName(), e);
501
502          VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
503          notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
504          notification.setMessage(e.getMessage());
505          notification.setFrom("policy");
506          notification.setPolicyName(drools.getRule().getName());
507          notification.setPolicyScope("${policyScope}");
508          notification.setPolicyVersion("${policyVersion}");
509   
510          PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
511
512          retract($event);
513                 
514          // don't retract manager, etc. - a clean-up rule will do that
515     }
516         
517 end
518
519 /*
520 *
521 * Guard Permitted, let's send request to the actor.
522 *
523 */
524 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
525     when
526         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
527         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
528         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
529             requestId == $event.getRequestId() )
530         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
531             onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
532         $lock : TargetLock (requestID == $event.getRequestId())
533         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
534             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
535     then
536
537     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
538     logger.info("{}: {}: event={} manager={} operation={} lock={}", 
539                 $params.getClosedLoopControlName(), drools.getRule().getName(),
540                 $event, $manager, $operation, $lock);    
541
542     Object request = null;
543     boolean caughtException = false;
544     
545     try {
546         request = $operation.startOperation($event);
547         
548         if (request != null) {
549           logger.debug("{}: {}: starting operation ..", 
550                        $params.getClosedLoopControlName(), drools.getRule().getName());
551           //
552           // Tell interested parties we are performing this Operation
553           //
554           VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
555           notification.setNotification(ControlLoopNotificationType.OPERATION);
556           notification.setMessage($operation.getOperationMessage());
557           notification.setHistory($operation.getHistory());
558           notification.setFrom("policy");
559           notification.setPolicyName(drools.getRule().getName());
560           notification.setPolicyScope("${policyScope}");
561           notification.setPolicyVersion("${policyVersion}");
562
563           PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
564
565           switch ($operation.policy.getActor()){
566
567               case "APPC":
568                   if (request instanceof Request) {
569                       PolicyEngine.manager.deliver("APPC-CL", request);
570                   }
571                   else if (request instanceof LcmRequestWrapper) {
572                       PolicyEngine.manager.deliver("APPC-LCM-READ", request);
573                   }
574                   break;
575               case "SO":
576                   // at this point the AAI named query request should have already been made, 
577                   // the response recieved and used
578                   // in the construction of the SO Request which is stored in operationRequest
579
580                   if(request instanceof SoRequest) {
581                       // Call SO. The response will be inserted into memory once it's received 
582                       SoActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(),
583                           request);                        
584                   }
585                   break;
586               case "VFC":
587                   if (request instanceof VfcRequest) {
588                       // Start VFC thread
589                       Thread t = new Thread(new VfcManager(drools.getWorkingMemory(), (VfcRequest)request));
590                       t.start();
591                   }          
592                   break;
593                 
594               case "SDNC":
595                   if (request instanceof SdncRequest) {
596                      // Start SDNC thread
597                      Thread t = new Thread(new SdncManager(drools.getWorkingMemory(), (SdncRequest)request));
598                      t.start();
599                   }
600                   break;                       
601               case "SDNR":
602                   if (request instanceof PciRequestWrapper) {
603                       PolicyEngine.manager.deliver("SDNR-CL", request);
604                   }
605                   break;
606           }
607         } else {
608           //
609           // What happens if its null?
610           //
611             logger.warn("{}: {}: unexpected null operation request", 
612                       $params.getClosedLoopControlName(), 
613                       drools.getRule().getName());
614             if ("SO".equals($operation.policy.getActor())) {
615                 retract($opTimer);
616                 retract($operation);
617                 modify($manager) {finishOperation($operation)};
618             }
619             else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
620                 retract($opTimer);
621                 retract($operation);
622                 modify($manager) {finishOperation($operation)};
623             }
624             else if ("sdnc".equalsIgnoreCase($operation.policy.getActor())) {
625                 retract($opTimer);
626                 retract($operation);
627                 modify($manager) {finishOperation($operation)};
628             }
629         }
630         
631     } catch (Exception e) {
632         String msg = e.getMessage();
633         logger.warn("{}: {}: operation={}:  AAI failure: {}", 
634                     $params.getClosedLoopControlName(), drools.getRule().getName(),
635                     $operation, msg, e);
636         $operation.setOperationHasException(msg);
637         
638         if(request != null) {
639             //
640             // Create a notification for it ("DB Write - end operation")
641             //
642             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
643             notification.setFrom("policy");
644             notification.setPolicyName(drools.getRule().getName());
645             notification.setPolicyScope("${policyScope}");
646             notification.setPolicyVersion("${policyVersion}");
647             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
648             notification.setMessage($operation.getOperationHistory());
649             notification.setHistory($operation.getHistory());
650           
651             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
652         }
653     
654         retract($opTimer);
655         retract($operation);
656         caughtException = true;
657     }
658     
659     // Having the modify statement in the catch clause doesn't work for whatever reason
660     if (caughtException) {
661         modify($manager) {finishOperation($operation)};
662     }
663 end
664
665
666 /*
667 *
668 * We were able to acquire a lock so now let's ask Xacml Guard whether 
669 * we are allowed to proceed with the request to the actor.
670 *
671 */
672 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
673     when
674         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
675         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
676         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
677             requestId == $event.getRequestId() )
678         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
679             onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
680         $lock : TargetLock (requestID == $event.getRequestId())
681     then
682
683     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
684     logger.info("{}: {}: event={} manager={} operation={} lock={}", 
685                 $params.getClosedLoopControlName(), drools.getRule().getName(),
686                 $event, $manager, $operation, $lock);
687     
688     //
689     // Sending notification that we are about to query Guard ("DB write - start operation")
690     //
691     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
692     notification.setNotification(ControlLoopNotificationType.OPERATION);
693     notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " 
694         + $operation.policy.getRecipe());
695     notification.setHistory($operation.getHistory());
696     notification.setFrom("policy");
697     notification.setPolicyName(drools.getRule().getName());
698     notification.setPolicyScope("${policyScope}");
699     notification.setPolicyVersion("${policyVersion}");
700     
701     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
702         
703     //
704     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard, 
705     // just change guardEnabled to false.
706     // 
707     // In order to use REST XACML, provide a URL instead of "" as a second argument 
708     // to the CallGuardTask() and set the first argument to null 
709     // (instead of XacmlPdpEngine).
710     //
711     
712     // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
713     boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
714     
715     if(guardEnabled){
716     
717         Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
718                                                         drools.getWorkingMemory(),
719                                                         $event.getClosedLoopControlName(),
720                                                         $operation.policy.getActor().toString(),
721                                                         $operation.policy.getRecipe(),
722                                                         $operation.getTargetEntity(),
723                                                         $event.getRequestId().toString(),
724                                                         () -> {
725                                                             AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
726                                                             return(resp == null ? null : resp.countVfModules());
727                                                         }));
728         t.start();
729     }
730     else{
731         insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
732     }
733
734 end
735
736 //
737 // This rule will be triggered when a thread talking to the XACML Guard inserts a 
738 // guardResponse object into the working memory
739 //
740 rule "${policyName}.GUARD.RESPONSE"
741     when
742         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
743         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
744             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
745         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
746             requestId == $event.getRequestId() ) 
747         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
748             onset.getRequestId() == $event.getRequestId() )
749         $lock : TargetLock (requestID == $event.getRequestId())
750         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
751             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
752         $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
753     then
754
755     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
756     logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}", 
757                  $params.getClosedLoopControlName(), drools.getRule().getName(),
758                  $event, $manager, $operation, $lock, $opTimer, $guardResponse);
759         
760         
761     //we will permit the operation if there was no Guard for it
762     if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
763         $guardResponse.setResult("Permit");
764     }
765     
766     //
767     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
768     //
769     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
770     notification.setNotification(ControlLoopNotificationType.OPERATION);
771     notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe()
772         + " is " + $guardResponse.getResult());
773     notification.setHistory($operation.getHistory());
774     notification.setFrom("policy");
775     notification.setPolicyName(drools.getRule().getName());
776     notification.setPolicyScope("${policyScope}");
777     notification.setPolicyVersion("${policyVersion}");
778     
779     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
780     
781     if("Permit".equalsIgnoreCase($guardResponse.getResult())){
782     
783         modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
784     }
785     else {
786         //This is the Deny case
787         $operation.startOperation($event);
788         $operation.setOperationHasGuardDeny();
789         retract($opTimer);
790         retract($operation);
791         modify($manager) {finishOperation($operation)};
792     }
793     
794     retract($guardResponse);
795             
796 end
797
798 /*
799 *
800 * This rule responds to APPC Response Events
801 *
802 * I would have like to be consistent and write the Response like this:
803 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
804 *
805 * However, no compile error was given. But a runtime error was given. I think
806 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
807 *
808 */
809 rule "${policyName}.APPC.RESPONSE"
810     when
811         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
812         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
813             closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
814         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
815             requestId == $event.getRequestId() )
816         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
817             onset.getRequestId() == $event.getRequestId() )
818         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
819             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
820         $lock : TargetLock (requestID == $event.getRequestId())
821         $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
822     then
823
824     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
825     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
826     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
827                  $params.getClosedLoopControlName(), drools.getRule().getName(),
828                  $event, $manager, $operation, $lock, $opTimer, $response);
829     //
830     // Get the result of the operation
831     //
832     PolicyResult policyResult = $operation.onResponse($response);
833     if (policyResult != null) {
834         logger.debug("{}: {}: operation finished - result={}", 
835                     $params.getClosedLoopControlName(), drools.getRule().getName(),
836                     policyResult);
837         //
838         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
839         //
840         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
841         notification.setFrom("policy");
842         notification.setPolicyName(drools.getRule().getName());
843         notification.setPolicyScope("${policyScope}");
844         notification.setPolicyVersion("${policyVersion}");
845         notification.setMessage($operation.getOperationHistory());
846         notification.setHistory($operation.getHistory());
847         if (policyResult.equals(PolicyResult.SUCCESS)) {
848             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
849             //
850             // Let interested parties know
851             //
852             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
853         } else {
854             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
855             //
856             // Let interested parties know
857             //
858             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
859         }
860         //
861         // Ensure the operation is complete
862         //
863         if ($operation.isOperationComplete() == true) {
864             //
865             // It is complete, remove it from memory
866             //
867             retract($operation);
868             //
869             // We must also retract the timer object
870             // NOTE: We could write a Rule to do this
871             //
872             retract($opTimer);
873             //
874             // Complete the operation
875             //
876             modify($manager) {finishOperation($operation)};
877         } else {
878             //
879             // Just doing this will kick off the LOCKED rule again
880             //
881             modify($operation) {};
882         }
883     } else {
884         //
885         // Its not finished yet (i.e. expecting more Response objects)
886         //
887         // Or possibly it is a leftover response that we timed the request out previously
888         //
889     }
890     //
891     // We are going to retract these objects from memory
892     //
893     retract($response);
894 end
895
896 /*
897 *
898 * The problem with Responses is that they don't have a controlLoopControlName
899 * field in them, so the only way to attach them is via RequestId. If we have multiple
900 * control loop .drl's loaded in the same container, we need to be sure the cleanup
901 * rules don't remove Responses for other control loops.
902 *
903 */
904 rule "${policyName}.APPC.RESPONSE.CLEANUP"
905     when
906         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
907         $response : Response($id : getCommonHeader().RequestId )
908         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
909     then
910
911     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
912     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
913     logger.debug("{}: {}: orphan appc response={}", 
914                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
915         
916     //
917     // Retract it
918     //
919     retract($response);
920 end
921
922 /*
923 *
924 * This rule responds to APPC Response Events using the new LCM interface provided by appc
925 *
926 */
927 rule "${policyName}.APPC.LCM.RESPONSE"
928     when
929         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
930         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
931             closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
932         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
933             requestId == $event.getRequestId() )
934         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
935             onset.getRequestId() == $event.getRequestId() )
936         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
937             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
938         $lock : TargetLock (requestID == $event.getRequestId())
939         $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
940     then
941
942     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
943     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
944     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
945                 $params.getClosedLoopControlName(), drools.getRule().getName(),
946                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
947     
948     //
949     // Get the result of the operation
950     //
951     PolicyResult policyResult = $operation.onResponse($response);
952     if (policyResult != null) {
953       logger.debug("{}: {}: operation finished - result={}", 
954                   $params.getClosedLoopControlName(), drools.getRule().getName(),
955                   policyResult);
956       
957       //
958       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
959       //
960       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
961       notification.setFrom("policy");
962       notification.setPolicyName(drools.getRule().getName());
963       notification.setPolicyScope("${policyScope}");
964       notification.setPolicyVersion("${policyVersion}");
965       notification.setMessage($operation.getOperationHistory());
966       notification.setHistory($operation.getHistory());
967       if (policyResult.equals(PolicyResult.SUCCESS)) {
968           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
969       } else {
970           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
971       }
972       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
973       //
974       // Ensure the operation is complete
975       //
976       if ($operation.isOperationComplete() == true) {
977           //
978           // It is complete, remove it from memory
979           //
980           retract($operation);
981           //
982           // We must also retract the timer object
983           // NOTE: We could write a Rule to do this
984           //
985           retract($opTimer);
986           //
987           // Complete the operation
988           //
989           modify($manager) {finishOperation($operation)};
990       } else {
991           //
992           // Just doing this will kick off the LOCKED rule again
993           //
994           modify($operation) {};
995       }
996     } else {
997         //
998         // Its not finished yet (i.e. expecting more Response objects)
999         //
1000         // Or possibly it is a leftover response that we timed the request out previously
1001         //
1002     }
1003     //
1004     // We are going to retract these objects from memory
1005     //
1006     retract($response);
1007 end
1008
1009 /*
1010 *
1011 * Clean Up any lingering LCM reponses
1012 *
1013 */
1014 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
1015     when
1016         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1017         $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1018         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
1019     then
1020     
1021     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1022     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1023     logger.debug("{}: {}: orphan appc response={}", 
1024                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1025     //
1026     // Retract it
1027     //
1028     retract($response);
1029 end
1030
1031 /*
1032 *
1033 * This rule responds to SDNR Response Events using the new interface provided by SDNR
1034 *
1035 */
1036 rule "${policyName}.SDNR.RESPONSE"
1037     when
1038         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1039         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
1040             closedLoopEventStatus == ControlLoopEventStatus.ONSET ) 
1041         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1042             requestId == $event.getRequestId() )
1043         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1044             onset.getRequestId() == $event.getRequestId() )
1045         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1046             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1047         $lock : TargetLock (requestID == $event.getRequestId())
1048         $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1049     then
1050
1051     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1052     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1053     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1054                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1055                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1056     
1057     //
1058     // Get the result of the operation
1059     //
1060     PolicyResult policyResult = $operation.onResponse($response);
1061     if (policyResult != null) {
1062       logger.debug("{}: {}: operation finished - result={}", 
1063                   $params.getClosedLoopControlName(), drools.getRule().getName(),
1064                   policyResult);
1065       
1066       //
1067       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1068       //
1069       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1070       notification.setFrom("policy");
1071       notification.setPolicyName(drools.getRule().getName());
1072       notification.setPolicyScope("${policyScope}");
1073       notification.setPolicyVersion("${policyVersion}");
1074       notification.setMessage($operation.getOperationHistory());
1075       notification.setHistory($operation.getHistory());
1076       if (policyResult.equals(PolicyResult.SUCCESS)) {
1077           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1078       } else {
1079           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1080       }
1081       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1082       //
1083       // Ensure the operation is complete
1084       //
1085       if ($operation.isOperationComplete()) {
1086           //
1087           // It is complete, remove it from memory
1088           //
1089           retract($operation);
1090           //
1091           // We must also retract the timer object
1092           // NOTE: We could write a Rule to do this
1093           //
1094           retract($opTimer);
1095           //
1096           // Complete the operation
1097           //
1098           modify($manager) {finishOperation($operation)};
1099       } else {
1100           //
1101           // Just doing this will kick off the LOCKED rule again
1102           //
1103           modify($operation) {};
1104       }
1105     } else {
1106         //
1107         // Its not finished yet (i.e. expecting more Response objects)
1108         //
1109         // Or possibly it is a leftover response that we timed the request out previously
1110         //
1111     }
1112     //
1113     // We are going to retract these objects from memory
1114     //
1115     retract($response);
1116 end
1117
1118 /*
1119 *
1120 * Clean Up any lingering SDNR reponses
1121 *
1122 */
1123 rule "${policyName}.SDNR.RESPONSE.CLEANUP"
1124     when
1125         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1126         $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1127         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
1128     then
1129     
1130     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1131     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1132     logger.debug("{}: {}: orphan SDNR response={}", 
1133                 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1134     //
1135     // Retract it
1136     //
1137     retract($response);
1138 end
1139
1140 /*
1141 *
1142 * This rule responds to SO Response Events
1143 *
1144 */
1145 rule "${policyName}.SO.RESPONSE"
1146     when
1147         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1148         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
1149             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1150         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1151             requestId == $event.getRequestId() )
1152         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1153             onset.getRequestId() == $event.getRequestId() )
1154         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1155             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1156         $lock : TargetLock (requestID == $event.getRequestId())
1157         $response : SoResponseWrapper(requestId.toString() == $event.getRequestId().toString() )
1158     then
1159
1160     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1161     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1162     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1163                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1164                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1165         
1166     // Get the result of the operation
1167     //
1168     PolicyResult policyResult = $operation.onResponse($response);
1169     if (policyResult != null) {
1170         logger.debug("{}: {}: operation finished - result={}", 
1171                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1172                     policyResult);
1173       
1174         //
1175         // This Operation has completed, construct a notification showing our results
1176         //
1177         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1178         notification.setFrom("policy");
1179         notification.setPolicyName(drools.getRule().getName());
1180         notification.setPolicyScope("${policyScope}");
1181         notification.setPolicyVersion("${policyVersion}");
1182         notification.setMessage($operation.getOperationHistory());
1183         notification.setHistory($operation.getHistory());
1184         if (policyResult.equals(PolicyResult.SUCCESS)) {
1185             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1186         } else {
1187             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1188
1189         }
1190         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1191         //
1192         // Ensure the operation is complete
1193         //
1194         if ($operation.isOperationComplete() == true) {
1195             //
1196             // It is complete, remove it from memory
1197             //
1198             retract($operation);
1199             //
1200             // We must also retract the timer object
1201             // NOTE: We could write a Rule to do this
1202             //
1203             retract($opTimer);
1204             //
1205             // Complete the operation
1206             //
1207             modify($manager) {finishOperation($operation)};
1208         } else {
1209             //
1210             // Just doing this will kick off the LOCKED rule again
1211             //
1212             modify($operation) {};
1213         }
1214     } else {
1215         //
1216         // Its not finished yet (i.e. expecting more Response objects)
1217         //
1218         // Or possibly it is a leftover response that we timed the request out previously
1219         //
1220     }
1221     //
1222     // We are going to retract these objects from memory
1223     //
1224     retract($response);
1225
1226 end
1227
1228 /*
1229 *
1230 * This rule responds to VFC Response Events
1231 *
1232 */
1233 rule "${policyName}.VFC.RESPONSE"
1234     when
1235         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1236         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
1237             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1238         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1239             requestId == $event.getRequestId() )
1240         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1241             onset.getRequestId() == $event.getRequestId() )
1242         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1243             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1244         $lock : TargetLock (requestID == $event.getRequestId())
1245         $response : VfcResponse( requestId.toString() == $event.getRequestId().toString() )    
1246     then
1247         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1248         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1249         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1250                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1251                     $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1252
1253         // Get the result of the operation
1254         //
1255         PolicyResult policyResult = $operation.onResponse($response);
1256         if (policyResult != null) {
1257             //
1258             // This Operation has completed, construct a notification showing our results
1259             //
1260             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1261             notification.setFrom("policy");
1262             notification.setPolicyName(drools.getRule().getName());
1263             notification.setPolicyScope("${policyScope}");
1264             notification.setPolicyVersion("${policyVersion}");
1265             notification.setMessage($operation.getOperationHistory());
1266             notification.setHistory($operation.getHistory());
1267             //
1268             // Ensure the operation is complete
1269             //
1270             if ($operation.isOperationComplete() == true) {
1271                 //
1272                 // It is complete, remove it from memory
1273                 //
1274                 retract($operation);
1275                 //
1276                 // We must also retract the timer object
1277                 // NOTE: We could write a Rule to do this
1278                 //
1279                 retract($opTimer);
1280                 //
1281                 // Complete the operation
1282                 //
1283                 modify($manager) {finishOperation($operation)};
1284             } else {
1285                 //
1286                 // Just doing this will kick off the LOCKED rule again
1287                 //
1288                 modify($operation) {};
1289             }
1290         } else {
1291             //
1292             // Its not finished yet (i.e. expecting more Response objects)
1293             //
1294             // Or possibly it is a leftover response that we timed the request out previously
1295             //
1296         }
1297         //
1298         // We are going to retract these objects from memory
1299         //
1300         retract($response);
1301
1302 end
1303
1304 /*
1305 *
1306 * This rule responds to SDNC Response Events
1307 *
1308 */
1309
1310 rule "${policyName}.SDNC.RESPONSE"
1311     when
1312         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1313         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), 
1314             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1315         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1316             requestId == $event.getRequestId() )
1317         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1318             onset.getRequestId() == $event.getRequestId() )
1319         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1320             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1321         $lock : TargetLock (requestID == $event.getRequestId())
1322         $response : SdncResponse( requestId.toString() == $event.getRequestId().toString() )    
1323     then
1324         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1325         logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1326         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", 
1327                     $params.getClosedLoopControlName(), drools.getRule().getName(),
1328                     $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1329
1330         // Get the result of the operation
1331         //
1332         PolicyResult policyResult = $operation.onResponse($response);
1333         if (policyResult != null) {
1334             //
1335             // This Operation has completed, construct a notification showing our results
1336             //
1337             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1338             notification.setFrom("policy");
1339             notification.setPolicyName(drools.getRule().getName());
1340             notification.setPolicyScope("${policyScope}");
1341             notification.setPolicyVersion("${policyVersion}");
1342             notification.setMessage($operation.getOperationHistory());
1343             notification.setHistory($operation.getHistory());
1344             //
1345             // Ensure the operation is complete
1346             //
1347             if ($operation.isOperationComplete()) {
1348                 //
1349                 // It is complete, remove it from memory
1350                 //
1351                 retract($operation);
1352                 //
1353                 // We must also retract the timer object
1354                 // NOTE: We could write a Rule to do this
1355                 //
1356                 retract($opTimer);
1357                 //
1358                 // Complete the operation
1359                 //
1360                 modify($manager) {finishOperation($operation)};
1361             } else {
1362                 //
1363                 // Just doing this will kick off the LOCKED rule again
1364                 //
1365                 modify($operation) {};
1366             }
1367         } else {
1368             //
1369             // Its not finished yet (i.e. expecting more Response objects)
1370             //
1371             // Or possibly it is a leftover response that we timed the request out previously
1372             //
1373         }
1374         //
1375         // We are going to retract these objects from memory
1376         //
1377         retract($response);
1378
1379 end
1380
1381 /*
1382 *
1383 * This manages a single timer.
1384 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1385 *
1386 */
1387 rule "${policyName}.TIMER.FIRED"
1388     timer (expr: $timeout)
1389     when
1390         $timer : ControlLoopTimer($timeout : delay, !expired)
1391     then
1392         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1393         logger.info("This is ${policyName}.TIMER.FIRED");
1394         modify($timer){setExpired(true)};
1395     end
1396
1397 /*
1398 *
1399 * This is the timer that manages the timeout for an individual operation.
1400 *
1401 */
1402 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1403     when
1404         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1405         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1406         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1407             requestId == $event.getRequestId() )
1408         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1409             onset.getRequestId() == $event.getRequestId() )
1410         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1411             requestID == $event.getRequestId().toString(), expired, timerType == "Operation" )
1412         $lock : TargetLock (requestID == $event.getRequestId())
1413     then
1414     
1415     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1416     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1417     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}", 
1418                 $params.getClosedLoopControlName(), drools.getRule().getName(),
1419                 $event, $manager, $operation, $lock, $operation, $opTimer);
1420     
1421     //
1422     // Tell it its timed out
1423     //
1424     $operation.setOperationHasTimedOut();
1425     //
1426     // Create a notification for it ("DB Write - end operation")
1427     //
1428     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1429     notification.setFrom("policy");
1430     notification.setPolicyName(drools.getRule().getName());
1431     notification.setPolicyScope("${policyScope}");
1432     notification.setPolicyVersion("${policyVersion}");
1433     notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1434     notification.setMessage($operation.getOperationHistory());
1435     notification.setHistory($operation.getHistory());
1436     //
1437     // Let interested parties know
1438     //
1439     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1440     //
1441     // Get rid of the timer
1442     //
1443     retract($opTimer);
1444     //
1445     // Ensure the operation is complete
1446     //
1447     if ($operation.isOperationComplete() == true) {
1448         //
1449         // It is complete, remove it from memory
1450         //
1451         retract($operation);
1452         //
1453         // Complete the operation
1454         //
1455         modify($manager) {finishOperation($operation)};
1456     } else {
1457         //
1458         // Just doing this will kick off the LOCKED rule again
1459         //
1460         modify($operation) {};
1461     }
1462 end
1463
1464 /*
1465 *
1466 * This is the timer that manages the overall control loop timeout.
1467 *
1468 */
1469 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1470     when
1471         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1472         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1473         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1474             requestId == $event.getRequestId() )
1475         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1476             requestID == $event.getRequestId().toString(), expired, timerType == "ClosedLoop" )
1477     then
1478     
1479     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1480     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1481
1482     logger.debug("{}: {}: event={}", 
1483               $params.getClosedLoopControlName(), drools.getRule().getName(),
1484               $event);
1485     //
1486     // Tell the Event Manager it has timed out
1487     //
1488     VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1489     if (notification != null) {
1490         notification.setFrom("policy");
1491         notification.setPolicyName(drools.getRule().getName());
1492         notification.setPolicyScope("${policyScope}");
1493         notification.setPolicyVersion("${policyVersion}");
1494         //
1495         // Let interested parties know
1496         //
1497         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1498     }
1499     //
1500     // Retract the event
1501     //
1502     retract($event);
1503 end
1504
1505 /*
1506 *
1507 * This rule cleans up the manager and other objects after an event has
1508 * been retracted.
1509 *
1510 */
1511 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1512     when
1513         $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestId() )
1514         $operations : LinkedList()
1515                         from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, 
1516                             onset.getRequestId() == $requestId ) )
1517         $timers : LinkedList()
1518                         from collect( ControlLoopTimer( closedLoopControlName == $clName, 
1519                             requestID == $requestId.toString() ) )
1520         $locks : LinkedList()
1521                         from collect( TargetLock (requestID == $requestId) )
1522         not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1523     then
1524     
1525     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1526     logger.info("{}: {}", $clName, drools.getRule().getName());
1527
1528     logger.debug("{}: {}: manager={} timers={} operations={}", 
1529               $clName, drools.getRule().getName(),
1530               $manager, $timers.size(), $operations.size());
1531     
1532     //
1533     // Retract EVERYTHING
1534     //
1535     retract($manager);
1536     
1537     for(Object manager: $operations) {
1538         retract((ControlLoopOperationManager) manager);
1539     }
1540     for(Object timer: $timers) {
1541         retract((ControlLoopTimer) timer);
1542     }
1543     for(Object lock: $locks) {
1544         TargetLock tgt = (TargetLock) lock;
1545         //
1546         // Ensure we release the lock
1547         //
1548         PolicyGuard.unlockTarget(tgt);
1549         retract(tgt);
1550     }
1551 end
1552
1553 /*
1554 *
1555 * This rule will clean up any rogue onsets where there is no 
1556 * ControlLoopParams object corresponding to the onset event.
1557 *
1558 */
1559 rule "${policyName}.EVENT.CLEANUP"
1560     when
1561         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1562         not ( Params( getClosedLoopControlName() == $clName) )
1563     then
1564  
1565     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1566     logger.info("{}: {}", $clName, drools.getRule().getName());
1567     logger.debug("{}: {}: orphan onset event={}", 
1568                 $clName, drools.getRule().getName(), $event);
1569
1570     retract($event);
1571 end
1572
1573 /*
1574 * Creates a cleaner for every Params object.
1575 * This has a higher salience so that it is fired before PARAMS.FINISHED in ANY policy.
1576 */
1577 rule "${policyName}.PARAMS.CLEANING"
1578     salience 2
1579     when
1580         $params: Params( )
1581         ParamsInitCleaner( )
1582     then
1583  
1584     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1585     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1586         $params.getControlLoopYaml());
1587         
1588     ParamsCleaner cleaner = new ParamsCleaner();
1589     cleaner.setClosedLoopControlName($params.getClosedLoopControlName());
1590     cleaner.setControlLoopYaml($params.getControlLoopYaml());
1591     insert(cleaner);
1592 end
1593
1594 /*
1595 * Finished creating cleaner objects, so remove the trigger.
1596 * This has a higher salience so that it is fired before processing any events.
1597 */
1598 rule "${policyName}.PARAMS.FINISHED"
1599     salience 1
1600     when
1601         $initCleaner: ParamsInitCleaner( )
1602     then
1603  
1604     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1605     logger.info("{}: {}", $initCleaner.getClosedLoopControlName(), drools.getRule().getName());
1606     
1607     retract($initCleaner);
1608 end
1609
1610 /*
1611 * Identifies Params objects that are still active, removing their associated cleaners.
1612 * This should only leave one active Params object for each policy.
1613 * This has a higher salience so that it is fired before PARAMS.DELETE in ANY policy.
1614 */
1615 rule "${policyName}.PARAMS.ACTIVE"
1616     salience 3
1617     when
1618         $params: Params( getClosedLoopControlName() == "${closedLoopControlName}",
1619                             getControlLoopYaml() == "${controlLoopYaml}" )
1620         $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}",
1621                             getControlLoopYaml() == "${controlLoopYaml}"  )
1622     then
1623  
1624     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1625     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1626         $params.getControlLoopYaml());
1627         
1628     retract($cleaner);
1629 end
1630
1631 /*
1632 * Delete Params objects that are not active (i.e., those that still have an associated
1633 * cleaner object).
1634 * This has a higher salience so that it is fired before PARAMS.CLEANED in ANY policy.
1635 */
1636 rule "${policyName}.PARAMS.DELETE"
1637     salience 2
1638     when
1639         $params: Params( )
1640         $cleaner: ParamsCleaner( getClosedLoopControlName() == $params.getClosedLoopControlName(),
1641                             getControlLoopYaml() == $params.getControlLoopYaml()  )
1642     then
1643  
1644     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1645     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1646         $params.getControlLoopYaml());
1647         
1648     retract($params);
1649 end
1650
1651 /*
1652 * Finished clean-up, so delete the cleaner objects.
1653 * This has a higher salience so that it is fired before processing any events.
1654 */
1655 rule "${policyName}.PARAMS.CLEANED"
1656     salience 1
1657     when
1658         $cleaner: ParamsCleaner( )
1659     then
1660  
1661     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1662     logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(),
1663         $cleaner.getControlLoopYaml());
1664         
1665     retract($cleaner);
1666 end