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