2  * ============LICENSE_START=======================================================
 
   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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.controlloop;
 
  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;
 
  75 import org.yaml.snakeyaml.Yaml;
 
  76 import org.yaml.snakeyaml.constructor.Constructor;
 
  78 import org.slf4j.LoggerFactory;
 
  79 import org.slf4j.Logger;
 
  81 import java.time.Instant;
 
  82 import java.util.LinkedList;
 
  83 import java.util.Iterator;
 
  84 import java.util.HashSet;
 
  87 import org.onap.policy.drools.system.PolicyEngine;
 
  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.
 
  97   closedLoopControlName : String
 
  98   controlLoopYaml : String
 
 102  * Control Loop Identity
 
 105   closedLoopControlName : String
 
 106   controlLoopYaml : String
 
 110  * Used to clean up Params that no longer have associated rules.
 
 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
 
 119  * This object is to provide support for timeouts
 
 120  * due to a bug in drools' built-in timers
 
 122 declare ControlLoopTimer
 
 123     closedLoopControlName : String
 
 127     //timerType is the type of timer: either "ClosedLoop" or "Operation"
 
 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.
 
 139 rule "${policyName}.SETUP"
 
 142         not( Params( getClosedLoopControlName() == "${closedLoopControlName}", 
 
 143             getControlLoopYaml() == "${controlLoopYaml}" ) )
 
 146     Params params = new Params();
 
 147     params.setClosedLoopControlName("${closedLoopControlName}");
 
 148     params.setControlLoopYaml("${controlLoopYaml}");
 
 151     ParamsCleaner cleaner = new ParamsCleaner();
 
 152     cleaner.setClosedLoopControlName("${closedLoopControlName}");
 
 153     cleaner.setIdentified(false);
 
 154     cleaner.setActive(new HashSet());
 
 157     // Note: globals have bad behavior when persistence is used,
 
 158     //       hence explicitly getting the logger vs using a global
 
 160     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
 161     logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), 
 
 162         params.getControlLoopYaml());
 
 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)
 
 171 rule "${policyName}.EVENT"
 
 173         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
 
 174         $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
 
 175         not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
 
 176             requestID == $event.getRequestId() ) )
 
 179     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
 180     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
 
 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.
 
 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}");
 
 199             // Let interested parties know
 
 201             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 204             // Retract it from memory
 
 207         } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
 
 208             throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
 
 211             // Create an EventManager
 
 213             ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(), 
 
 214                 $event.getRequestId());
 
 216             // Determine if EventManager can actively process the event 
 
 217             // (i.e. syntax, is_closed_loop_disabled checks etc.)
 
 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}");
 
 225             // Are we actively pursuing this event?
 
 227             if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
 
 229                 // Insert Event Manager into memory, this will now kick off processing.
 
 233                 // Let interested parties know
 
 235                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 237                 // Setup the Overall Control Loop timer
 
 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");
 
 250                 // Let interested parties know
 
 252                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 254                 // Retract it from memory
 
 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.
 
 265     } catch (Exception e) {
 
 266         logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
 
 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}");
 
 277         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 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.
 
 291 rule "${policyName}.EVENT.MANAGER"
 
 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 )
 
 301     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
 302     logger.info("{}: {}: event={} manager={} clTimer={}", 
 
 303                 $params.getClosedLoopControlName(), drools.getRule().getName(),
 
 304                 $event, $manager, $clTimer);
 
 308         // Check which event this is.
 
 310         ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
 
 312         // Check what kind of event this is
 
 314         if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
 
 316             // We don't care about subsequent onsets
 
 318             logger.info("{}: {}: subsequent onset", 
 
 319                         $params.getClosedLoopControlName(), drools.getRule().getName());
 
 323         if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
 
 325             // Ignore any bad syntax events
 
 327             logger.warn("{}: {}: syntax error", 
 
 328                         $params.getClosedLoopControlName(), drools.getRule().getName());
 
 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.
 
 337         if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
 
 338             logger.warn("{}: {}: not first onset", 
 
 339                         $params.getClosedLoopControlName(), drools.getRule().getName());
 
 343         logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(), 
 
 344                      drools.getRule().getName(), $event.getTarget());
 
 346         // Now start seeing if we need to process this event
 
 350         // Check if this is a Final Event
 
 352         VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
 
 355         if (notification != null) {
 
 357             // Its final, but are we waiting for abatement?
 
 359             if ($manager.getNumAbatements() > 0) {
 
 360                 logger.info("{}: {}: abatement received for {}.  Closing the control loop", 
 
 361                             $params.getClosedLoopControlName(), drools.getRule().getName(), 
 
 362                             $event.getRequestId());
 
 364                 /// DB Write---end event processing for this RequestId()
 
 365                 $manager.commitAbatement("Event Abated","Closed");
 
 367                 notification.setFrom("policy");
 
 368                 notification.setPolicyName(drools.getRule().getName());
 
 369                 notification.setPolicyScope("${policyScope}");
 
 370                 notification.setPolicyVersion("${policyVersion}");
 
 372                 // In this case, we are done
 
 374                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 378                 TargetLock lock = $manager.unlockCurrentOperation();
 
 380                     logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(), 
 
 381                                  drools.getRule().getName(), lock);
 
 385                 // Retract everything from memory
 
 387                 logger.info("{}: {}: retracting onset, manager, and timer", 
 
 388                             $params.getClosedLoopControlName(), drools.getRule().getName());
 
 390                 retract($manager.getOnsetEvent());
 
 392                 // don't retract manager, etc. - a clean-up rule will do that
 
 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
 
 401                 // Check whether we need to wait for abatement
 
 403                 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
 
 404                   logger.info("{}: {}: waiting for abatement ..", 
 
 405                               $params.getClosedLoopControlName(), drools.getRule().getName());
 
 407                   logger.info("{}: {}: no abatement expect for {}.  Closing the control loop", 
 
 408                               $params.getClosedLoopControlName(), drools.getRule().getName(), 
 
 409                               $event.getRequestId());
 
 411                   notification.setFrom("policy");
 
 412                   notification.setPolicyName(drools.getRule().getName());
 
 413                   notification.setPolicyScope("${policyScope}");
 
 414                   notification.setPolicyVersion("${policyVersion}");
 
 417                   // In this case, we are done
 
 419                   PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 423                   TargetLock lock = $manager.unlockCurrentOperation();
 
 425                       logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(), 
 
 426                                   drools.getRule().getName(), lock);
 
 430                   // Retract everything from memory
 
 432                   logger.info("{}: {}: retracting onset, manager, and timer", 
 
 433                               $params.getClosedLoopControlName(), drools.getRule().getName());
 
 435                   retract($manager.getOnsetEvent());
 
 437                 // don't retract manager, etc. - a clean-up rule will do that
 
 442             // NOT final, so let's ask for the next operation
 
 444             ControlLoopOperationManager operation = $manager.processControlLoop();
 
 445             if (operation != null) {
 
 447               // Let's ask for a lock right away
 
 449               LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
 
 450               logger.info("{}: {}: guard lock acquired={}", 
 
 451                             $params.getClosedLoopControlName(), drools.getRule().getName(), 
 
 453               if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
 
 455                   // insert the operation into memory
 
 459                   // insert operation timeout object
 
 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");
 
 469                   // Insert lock into memory
 
 471                   insert(result.getB());
 
 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}");
 
 484                   PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 488                   // don't retract manager, etc. - a clean-up rule will do that
 
 490                   if (result.getB() != null) {
 
 491                       retract(result.getB());
 
 494               logger.info("{}: {}: starting operation={}", 
 
 495                           $params.getClosedLoopControlName(), drools.getRule().getName(), 
 
 499                 // Probably waiting for abatement
 
 501               logger.info("{}: {}: no operation, probably waiting for abatement", 
 
 502                           $params.getClosedLoopControlName(), drools.getRule().getName());
 
 505     } catch (Exception e) {
 
 506          logger.warn("{}: {}: unexpected", 
 
 507                   $params.getClosedLoopControlName(), 
 
 508                   drools.getRule().getName(), e);
 
 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}");
 
 518          PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 522          // don't retract manager, etc. - a clean-up rule will do that
 
 529 * Guard Permitted, let's send request to the actor.
 
 532 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
 
 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 )
 
 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);    
 
 550     Object request = null;
 
 551     boolean caughtException = false;
 
 554         request = $operation.startOperation($event);
 
 556         if (request != null) {
 
 557           logger.debug("{}: {}: starting operation ..", 
 
 558                        $params.getClosedLoopControlName(), drools.getRule().getName());
 
 560           // Tell interested parties we are performing this Operation
 
 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}");
 
 571           PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 573           switch ($operation.policy.getActor()){
 
 576                   if (request instanceof Request) {
 
 577                       PolicyEngine.manager.deliver("APPC-CL", request);
 
 579                   else if (request instanceof LcmRequestWrapper) {
 
 580                       PolicyEngine.manager.deliver("APPC-LCM-READ", request);
 
 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
 
 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(),
 
 595                   if (request instanceof VFCRequest) {
 
 597                       Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
 
 603                   if (request instanceof SdncRequest) {
 
 605                      Thread t = new Thread(new SdncManager(drools.getWorkingMemory(), (SdncRequest)request));
 
 610                   if (request instanceof PciRequestWrapper) {
 
 611                       PolicyEngine.manager.deliver("SDNR-CL", request);
 
 617           // What happens if its null?
 
 619             logger.warn("{}: {}: unexpected null operation request", 
 
 620                       $params.getClosedLoopControlName(), 
 
 621                       drools.getRule().getName());
 
 622             if ("SO".equals($operation.policy.getActor())) {
 
 625                 modify($manager) {finishOperation($operation)};
 
 627             else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
 
 630                 modify($manager) {finishOperation($operation)};
 
 632             else if ("sdnc".equalsIgnoreCase($operation.policy.getActor())) {
 
 635                 modify($manager) {finishOperation($operation)};
 
 639     } catch (Exception e) {
 
 640         String msg = e.getMessage();
 
 641         logger.warn("{}: {}: operation={}:  AAI failure: {}", 
 
 642                     $params.getClosedLoopControlName(), drools.getRule().getName(),
 
 644         $operation.setOperationHasException(msg);
 
 646         if(request != null) {
 
 648             // Create a notification for it ("DB Write - end operation")
 
 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());
 
 659             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 664         caughtException = true;
 
 667     // Having the modify statement in the catch clause doesn't work for whatever reason
 
 668     if (caughtException) {
 
 669         modify($manager) {finishOperation($operation)};
 
 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.
 
 680 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
 
 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())
 
 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);
 
 697     // Sending notification that we are about to query Guard ("DB write - start operation")
 
 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}");
 
 709     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 712     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard, 
 
 713     // just change guardEnabled to false.
 
 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).
 
 720     // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
 
 721     boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
 
 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(),
 
 733                                                             AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
 
 734                                                             return(resp == null ? null : resp.countVfModules());
 
 739         insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
 
 745 // This rule will be triggered when a thread talking to the XACML Guard inserts a 
 
 746 // guardResponse object into the working memory
 
 748 rule "${policyName}.GUARD.RESPONSE"
 
 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)
 
 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);
 
 769     //we will permit the operation if there was no Guard for it
 
 770     if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
 
 771         $guardResponse.setResult("Permit");
 
 775     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
 
 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}");
 
 787     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 789     if("Permit".equalsIgnoreCase($guardResponse.getResult())){
 
 791         modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
 
 794         //This is the Deny case
 
 795         $operation.startOperation($event);
 
 796         $operation.setOperationHasGuardDeny();
 
 799         modify($manager) {finishOperation($operation)};
 
 802     retract($guardResponse);
 
 808 * This rule responds to APPC Response Events
 
 810 * I would have like to be consistent and write the Response like this:
 
 811 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
 
 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.
 
 817 rule "${policyName}.APPC.RESPONSE"
 
 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() )
 
 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);
 
 838     // Get the result of the operation
 
 840     PolicyResult policyResult = $operation.onResponse($response);
 
 841     if (policyResult != null) {
 
 842         logger.debug("{}: {}: operation finished - result={}", 
 
 843                     $params.getClosedLoopControlName(), drools.getRule().getName(),
 
 846         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
 
 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);
 
 858             // Let interested parties know
 
 860             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 862             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
 
 864             // Let interested parties know
 
 866             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 869         // Ensure the operation is complete
 
 871         if ($operation.isOperationComplete() == true) {
 
 873             // It is complete, remove it from memory
 
 877             // We must also retract the timer object
 
 878             // NOTE: We could write a Rule to do this
 
 882             // Complete the operation
 
 884             modify($manager) {finishOperation($operation)};
 
 887             // Just doing this will kick off the LOCKED rule again
 
 889             modify($operation) {};
 
 893         // Its not finished yet (i.e. expecting more Response objects)
 
 895         // Or possibly it is a leftover response that we timed the request out previously
 
 899     // We are going to retract these objects from memory
 
 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.
 
 912 rule "${policyName}.APPC.RESPONSE.CLEANUP"
 
 914         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
 
 915         $response : Response($id : getCommonHeader().RequestId )
 
 916         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
 
 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);
 
 932 * This rule responds to APPC Response Events using the new LCM interface provided by appc
 
 935 rule "${policyName}.APPC.LCM.RESPONSE"
 
 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() )
 
 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);
 
 957     // Get the result of the operation
 
 959     PolicyResult policyResult = $operation.onResponse($response);
 
 960     if (policyResult != null) {
 
 961       logger.debug("{}: {}: operation finished - result={}", 
 
 962                   $params.getClosedLoopControlName(), drools.getRule().getName(),
 
 966       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
 
 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);
 
 978           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
 
 980       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
 982       // Ensure the operation is complete
 
 984       if ($operation.isOperationComplete() == true) {
 
 986           // It is complete, remove it from memory
 
 990           // We must also retract the timer object
 
 991           // NOTE: We could write a Rule to do this
 
 995           // Complete the operation
 
 997           modify($manager) {finishOperation($operation)};
 
1000           // Just doing this will kick off the LOCKED rule again
 
1002           modify($operation) {};
 
1006         // Its not finished yet (i.e. expecting more Response objects)
 
1008         // Or possibly it is a leftover response that we timed the request out previously
 
1012     // We are going to retract these objects from memory
 
1019 * Clean Up any lingering LCM reponses
 
1022 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
 
1024         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
 
1025         $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
 
1026         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
 
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);
 
1041 * This rule responds to SDNR Response Events using the new interface provided by SDNR
 
1044 rule "${policyName}.SDNR.RESPONSE"
 
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() )
 
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);
 
1066     // Get the result of the operation
 
1068     PolicyResult policyResult = $operation.onResponse($response);
 
1069     if (policyResult != null) {
 
1070       logger.debug("{}: {}: operation finished - result={}", 
 
1071                   $params.getClosedLoopControlName(), drools.getRule().getName(),
 
1075       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
 
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);
 
1087           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
 
1089       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
1091       // Ensure the operation is complete
 
1093       if ($operation.isOperationComplete()) {
 
1095           // It is complete, remove it from memory
 
1097           retract($operation);
 
1099           // We must also retract the timer object
 
1100           // NOTE: We could write a Rule to do this
 
1104           // Complete the operation
 
1106           modify($manager) {finishOperation($operation)};
 
1109           // Just doing this will kick off the LOCKED rule again
 
1111           modify($operation) {};
 
1115         // Its not finished yet (i.e. expecting more Response objects)
 
1117         // Or possibly it is a leftover response that we timed the request out previously
 
1121     // We are going to retract these objects from memory
 
1128 * Clean Up any lingering SDNR reponses
 
1131 rule "${policyName}.SDNR.RESPONSE.CLEANUP"
 
1133         $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
 
1134         $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
 
1135         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) 
 
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);
 
1150 * This rule responds to SO Response Events
 
1153 rule "${policyName}.SO.RESPONSE"
 
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() )
 
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);
 
1174     // Get the result of the operation
 
1176     PolicyResult policyResult = $operation.onResponse($response);
 
1177     if (policyResult != null) {
 
1178         logger.debug("{}: {}: operation finished - result={}", 
 
1179                     $params.getClosedLoopControlName(), drools.getRule().getName(),
 
1183         // This Operation has completed, construct a notification showing our results
 
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);
 
1195             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
 
1198         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
1200         // Ensure the operation is complete
 
1202         if ($operation.isOperationComplete() == true) {
 
1204             // It is complete, remove it from memory
 
1206             retract($operation);
 
1208             // We must also retract the timer object
 
1209             // NOTE: We could write a Rule to do this
 
1213             // Complete the operation
 
1215             modify($manager) {finishOperation($operation)};
 
1218             // Just doing this will kick off the LOCKED rule again
 
1220             modify($operation) {};
 
1224         // Its not finished yet (i.e. expecting more Response objects)
 
1226         // Or possibly it is a leftover response that we timed the request out previously
 
1230     // We are going to retract these objects from memory
 
1238 * This rule responds to VFC Response Events
 
1241 rule "${policyName}.VFC.RESPONSE"
 
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() )    
 
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);
 
1261         // Get the result of the operation
 
1263         PolicyResult policyResult = $operation.onResponse($response);
 
1264         if (policyResult != null) {
 
1266             // This Operation has completed, construct a notification showing our results
 
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());
 
1276             // Ensure the operation is complete
 
1278             if ($operation.isOperationComplete() == true) {
 
1280                 // It is complete, remove it from memory
 
1282                 retract($operation);
 
1284                 // We must also retract the timer object
 
1285                 // NOTE: We could write a Rule to do this
 
1289                 // Complete the operation
 
1291                 modify($manager) {finishOperation($operation)};
 
1294                 // Just doing this will kick off the LOCKED rule again
 
1296                 modify($operation) {};
 
1300             // Its not finished yet (i.e. expecting more Response objects)
 
1302             // Or possibly it is a leftover response that we timed the request out previously
 
1306         // We are going to retract these objects from memory
 
1314 * This rule responds to SDNC Response Events
 
1318 rule "${policyName}.SDNC.RESPONSE"
 
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() )    
 
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);
 
1338         // Get the result of the operation
 
1340         PolicyResult policyResult = $operation.onResponse($response);
 
1341         if (policyResult != null) {
 
1343             // This Operation has completed, construct a notification showing our results
 
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());
 
1353             // Ensure the operation is complete
 
1355             if ($operation.isOperationComplete()) {
 
1357                 // It is complete, remove it from memory
 
1359                 retract($operation);
 
1361                 // We must also retract the timer object
 
1362                 // NOTE: We could write a Rule to do this
 
1366                 // Complete the operation
 
1368                 modify($manager) {finishOperation($operation)};
 
1371                 // Just doing this will kick off the LOCKED rule again
 
1373                 modify($operation) {};
 
1377             // Its not finished yet (i.e. expecting more Response objects)
 
1379             // Or possibly it is a leftover response that we timed the request out previously
 
1383         // We are going to retract these objects from memory
 
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
 
1395 rule "${policyName}.TIMER.FIRED"
 
1396     timer (expr: $timeout)
 
1398         $timer : ControlLoopTimer($timeout : delay, !expired)
 
1400         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1401         logger.info("This is ${policyName}.TIMER.FIRED");
 
1402         modify($timer){setExpired(true)};
 
1407 * This is the timer that manages the timeout for an individual operation.
 
1410 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
 
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())
 
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);
 
1430     // Tell it its timed out
 
1432     $operation.setOperationHasTimedOut();
 
1434     // Create a notification for it ("DB Write - end operation")
 
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());
 
1445     // Let interested parties know
 
1447     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
1449     // Get rid of the timer
 
1453     // Ensure the operation is complete
 
1455     if ($operation.isOperationComplete() == true) {
 
1457         // It is complete, remove it from memory
 
1459         retract($operation);
 
1461         // Complete the operation
 
1463         modify($manager) {finishOperation($operation)};
 
1466         // Just doing this will kick off the LOCKED rule again
 
1468         modify($operation) {};
 
1474 * This is the timer that manages the overall control loop timeout.
 
1477 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
 
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" )
 
1487     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1488     logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
 
1490     logger.debug("{}: {}: event={}", 
 
1491               $params.getClosedLoopControlName(), drools.getRule().getName(),
 
1494     // Tell the Event Manager it has timed out
 
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}");
 
1503         // Let interested parties know
 
1505         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
 
1508     // Retract the event
 
1515 * This rule cleans up the manager and other objects after an event has
 
1519 rule "${policyName}.EVENT.MANAGER.CLEANUP"
 
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 ) )
 
1533     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1534     logger.info("{}: {}", $clName, drools.getRule().getName());
 
1536     logger.debug("{}: {}: manager={} timers={} operations={}", 
 
1537               $clName, drools.getRule().getName(),
 
1538               $manager, $timers.size(), $operations.size());
 
1541     // Retract EVERYTHING
 
1545     for(Object manager: $operations) {
 
1546         retract((ControlLoopOperationManager) manager);
 
1548     for(Object timer: $timers) {
 
1549         retract((ControlLoopTimer) timer);
 
1551     for(Object lock: $locks) {
 
1552         TargetLock tgt = (TargetLock) lock;
 
1554         // Ensure we release the lock
 
1556         PolicyGuard.unlockTarget(tgt);
 
1563 * This rule will clean up any rogue onsets where there is no 
 
1564 * ControlLoopParams object corresponding to the onset event.
 
1567 rule "${policyName}.EVENT.CLEANUP"
 
1569         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
 
1570         not ( Params( getClosedLoopControlName() == $clName) )
 
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);
 
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.
 
1585 rule "${policyName}.PARAMS.ACTIVE"
 
1588         $params: Params( getClosedLoopControlName() == "${closedLoopControlName}",
 
1589                             getControlLoopYaml() == "${controlLoopYaml}" )
 
1590         ParamsCleaner( !identified, $active: active )
 
1593     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1594     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
 
1595         $params.getControlLoopYaml());
 
1597     $active.add($params);
 
1599     // do NOT update anything at this point
 
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.
 
1606 rule "${policyName}.PARAMS.IDENTIFIED"
 
1609         $cleaner: ParamsCleaner( !identified )
 
1612     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1613     logger.info("{}: {}", $cleaner.getClosedLoopControlName(), drools.getRule().getName());
 
1615     $cleaner.setIdentified(true);
 
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.
 
1623 rule "${policyName}.PARAMS.DELETE"
 
1627         ParamsCleaner( identified, !active.contains($params) )
 
1630     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1631     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
 
1632         $params.getControlLoopYaml());
 
1636     // do NOT update anything at this point
 
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.
 
1643 rule "${policyName}.PARAMS.CLEANED"
 
1646         $cleaner: ParamsCleaner( identified )
 
1649     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
 
1650     logger.info("{}: {}", $cleaner.getClosedLoopControlName(), drools.getRule().getName());