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