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