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