2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2020 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.actor.so;
 
  23 import java.util.ArrayList;
 
  24 import java.util.List;
 
  26 import java.util.concurrent.CompletableFuture;
 
  27 import java.util.concurrent.TimeUnit;
 
  28 import java.util.function.Function;
 
  29 import javax.ws.rs.core.Response;
 
  31 import org.onap.aai.domain.yang.CloudRegion;
 
  32 import org.onap.aai.domain.yang.GenericVnf;
 
  33 import org.onap.aai.domain.yang.ServiceInstance;
 
  34 import org.onap.aai.domain.yang.Tenant;
 
  35 import org.onap.policy.aai.AaiCqResponse;
 
  36 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
 
  37 import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
 
  38 import org.onap.policy.common.utils.coder.Coder;
 
  39 import org.onap.policy.common.utils.coder.CoderException;
 
  40 import org.onap.policy.common.utils.coder.StandardCoder;
 
  41 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 
  42 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
 
  43 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 
  44 import org.onap.policy.controlloop.policy.PolicyResult;
 
  45 import org.onap.policy.controlloop.policy.Target;
 
  46 import org.onap.policy.so.SoModelInfo;
 
  47 import org.onap.policy.so.SoRequest;
 
  48 import org.onap.policy.so.SoRequestInfo;
 
  49 import org.onap.policy.so.SoRequestParameters;
 
  50 import org.onap.policy.so.SoRequestStatus;
 
  51 import org.onap.policy.so.SoResponse;
 
  52 import org.slf4j.Logger;
 
  53 import org.slf4j.LoggerFactory;
 
  56  * Superclass for SDNC Operators. Note: subclasses should invoke {@link #resetGetCount()}
 
  57  * each time they issue an HTTP request.
 
  59 public abstract class SoOperation extends HttpOperation<SoResponse> {
 
  60     private static final Logger logger = LoggerFactory.getLogger(SoOperation.class);
 
  61     private static final Coder coder = new StandardCoder();
 
  63     public static final String FAILED = "FAILED";
 
  64     public static final String COMPLETE = "COMPLETE";
 
  65     public static final int SO_RESPONSE_CODE = 999;
 
  67     // fields within the policy payload
 
  68     public static final String REQ_PARAM_NM = "requestParameters";
 
  69     public static final String CONFIG_PARAM_NM = "configurationParameters";
 
  72     private final SoOperator operator;
 
  75      * Number of "get" requests issued so far, on the current operation attempt.
 
  82      * Constructs the object.
 
  84      * @param params operation parameters
 
  85      * @param operator operator that created this operation
 
  87     public SoOperation(ControlLoopOperationParams params, SoOperator operator) {
 
  88         super(params, operator, SoResponse.class);
 
  89         this.operator = operator;
 
  93      * Subclasses should invoke this before issuing their first HTTP request.
 
  95     protected void resetGetCount() {
 
 103     protected CompletableFuture<OperationOutcome> startPreprocessorAsync() {
 
 104         return startGuardAsync();
 
 108      * If the response does not indicate that the request has been completed, then sleep a
 
 109      * bit and issue a "get".
 
 112     protected CompletableFuture<OperationOutcome> postProcessResponse(OperationOutcome outcome, String url,
 
 113                     Response rawResponse, SoResponse response) {
 
 115         // see if the request has "completed", whether or not it was successful
 
 116         if (rawResponse.getStatus() == 200) {
 
 117             String requestState = getRequestState(response);
 
 118             if (COMPLETE.equalsIgnoreCase(requestState)) {
 
 119                 return CompletableFuture
 
 120                                 .completedFuture(setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response));
 
 123             if (FAILED.equalsIgnoreCase(requestState)) {
 
 124                 return CompletableFuture
 
 125                                 .completedFuture(setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response));
 
 131         // need a request ID with which to query
 
 132         if (response.getRequestReferences() == null || response.getRequestReferences().getRequestId() == null) {
 
 133             throw new IllegalArgumentException("missing request ID in response");
 
 136         // see if the limit for the number of "gets" has been reached
 
 137         if (getCount++ >= operator.getMaxGets()) {
 
 138             logger.warn("{}: execeeded 'get' limit {} for {}", getFullName(), operator.getMaxGets(),
 
 139                             params.getRequestId());
 
 140             setOutcome(outcome, PolicyResult.FAILURE_TIMEOUT);
 
 141             outcome.setMessage(SO_RESPONSE_CODE + " " + outcome.getMessage());
 
 142             return CompletableFuture.completedFuture(outcome);
 
 145         // sleep and then perform a "get" operation
 
 146         Function<Void, CompletableFuture<OperationOutcome>> doGet = unused -> issueGet(outcome, response);
 
 147         return sleep(getWaitMsGet(), TimeUnit.MILLISECONDS).thenComposeAsync(doGet);
 
 151      * Issues a "get" request to see if the original request is complete yet.
 
 153      * @param outcome outcome to be populated with the response
 
 154      * @param response previous response
 
 155      * @return a future that can be used to cancel the "get" request or await its response
 
 157     private CompletableFuture<OperationOutcome> issueGet(OperationOutcome outcome, SoResponse response) {
 
 158         String path = operator.getPathGet() + response.getRequestReferences().getRequestId();
 
 159         String url = operator.getClient().getBaseUrl() + path;
 
 161         logger.debug("{}: 'get' count {} for {}", getFullName(), getCount, params.getRequestId());
 
 163         logMessage(EventType.OUT, CommInfrastructure.REST, url, null);
 
 165         // TODO should this use "path" or the full "url"?
 
 166         return handleResponse(outcome, url, callback -> operator.getClient().get(callback, path, null));
 
 170      * Gets the request state of a response.
 
 172      * @param response response from which to get the state
 
 173      * @return the request state of the response, or {@code null} if it does not exist
 
 175     protected String getRequestState(SoResponse response) {
 
 176         SoRequest request = response.getRequest();
 
 177         if (request == null) {
 
 181         SoRequestStatus status = request.getRequestStatus();
 
 182         if (status == null) {
 
 186         return status.getRequestState();
 
 190      * Treats everything as a success, so we always go into
 
 191      * {@link #postProcessResponse(OperationOutcome, String, Response, SoResponse)}.
 
 194     protected boolean isSuccess(Response rawResponse, SoResponse response) {
 
 199      * Prepends the message with the http status code.
 
 202     public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, Response rawResponse,
 
 203                     SoResponse response) {
 
 205         // set default result and message
 
 206         setOutcome(outcome, result);
 
 208         outcome.setMessage(rawResponse.getStatus() + " " + outcome.getMessage());
 
 212     protected SoModelInfo prepareSoModelInfo() {
 
 213         Target target = params.getTarget();
 
 214         if (target == null) {
 
 215             throw new IllegalArgumentException("missing Target");
 
 218         if (target.getModelCustomizationId() == null || target.getModelInvariantId() == null
 
 219                         || target.getModelName() == null || target.getModelVersion() == null
 
 220                         || target.getModelVersionId() == null) {
 
 221             throw new IllegalArgumentException("missing VF Module model");
 
 224         SoModelInfo soModelInfo = new SoModelInfo();
 
 225         soModelInfo.setModelCustomizationId(target.getModelCustomizationId());
 
 226         soModelInfo.setModelInvariantId(target.getModelInvariantId());
 
 227         soModelInfo.setModelName(target.getModelName());
 
 228         soModelInfo.setModelVersion(target.getModelVersion());
 
 229         soModelInfo.setModelVersionId(target.getModelVersionId());
 
 230         soModelInfo.setModelType("vfModule");
 
 235      * Construct requestInfo for the SO requestDetails.
 
 237      * @return SO request information
 
 239     protected SoRequestInfo constructRequestInfo() {
 
 240         SoRequestInfo soRequestInfo = new SoRequestInfo();
 
 241         soRequestInfo.setSource("POLICY");
 
 242         soRequestInfo.setSuppressRollback(false);
 
 243         soRequestInfo.setRequestorId("policy");
 
 244         return soRequestInfo;
 
 248      * Builds the request parameters from the policy payload.
 
 250     protected SoRequestParameters buildRequestParameters() {
 
 251         if (params.getPayload() == null) {
 
 255         String json = params.getPayload().get(REQ_PARAM_NM);
 
 261             return coder.decode(json, SoRequestParameters.class);
 
 262         } catch (CoderException e) {
 
 263             throw new IllegalArgumentException("invalid payload value: " + REQ_PARAM_NM);
 
 268      * Builds the configuration parameters from the policy payload.
 
 270     protected List<Map<String, String>> buildConfigurationParameters() {
 
 271         if (params.getPayload() == null) {
 
 275         String json = params.getPayload().get(CONFIG_PARAM_NM);
 
 281             @SuppressWarnings("unchecked")
 
 282             List<Map<String, String>> result = coder.decode(json, ArrayList.class);
 
 284         } catch (CoderException | RuntimeException e) {
 
 285             throw new IllegalArgumentException("invalid payload value: " + CONFIG_PARAM_NM);
 
 290      * These methods extract data from the Custom Query and throw an
 
 291      * IllegalArgumentException if the desired data item is not found.
 
 294     protected GenericVnf getVnfItem(AaiCqResponse aaiCqResponse, SoModelInfo soModelInfo) {
 
 295         GenericVnf vnf = aaiCqResponse.getGenericVnfByVfModuleModelInvariantId(soModelInfo.getModelInvariantId());
 
 297             throw new IllegalArgumentException("missing generic VNF");
 
 303     protected ServiceInstance getServiceInstance(AaiCqResponse aaiCqResponse) {
 
 304         ServiceInstance vnfService = aaiCqResponse.getServiceInstance();
 
 305         if (vnfService == null) {
 
 306             throw new IllegalArgumentException("missing VNF Service Item");
 
 312     protected Tenant getDefaultTenant(AaiCqResponse aaiCqResponse) {
 
 313         Tenant tenant = aaiCqResponse.getDefaultTenant();
 
 314         if (tenant == null) {
 
 315             throw new IllegalArgumentException("missing Tenant Item");
 
 321     protected CloudRegion getDefaultCloudRegion(AaiCqResponse aaiCqResponse) {
 
 322         CloudRegion cloudRegion = aaiCqResponse.getDefaultCloudRegion();
 
 323         if (cloudRegion == null) {
 
 324             throw new IllegalArgumentException("missing Cloud Region");
 
 330     // these may be overridden by junit tests
 
 333      * Gets the wait time, in milliseconds, between "get" requests.
 
 335      * @return the wait time, in milliseconds, between "get" requests
 
 337     public long getWaitMsGet() {
 
 338         return TimeUnit.MILLISECONDS.convert(operator.getWaitSecGet(), TimeUnit.SECONDS);