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