2  * ============LICENSE_START=======================================================
 
   3  * controlloop event manager
 
   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
 
  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.eventmanager;
 
  23 import java.io.Serializable;
 
  24 import java.io.UnsupportedEncodingException;
 
  25 import java.net.URLDecoder;
 
  26 import java.util.ArrayList;
 
  27 import java.util.Arrays;
 
  28 import java.util.Collection;
 
  29 import java.util.Collections;
 
  30 import java.util.HashMap;
 
  31 import java.util.HashSet;
 
  32 import java.util.LinkedList;
 
  33 import java.util.List;
 
  35 import java.util.NoSuchElementException;
 
  37 import java.util.UUID;
 
  38 import java.util.stream.Collectors;
 
  39 import org.apache.commons.lang3.StringUtils;
 
  40 import org.onap.policy.aai.AaiCqResponse;
 
  41 import org.onap.policy.aai.AaiGetVnfResponse;
 
  42 import org.onap.policy.aai.AaiGetVserverResponse;
 
  43 import org.onap.policy.aai.AaiManager;
 
  44 import org.onap.policy.aai.AaiNqInstanceFilters;
 
  45 import org.onap.policy.aai.AaiNqNamedQuery;
 
  46 import org.onap.policy.aai.AaiNqQueryParameters;
 
  47 import org.onap.policy.aai.AaiNqRequest;
 
  48 import org.onap.policy.aai.AaiNqResponse;
 
  49 import org.onap.policy.aai.AaiNqResponseWrapper;
 
  50 import org.onap.policy.aai.AaiNqVServer;
 
  51 import org.onap.policy.aai.util.AaiException;
 
  52 import org.onap.policy.controlloop.ControlLoopEventStatus;
 
  53 import org.onap.policy.controlloop.ControlLoopException;
 
  54 import org.onap.policy.controlloop.ControlLoopNotificationType;
 
  55 import org.onap.policy.controlloop.ControlLoopOperation;
 
  56 import org.onap.policy.controlloop.VirtualControlLoopEvent;
 
  57 import org.onap.policy.controlloop.VirtualControlLoopNotification;
 
  58 import org.onap.policy.controlloop.policy.FinalResult;
 
  59 import org.onap.policy.controlloop.policy.Policy;
 
  60 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
 
  61 import org.onap.policy.drools.system.PolicyEngineConstants;
 
  62 import org.onap.policy.guard.GuardResult;
 
  63 import org.onap.policy.guard.LockCallback;
 
  64 import org.onap.policy.guard.PolicyGuard;
 
  65 import org.onap.policy.guard.PolicyGuard.LockResult;
 
  66 import org.onap.policy.guard.TargetLock;
 
  67 import org.onap.policy.rest.RestManager;
 
  68 import org.onap.policy.so.util.Serialization;
 
  69 import org.slf4j.Logger;
 
  70 import org.slf4j.LoggerFactory;
 
  72 public class ControlLoopEventManager implements LockCallback, Serializable {
 
  73     public static final String PROV_STATUS_ACTIVE = "ACTIVE";
 
  74     private static final String VM_NAME = "VM_NAME";
 
  75     private static final String VNF_NAME = "VNF_NAME";
 
  76     public static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
 
  77     public static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
 
  78     public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
 
  79     public static final String GENERIC_VNF_IS_CLOSED_LOOP_DISABLED = "generic-vnf.is-closed-loop-disabled";
 
  80     public static final String VSERVER_IS_CLOSED_LOOP_DISABLED = "vserver.is-closed-loop-disabled";
 
  81     public static final String GENERIC_VNF_PROV_STATUS = "generic-vnf.prov-status";
 
  82     public static final String VSERVER_PROV_STATUS = "vserver.prov-status";
 
  84     public static final String AAI_URL = "aai.url";
 
  85     public static final String AAI_USERNAME_PROPERTY = "aai.username";
 
  86     public static final String AAI_PASS_PROPERTY = "aai.password";
 
  88     private static final String QUERY_AAI_ERROR_MSG = "Exception from queryAai: ";
 
  91      * Additional time, in seconds, to add to a "lock" request. This ensures that the lock won't expire right before an
 
  92      * operation completes.
 
  94     private static final int ADDITIONAL_LOCK_SEC = 60;
 
  96     private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
 
  98     private static final long serialVersionUID = -1216568161322872641L;
 
 100     private static final Set<String> VALID_TARGETS;
 
 103         VALID_TARGETS = Collections.unmodifiableSet(new HashSet<>(
 
 104                         Arrays.asList(VM_NAME, VNF_NAME, VSERVER_VSERVER_NAME,
 
 105                                         GENERIC_VNF_VNF_ID, GENERIC_VNF_VNF_NAME)
 
 106                         .stream().map(String::toLowerCase).collect(Collectors.toList())));
 
 109     public final String closedLoopControlName;
 
 110     private final UUID requestId;
 
 112     private String controlLoopResult;
 
 113     private ControlLoopProcessor processor = null;
 
 114     private VirtualControlLoopEvent onset;
 
 115     private Integer numOnsets = 0;
 
 116     private Integer numAbatements = 0;
 
 117     private VirtualControlLoopEvent abatement;
 
 118     private FinalResult controlLoopTimedOut = null;
 
 120     private boolean isActivated = false;
 
 121     private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
 
 122     private ControlLoopOperationManager currentOperation = null;
 
 123     private ControlLoopOperationManager lastOperationManager = null;
 
 124     private transient TargetLock targetLock = null;
 
 125     private AaiGetVnfResponse vnfResponse = null;
 
 126     private AaiGetVserverResponse vserverResponse = null;
 
 127     private boolean useTargetLock = true;
 
 130      * Wrapper for AAI vserver named-query response. This is initialized in a lazy fashion.
 
 132     private AaiNqResponseWrapper nqVserverResponse = null;
 
 134     private static Collection<String> requiredAAIKeys = new ArrayList<>();
 
 137         requiredAAIKeys.add("AICVServerSelfLink");
 
 138         requiredAAIKeys.add("AICIdentity");
 
 139         requiredAAIKeys.add("is_closed_loop_disabled");
 
 140         requiredAAIKeys.add(VM_NAME);
 
 143     public ControlLoopEventManager(String closedLoopControlName, UUID requestId) {
 
 144         this.closedLoopControlName = closedLoopControlName;
 
 145         this.requestId = requestId;
 
 148     public String getClosedLoopControlName() {
 
 149         return closedLoopControlName;
 
 152     public String getControlLoopResult() {
 
 153         return controlLoopResult;
 
 156     public void setControlLoopResult(String controlLoopResult) {
 
 157         this.controlLoopResult = controlLoopResult;
 
 160     public Integer getNumOnsets() {
 
 164     public void setNumOnsets(Integer numOnsets) {
 
 165         this.numOnsets = numOnsets;
 
 168     public Integer getNumAbatements() {
 
 169         return numAbatements;
 
 172     public void setNumAbatements(Integer numAbatements) {
 
 173         this.numAbatements = numAbatements;
 
 176     public boolean isActivated() {
 
 180     public void setActivated(boolean isActivated) {
 
 181         this.isActivated = isActivated;
 
 184     public boolean useTargetLock() {
 
 185         return useTargetLock();
 
 188     public void setUseTargetLock(boolean useTargetLock) {
 
 189         this.useTargetLock = useTargetLock;
 
 192     public VirtualControlLoopEvent getOnsetEvent() {
 
 196     public VirtualControlLoopEvent getAbatementEvent() {
 
 197         return this.abatement;
 
 200     public ControlLoopProcessor getProcessor() {
 
 201         return this.processor;
 
 204     public UUID getRequestId() {
 
 209      * Activate a control loop event.
 
 211      * @param event the event
 
 212      * @return the VirtualControlLoopNotification
 
 214     public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
 
 215         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
 
 218             // This method should ONLY be called ONCE
 
 220             if (this.isActivated) {
 
 221                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
 
 224             // Syntax check the event
 
 226             checkEventSyntax(event);
 
 229             // At this point we are good to go with this event
 
 234             notification.setNotification(ControlLoopNotificationType.ACTIVE);
 
 236             // Set ourselves as active
 
 238             this.isActivated = true;
 
 239         } catch (ControlLoopException e) {
 
 240             logger.error("{}: activate by event threw: ", this, e);
 
 241             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 242             notification.setMessage(e.getMessage());
 
 248      * Activate a control loop event.
 
 250      * @param yamlSpecification the yaml specification
 
 251      * @param event the event
 
 252      * @return the VirtualControlLoopNotification
 
 254     public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
 
 255         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
 
 258             // This method should ONLY be called ONCE
 
 260             if (this.isActivated) {
 
 261                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
 
 264             // Syntax check the event
 
 266             checkEventSyntax(event);
 
 271             if (yamlSpecification == null || yamlSpecification.length() < 1) {
 
 272                 throw new ControlLoopException("yaml specification is null or 0 length");
 
 274         } catch (ControlLoopException e) {
 
 275             logger.error("{}: activate by YAML specification and event threw: ", this, e);
 
 276             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 277             notification.setMessage(e.getMessage());
 
 281         String decodedYaml = null;
 
 283             decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
 
 284             if (decodedYaml != null && decodedYaml.length() > 0) {
 
 285                 yamlSpecification = decodedYaml;
 
 287         } catch (UnsupportedEncodingException e) {
 
 288             logger.error("{}: YAML decode in activate by YAML specification and event threw: ", this, e);
 
 289             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 290             notification.setMessage(e.getMessage());
 
 296             // Parse the YAML specification
 
 298             this.processor = new ControlLoopProcessor(yamlSpecification);
 
 300             // At this point we are good to go with this event
 
 307             notification.setNotification(ControlLoopNotificationType.ACTIVE);
 
 309             // Set ourselves as active
 
 311             this.isActivated = true;
 
 312         } catch (ControlLoopException e) {
 
 313             logger.error("{}: activate by YAML specification and event threw: ", this, e);
 
 314             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 315             notification.setMessage(e.getMessage());
 
 321      * Check if the control loop is final.
 
 323      * @return a VirtualControlLoopNotification if the control loop is final, otherwise <code>null</code> is returned
 
 324      * @throws ControlLoopException if an error occurs
 
 326     public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
 
 327         validateFinalControlLoop();
 
 329         // Ok, start creating the notification
 
 331         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
 
 333         // Check if the overall control loop has timed out
 
 335         if (this.isControlLoopTimedOut()) {
 
 337             // Yes we have timed out
 
 339             notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 340             notification.setMessage("Control Loop timed out");
 
 341             notification.getHistory().addAll(this.controlLoopHistory);
 
 345         // Check if the current policy is Final
 
 347         FinalResult result = this.processor.checkIsCurrentPolicyFinal();
 
 348         if (result == null) {
 
 350             // we are not at a final result
 
 356             case FINAL_FAILURE_EXCEPTION:
 
 357                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 358                 notification.setMessage("Exception in processing closed loop");
 
 361             case FINAL_FAILURE_RETRIES:
 
 362             case FINAL_FAILURE_TIMEOUT:
 
 363             case FINAL_FAILURE_GUARD:
 
 364                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 367                 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
 
 370                 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
 
 376         // Be sure to add all the history
 
 378         notification.getHistory().addAll(this.controlLoopHistory);
 
 382     private void validateFinalControlLoop() throws ControlLoopException {
 
 384         // Check if they activated us
 
 386         if (!this.isActivated) {
 
 387             throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
 
 390         // Make sure we are expecting this call.
 
 392         if (this.onset == null) {
 
 393             throw new ControlLoopException("No onset event for ControlLoopEventManager.");
 
 398      * Process the control loop.
 
 400      * @return a ControlLoopOperationManager
 
 401      * @throws ControlLoopException if an error occurs
 
 403     public ControlLoopOperationManager processControlLoop() throws ControlLoopException {
 
 404         validateFinalControlLoop();
 
 406         // Is there a current operation?
 
 408         if (this.currentOperation != null) {
 
 410             // Throw an exception, or simply return the current operation?
 
 412             throw new ControlLoopException("Already working an Operation, do not call this method.");
 
 415         // Ensure we are not FINAL
 
 417         VirtualControlLoopNotification notification = this.isControlLoopFinal();
 
 418         if (notification != null) {
 
 420             // This is weird, we require them to call the isControlLoopFinal() method first
 
 422             // We should really abstract this and avoid throwing an exception, because it really
 
 423             // isn't an exception.
 
 425             throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
 
 428         // Not final so get the policy that needs to be worked on.
 
 430         Policy policy = this.processor.getCurrentPolicy();
 
 431         if (policy == null) {
 
 432             throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
 
 435         // And setup an operation
 
 437         this.lastOperationManager = this.currentOperation;
 
 438         this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
 
 442         return this.currentOperation;
 
 446      * Finish an operation.
 
 448      * @param operation the operation
 
 450     public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
 
 452         // Verify we have a current operation
 
 454         if (this.currentOperation != null) {
 
 456             // Validate they are finishing the current operation
 
 457             // PLD - this is simply comparing the policy. Do we want to equals the whole object?
 
 459             if (this.currentOperation.policy.equals(operation.policy)) {
 
 460                 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(),
 
 461                         this.currentOperation.getOperationResult());
 
 465                 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
 
 467                 // Move to the next Policy
 
 469                 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
 
 471                 // Just null this out
 
 473                 this.lastOperationManager = this.currentOperation;
 
 474                 this.currentOperation = null;
 
 476                 // TODO: Release our lock
 
 480             logger.debug("Cannot finish current operation {} does not match given operation {}",
 
 481                     this.currentOperation.policy, operation.policy);
 
 484         throw new ControlLoopException("No operation to finish.");
 
 488      * Obtain a lock for the current operation.
 
 490      * @return the lock result
 
 491      * @throws ControlLoopException if an error occurs
 
 493     public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
 
 497         if (this.currentOperation == null) {
 
 498             throw new ControlLoopException("Do not have a current operation.");
 
 501         // Not using target locks? Create and return a lock w/o actually locking.
 
 503         if (!this.useTargetLock) {
 
 504             TargetLock lock = PolicyGuard.createTargetLock(this.currentOperation.policy.getTarget().getType(),
 
 505                     this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this);
 
 506             this.targetLock = lock;
 
 507             return LockResult.createLockResult(GuardResult.LOCK_ACQUIRED, lock);
 
 510         // Have we acquired it already?
 
 512         if (this.targetLock != null) {
 
 514             // TODO: Make sure the current lock is for the same target.
 
 515             // Currently, it should be. But in the future it may not.
 
 517             GuardResult result = PolicyGuard.lockTarget(targetLock,
 
 518                     this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
 
 519             return new LockResult<>(result, this.targetLock);
 
 524             LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
 
 525                     this.currentOperation.policy.getTarget().getType(), this.currentOperation.getTargetEntity(),
 
 526                     this.onset.getRequestId(), this, this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
 
 530             if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
 
 532                 // Yes, let's save it
 
 534                 this.targetLock = lockResult.getB();
 
 541      * Release the lock for the current operation.
 
 543      * @return the target lock
 
 545     public synchronized TargetLock unlockCurrentOperation() {
 
 546         if (this.targetLock == null) {
 
 550         TargetLock returnLock = this.targetLock;
 
 551         this.targetLock = null;
 
 553         // if using target locking unlock before returning
 
 555         if (this.useTargetLock) {
 
 556             PolicyGuard.unlockTarget(returnLock);
 
 559         // always return the old target lock so rules can retract it
 
 563     public enum NewEventStatus {
 
 564         FIRST_ONSET, SUBSEQUENT_ONSET, FIRST_ABATEMENT, SUBSEQUENT_ABATEMENT, SYNTAX_ERROR;
 
 568      * An event onset/abatement.
 
 570      * @param event the event
 
 572      * @throws AaiException if an error occurs retrieving information from A&AI
 
 574     public NewEventStatus onNewEvent(VirtualControlLoopEvent event) throws AaiException {
 
 576             this.checkEventSyntax(event);
 
 577             if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ONSET) {
 
 579                 // Check if this is our original ONSET
 
 581                 if (event.equals(this.onset)) {
 
 583                     // Query A&AI if needed
 
 590                     return NewEventStatus.FIRST_ONSET;
 
 593                 // Log that we got an onset
 
 596                 return NewEventStatus.SUBSEQUENT_ONSET;
 
 597             } else if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
 
 599                 // Have we already got an abatement?
 
 601                 if (this.abatement == null) {
 
 605                     this.abatement = event;
 
 607                     // Keep track that we received another
 
 609                     this.numAbatements++;
 
 613                     return NewEventStatus.FIRST_ABATEMENT;
 
 616                     // Keep track that we received another
 
 618                     this.numAbatements++;
 
 622                     return NewEventStatus.SUBSEQUENT_ABATEMENT;
 
 625         } catch (ControlLoopException e) {
 
 626             logger.error("{}: onNewEvent threw: ", this, e);
 
 628         return NewEventStatus.SYNTAX_ERROR;
 
 633      * Commit the abatement to the history database.
 
 635      * @param message the abatement message
 
 636      * @param outcome the abatement outcome
 
 638     public void commitAbatement(String message, String outcome) {
 
 639         if (this.lastOperationManager == null) {
 
 640             logger.error("{}: commitAbatement: no operation manager", this);
 
 644             this.lastOperationManager.commitAbatement(message, outcome);
 
 645         } catch (NoSuchElementException e) {
 
 646             logger.error("{}: commitAbatement threw an exception ", this, e);
 
 652      * Set the control loop time out.
 
 654      * @return a VirtualControlLoopNotification
 
 656     public VirtualControlLoopNotification setControlLoopTimedOut() {
 
 657         this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
 
 658         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
 
 659         notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 660         notification.setMessage("Control Loop timed out");
 
 661         notification.getHistory().addAll(this.controlLoopHistory);
 
 665     public boolean isControlLoopTimedOut() {
 
 666         return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
 
 670      * Get the control loop timeout.
 
 672      * @param defaultTimeout the default timeout
 
 673      * @return the timeout
 
 675     public int getControlLoopTimeout(Integer defaultTimeout) {
 
 676         if (this.processor != null && this.processor.getControlLoop() != null) {
 
 677             Integer timeout = this.processor.getControlLoop().getTimeout();
 
 678             if (timeout != null && timeout > 0) {
 
 682         if (defaultTimeout != null) {
 
 683             return defaultTimeout;
 
 688     public AaiGetVnfResponse getVnfResponse() {
 
 692     public AaiGetVserverResponse getVserverResponse() {
 
 693         return vserverResponse;
 
 697      * Check an event syntax.
 
 699      * @param event the event syntax
 
 700      * @throws ControlLoopException if an error occurs
 
 702     public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
 
 703         validateStatus(event);
 
 704         if (StringUtils.isBlank(event.getClosedLoopControlName())) {
 
 705             throw new ControlLoopException("No control loop name");
 
 707         if (event.getRequestId() == null) {
 
 708             throw new ControlLoopException("No request ID");
 
 710         if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
 
 713         if (StringUtils.isBlank(event.getTarget())) {
 
 714             throw new ControlLoopException("No target field");
 
 715         } else if (!VALID_TARGETS.contains(event.getTarget().toLowerCase())) {
 
 716             throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
 
 718         validateAaiData(event);
 
 721     private void validateStatus(VirtualControlLoopEvent event) throws ControlLoopException {
 
 722         if (event.getClosedLoopEventStatus() == null
 
 723                 || (event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET
 
 724                         && event.getClosedLoopEventStatus() != ControlLoopEventStatus.ABATED)) {
 
 725             throw new ControlLoopException("Invalid value in closedLoopEventStatus");
 
 729     private void validateAaiData(VirtualControlLoopEvent event) throws ControlLoopException {
 
 730         if (event.getAai() == null) {
 
 731             throw new ControlLoopException("AAI is null");
 
 733         if (event.getAai().get(GENERIC_VNF_VNF_ID) == null && event.getAai().get(VSERVER_VSERVER_NAME) == null
 
 734                 && event.getAai().get(GENERIC_VNF_VNF_NAME) == null) {
 
 735             throw new ControlLoopException(
 
 736                     "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
 
 741      * Query A&AI for an event.
 
 743      * @param event the event
 
 744      * @throws AaiException if an error occurs retrieving information from A&AI
 
 746     public void queryAai(VirtualControlLoopEvent event) throws AaiException {
 
 748         Map<String, String> aai = event.getAai();
 
 750         if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
 
 752             if (isClosedLoopDisabled(event)) {
 
 753                 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
 
 756             if (isProvStatusInactive(event)) {
 
 757                 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
 
 760             // no need to query, as we already have the data
 
 764         if (vnfResponse != null || vserverResponse != null) {
 
 765             // query has already been performed
 
 770             if (aai.containsKey(GENERIC_VNF_VNF_ID) || aai.containsKey(GENERIC_VNF_VNF_NAME)) {
 
 771                 vnfResponse = getAaiVnfInfo(event);
 
 772                 processVnfResponse(vnfResponse, aai.containsKey(GENERIC_VNF_VNF_ID));
 
 773             } else if (aai.containsKey(VSERVER_VSERVER_NAME)) {
 
 774                 vserverResponse = getAaiVserverInfo(event);
 
 775                 processVServerResponse(vserverResponse);
 
 777         } catch (AaiException e) {
 
 778             logger.error(QUERY_AAI_ERROR_MSG, e);
 
 780         } catch (Exception e) {
 
 781             logger.error(QUERY_AAI_ERROR_MSG, e);
 
 782             throw new AaiException(QUERY_AAI_ERROR_MSG + e.toString());
 
 787      * Process a response from A&AI for a VNF.
 
 789      * @param aaiResponse the response from A&AI
 
 790      * @param queryByVnfId <code>true</code> if the query was based on vnf-id, <code>false</code> if the query was based
 
 792      * @throws AaiException if an error occurs processing the response
 
 794     private static void processVnfResponse(AaiGetVnfResponse aaiResponse, boolean queryByVnfId) throws AaiException {
 
 795         String queryTypeString = (queryByVnfId ? "vnf-id" : "vnf-name");
 
 797         if (aaiResponse == null) {
 
 798             throw new AaiException("AAI Response is null (query by " + queryTypeString + ")");
 
 800         if (aaiResponse.getRequestError() != null) {
 
 801             throw new AaiException("AAI Responded with a request error (query by " + queryTypeString + ")");
 
 804         if (aaiResponse.getIsClosedLoopDisabled()) {
 
 805             throw new AaiException("is-closed-loop-disabled is set to true (query by " + queryTypeString + ")");
 
 808         if (!PROV_STATUS_ACTIVE.equals(aaiResponse.getProvStatus())) {
 
 809             throw new AaiException("prov-status is not ACTIVE (query by " + queryTypeString + ")");
 
 814      * Process a response from A&AI for a VServer.
 
 816      * @param aaiResponse the response from A&AI
 
 817      * @throws AaiException if an error occurs processing the response
 
 819     private static void processVServerResponse(AaiGetVserverResponse aaiResponse) throws AaiException {
 
 820         if (aaiResponse == null) {
 
 821             throw new AaiException("AAI Response is null (query by vserver-name)");
 
 823         if (aaiResponse.getRequestError() != null) {
 
 824             throw new AaiException("AAI Responded with a request error (query by vserver-name)");
 
 827         List<AaiNqVServer> lst = aaiResponse.getVserver();
 
 832         AaiNqVServer svr = lst.get(0);
 
 833         if (svr.getIsClosedLoopDisabled()) {
 
 834             throw new AaiException("is-closed-loop-disabled is set to true (query by vserver-name)");
 
 837         if (!PROV_STATUS_ACTIVE.equals(svr.getProvStatus())) {
 
 838             throw new AaiException("prov-status is not ACTIVE (query by vserver-name)");
 
 843      * Is closed loop disabled for an event.
 
 845      * @param event the event
 
 846      * @return <code>true</code> if the control loop is disabled, <code>false</code> otherwise
 
 848     public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
 
 849         Map<String, String> aai = event.getAai();
 
 850         return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
 
 851                 || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)));
 
 855      * Does provisioning status, for an event, have a value other than ACTIVE.
 
 857      * @param event the event
 
 858      * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null}, {@code false} otherwise
 
 860     protected static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
 
 861         Map<String, String> aai = event.getAai();
 
 862         return (!PROV_STATUS_ACTIVE.equals(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
 
 863                 || !PROV_STATUS_ACTIVE.equals(aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
 
 867      * Determines the boolean value represented by the given AAI field value.
 
 869      * @param aaiValue value to be examined
 
 870      * @return the boolean value represented by the field value, or {@code false} if the value is {@code null}
 
 872     protected static boolean isAaiTrue(String aaiValue) {
 
 873         return ("true".equalsIgnoreCase(aaiValue) || "T".equalsIgnoreCase(aaiValue) || "yes".equalsIgnoreCase(aaiValue)
 
 874                 || "Y".equalsIgnoreCase(aaiValue));
 
 878      * Get the A&AI VService information for an event.
 
 880      * @param event the event
 
 881      * @return a AaiGetVserverResponse
 
 882      * @throws ControlLoopException if an error occurs
 
 884     public static AaiGetVserverResponse getAaiVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
 
 885         UUID requestId = event.getRequestId();
 
 886         AaiGetVserverResponse response = null;
 
 887         String vserverName = event.getAai().get(VSERVER_VSERVER_NAME);
 
 890             if (vserverName != null) {
 
 891                 String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
 
 892                 String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
 
 893                 String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
 
 894                 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
 
 895                 String url = aaiHostUrl + aaiGetQueryByVserver;
 
 896                 logger.info("AAI Host URL by VServer: {}", url);
 
 897                 response = new AaiManager(new RestManager()).getQueryByVserverName(url, aaiUser, aaiPassword, requestId,
 
 900         } catch (Exception e) {
 
 901             logger.error("getAaiVserverInfo exception: ", e);
 
 902             throw new ControlLoopException("Exception in getAaiVserverInfo: ", e);
 
 909      * Get A&AI VNF information for an event.
 
 911      * @param event the event
 
 912      * @return a AaiGetVnfResponse
 
 913      * @throws ControlLoopException if an error occurs
 
 915     public static AaiGetVnfResponse getAaiVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
 
 916         UUID requestId = event.getRequestId();
 
 917         AaiGetVnfResponse response = null;
 
 918         String vnfName = event.getAai().get(GENERIC_VNF_VNF_NAME);
 
 919         String vnfId = event.getAai().get(GENERIC_VNF_VNF_ID);
 
 921         String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
 
 922         String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
 
 923         String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
 
 926             if (vnfName != null) {
 
 927                 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
 
 928                 String url = aaiHostUrl + aaiGetQueryByVnfName;
 
 929                 logger.info("AAI Host URL by VNF name: {}", url);
 
 930                 response = new AaiManager(new RestManager()).getQueryByVnfName(url, aaiUser, aaiPassword, requestId,
 
 932             } else if (vnfId != null) {
 
 933                 String aaiGetQueryByVnfId = "/aai/v11/network/generic-vnfs/generic-vnf/";
 
 934                 String url = aaiHostUrl + aaiGetQueryByVnfId;
 
 935                 logger.info("AAI Host URL by VNF ID: {}", url);
 
 937                         new AaiManager(new RestManager()).getQueryByVnfId(url, aaiUser, aaiPassword, requestId, vnfId);
 
 939         } catch (Exception e) {
 
 940             logger.error("getAaiVnfInfo exception: ", e);
 
 941             throw new ControlLoopException("Exception in getAaiVnfInfo: ", e);
 
 948      * Gets the output from the AAI vserver named-query, using the cache, if appropriate.
 
 950      * @return output from the AAI vserver named-query
 
 952     public AaiNqResponseWrapper getNqVserverFromAai() {
 
 953         if (nqVserverResponse != null) {
 
 955             return nqVserverResponse;
 
 958         String vserverName = onset.getAai().get(VSERVER_VSERVER_NAME);
 
 959         if (vserverName == null) {
 
 960             logger.warn("Missing vserver-name for AAI request {}", onset.getRequestId());
 
 963         AaiNqRequest aaiNqRequest = getAaiNqRequest(vserverName);
 
 965         if (logger.isDebugEnabled()) {
 
 966             logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
 
 969         AaiNqResponse aaiNqResponse = new AaiManager(new RestManager()).postQuery(getPeManagerEnvProperty(AAI_URL),
 
 970                 getPeManagerEnvProperty(AAI_USERNAME_PROPERTY), getPeManagerEnvProperty(AAI_PASS_PROPERTY),
 
 971                 aaiNqRequest, onset.getRequestId());
 
 973         // Check AAI response
 
 974         if (aaiNqResponse == null) {
 
 975             logger.warn("No response received from AAI for request {}", aaiNqRequest);
 
 979         // Create AAINQResponseWrapper
 
 980         nqVserverResponse = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
 
 982         if (logger.isDebugEnabled()) {
 
 983             logger.debug("AAI Named Query Response: ");
 
 984             logger.debug(Serialization.gsonPretty.toJson(nqVserverResponse.getAaiNqResponse()));
 
 987         return nqVserverResponse;
 
 991      * Gets an AAI Named Query Request object.
 
 993      * @param vserverName vserver name.
 
 994      * @return the AAI Named Query Request object.
 
 996     public static AaiNqRequest getAaiNqRequest(String vserverName) {
 
 997         // create AAI named-query request with UUID started with ""
 
 998         AaiNqRequest aaiNqRequest = new AaiNqRequest();
 
 999         AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
 
1000         AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
 
1001         final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
 
1004         aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
 
1005         aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
 
1006         aaiNqRequest.setQueryParameters(aaiNqQueryParam);
 
1010         Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
 
1011         Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
 
1012         aaiNqInstanceFilterMapItem.put("vserver-name", vserverName);
 
1013         aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
 
1014         aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
 
1015         aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
 
1016         return aaiNqRequest;
 
1020      * This method reads and validates environmental properties coming from the policy engine. Null properties cause an
 
1021      * {@link IllegalArgumentException} runtime exception to be thrown
 
1023      * @param enginePropertyName the name of the parameter to retrieve
 
1024      * @return the property value
 
1026     private static String getPeManagerEnvProperty(String enginePropertyName) {
 
1027         String enginePropertyValue = PolicyEngineConstants.getManager().getEnvironmentProperty(enginePropertyName);
 
1028         if (enginePropertyValue == null) {
 
1029             throw new IllegalArgumentException("The value of policy engine manager environment property \""
 
1030                     + enginePropertyName + "\" may not be null");
 
1032         return enginePropertyValue;
 
1036     public boolean isActive() {
 
1042     public boolean releaseLock() {
 
1048     public String toString() {
 
1049         return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestId=" + requestId
 
1050                 + ", processor=" + processor + ", onset=" + (onset != null ? onset.getRequestId() : "null")
 
1051                 + ", numOnsets=" + numOnsets + ", numAbatements=" + numAbatements + ", isActivated=" + isActivated
 
1052                 + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";
 
1056      * This function calls Aai Custom Query and responds with the AaiCqResponse.
 
1058      * @param event input event
 
1059      * @return AaiCqResponse Response from Aai for custom query
 
1060      * @throws AaiException if error occurs
 
1062     public AaiCqResponse getCqResponse(VirtualControlLoopEvent event) throws AaiException {
 
1064         Map<String, String> aai = event.getAai();
 
1066         if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
 
1068             if (isClosedLoopDisabled(event)) {
 
1069                 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
 
1072             if (isProvStatusInactive(event)) {
 
1073                 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
 
1077         if (!aai.containsKey(VSERVER_VSERVER_NAME)) {
 
1078             throw new AaiException("Vserver name is missing");
 
1081         UUID reqId = event.getRequestId();
 
1082         AaiCqResponse response = null;
 
1083         String vserverId = event.getAai().get(VSERVER_VSERVER_NAME);
 
1085         String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
 
1086         String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
 
1087         String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
 
1089         response = new AaiManager(new RestManager()).getCustomQueryResponse(aaiHostUrl, aaiUser, aaiPassword, reqId,