X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=models-interactions%2Fmodel-actors%2Factor.so%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Fpolicy%2Fcontrolloop%2Factor%2Fso%2FSoOperation.java;h=8f0dda3d2b67272064f568b14cd572ecf6e3a682;hb=68a60a45f27287a4a523c82ef466cbeec655f641;hp=86b91017603e54113f27d3dbaf4e1dd2f302de0d;hpb=88fedd4d3edbb581eabe20074a65c32b635fc3b2;p=policy%2Fmodels.git diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java index 86b910176..8f0dda3d2 100644 --- a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java @@ -20,32 +20,35 @@ package org.onap.policy.controlloop.actor.so; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import java.util.function.Function; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import lombok.Getter; import org.onap.aai.domain.yang.CloudRegion; import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ModelVer; import org.onap.aai.domain.yang.ServiceInstance; import org.onap.aai.domain.yang.Tenant; import org.onap.policy.aai.AaiConstants; import org.onap.policy.aai.AaiCqResponse; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; +import org.onap.policy.common.gson.GsonMessageBodyHandler; import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.coder.StandardCoderObject; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.OperationProperties; import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; -import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpPollingConfig; import org.onap.policy.controlloop.policy.PolicyResult; import org.onap.policy.controlloop.policy.Target; import org.onap.policy.so.SoCloudConfiguration; @@ -55,16 +58,14 @@ import org.onap.policy.so.SoRequestInfo; import org.onap.policy.so.SoRequestParameters; import org.onap.policy.so.SoRequestStatus; import org.onap.policy.so.SoResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.onap.policy.so.util.SoLocalDateTimeTypeAdapter; /** - * Superclass for SDNC Operators. Note: subclasses should invoke {@link #resetGetCount()} + * Superclass for SDNC Operators. Note: subclasses should invoke {@link #resetPollCount()} * each time they issue an HTTP request. */ public abstract class SoOperation extends HttpOperation { - private static final Logger logger = LoggerFactory.getLogger(SoOperation.class); - private static final Coder coder = new StandardCoder(); + private static final Coder coder = new SoCoder(); public static final String PAYLOAD_KEY_VF_COUNT = "vfCount"; public static final String FAILED = "FAILED"; @@ -75,8 +76,6 @@ public abstract class SoOperation extends HttpOperation { public static final String REQ_PARAM_NM = "requestParameters"; public static final String CONFIG_PARAM_NM = "configurationParameters"; - private final SoConfig config; - // values extracted from the parameter Target private final String modelCustomizationId; private final String modelInvariantId; @@ -84,22 +83,18 @@ public abstract class SoOperation extends HttpOperation { private final String vfCountKey; - /** - * Number of "get" requests issued so far, on the current operation attempt. - */ - @Getter - private int getCount; - /** * Constructs the object. * * @param params operation parameters * @param config configuration for this operation + * @param propertyNames names of properties required by this operation */ - public SoOperation(ControlLoopOperationParams params, HttpConfig config) { - super(params, config, SoResponse.class); - this.config = (SoConfig) config; + public SoOperation(ControlLoopOperationParams params, HttpPollingConfig config, List propertyNames) { + super(params, config, SoResponse.class, propertyNames); + + setUsePolling(); verifyNotNull("Target information", params.getTarget()); @@ -111,11 +106,10 @@ public abstract class SoOperation extends HttpOperation { + modelVersionId + "]"; } - /** - * Subclasses should invoke this before issuing their first HTTP request. - */ - protected void resetGetCount() { - getCount = 0; + @Override + protected void resetPollCount() { + super.resetPollCount(); + setSubRequestId(null); } /** @@ -179,56 +173,50 @@ public abstract class SoOperation extends HttpOperation { } protected int getVfCount() { + if (containsProperty(OperationProperties.DATA_VF_COUNT)) { + return getProperty(OperationProperties.DATA_VF_COUNT); + } + return params.getContext().getProperty(vfCountKey); } protected void setVfCount(int vfCount) { + if (containsProperty(OperationProperties.DATA_VF_COUNT)) { + setProperty(OperationProperties.DATA_VF_COUNT, vfCount); + return; + } + params.getContext().setProperty(vfCountKey, vfCount); } - /** - * If the response does not indicate that the request has been completed, then sleep a - * bit and issue a "get". - */ @Override - protected CompletableFuture postProcessResponse(OperationOutcome outcome, String url, - Response rawResponse, SoResponse response) { - - // see if the request has "completed", whether or not it was successful + protected Status detmStatus(Response rawResponse, SoResponse response) { if (rawResponse.getStatus() == 200) { String requestState = getRequestState(response); if (COMPLETE.equalsIgnoreCase(requestState)) { extractSubRequestId(response); - successfulCompletion(); - return CompletableFuture - .completedFuture(setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response)); + return Status.SUCCESS; } if (FAILED.equalsIgnoreCase(requestState)) { extractSubRequestId(response); - return CompletableFuture - .completedFuture(setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response)); + return Status.FAILURE; } } // still incomplete // need a request ID with which to query - if (!extractSubRequestId(response)) { + if (getSubRequestId() == null && !extractSubRequestId(response)) { throw new IllegalArgumentException("missing request ID in response"); } - // see if the limit for the number of "gets" has been reached - if (getCount++ >= getMaxGets()) { - logger.warn("{}: execeeded 'get' limit {} for {}", getFullName(), getMaxGets(), params.getRequestId()); - setOutcome(outcome, PolicyResult.FAILURE_TIMEOUT); - outcome.setMessage(SO_RESPONSE_CODE + " " + outcome.getMessage()); - return CompletableFuture.completedFuture(outcome); - } + return Status.STILL_WAITING; + } - // sleep and then perform a "get" operation - Function> doGet = unused -> issueGet(outcome, response); - return sleep(getWaitMsGet(), TimeUnit.MILLISECONDS).thenComposeAsync(doGet); + @Override + protected String getPollingPath() { + return super.getPollingPath() + getSubRequestId(); } @Override @@ -246,32 +234,6 @@ public abstract class SoOperation extends HttpOperation { return true; } - /** - * Invoked when a request completes successfully. - */ - protected void successfulCompletion() { - // do nothing - } - - /** - * Issues a "get" request to see if the original request is complete yet. - * - * @param outcome outcome to be populated with the response - * @param response previous response - * @return a future that can be used to cancel the "get" request or await its response - */ - private CompletableFuture issueGet(OperationOutcome outcome, SoResponse response) { - String path = getPathGet() + response.getRequestReferences().getRequestId(); - String url = getClient().getBaseUrl() + path; - - logger.debug("{}: 'get' count {} for {}", getFullName(), getCount, params.getRequestId()); - - logMessage(EventType.OUT, CommInfrastructure.REST, url, null); - - // TODO should this use "path" or the full "url"? - return handleResponse(outcome, url, callback -> getClient().get(callback, path, null)); - } - /** * Gets the request state of a response. * @@ -311,7 +273,10 @@ public abstract class SoOperation extends HttpOperation { // set default result and message setOutcome(outcome, result); - outcome.setMessage(rawResponse.getStatus() + " " + outcome.getMessage()); + int code = (result == PolicyResult.FAILURE_TIMEOUT ? SO_RESPONSE_CODE : rawResponse.getStatus()); + + outcome.setResponse(response); + outcome.setMessage(code + " " + outcome.getMessage()); return outcome; } @@ -417,67 +382,110 @@ public abstract class SoOperation extends HttpOperation { return headers; } - /* - * These methods extract data from the Custom Query and throw an - * IllegalArgumentException if the desired data item is not found. + /** + * Gets an item from a property. If the property is not found, then it invokes the + * given function to retrieve it from the custom query data. If that fails as well, + * then an exception is thrown. + * + * @param propName property name + * @param getter method to extract the value from the custom query data + * @param errmsg error message to include in any exception + * @return the retrieved item */ + protected T getItem(String propName, Function getter, String errmsg) { + if (containsProperty(propName)) { + return getProperty(propName); + } - protected GenericVnf getVnfItem(AaiCqResponse aaiCqResponse, SoModelInfo soModelInfo) { - GenericVnf vnf = aaiCqResponse.getGenericVnfByVfModuleModelInvariantId(soModelInfo.getModelInvariantId()); - if (vnf == null) { - throw new IllegalArgumentException("missing generic VNF"); + final AaiCqResponse aaiCqResponse = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); + T item = getter.apply(aaiCqResponse); + if (item == null) { + throw new IllegalArgumentException(errmsg); } - return vnf; + return item; } - protected ServiceInstance getServiceInstance(AaiCqResponse aaiCqResponse) { - ServiceInstance vnfService = aaiCqResponse.getServiceInstance(); - if (vnfService == null) { - throw new IllegalArgumentException("missing VNF Service Item"); - } + /* + * These methods extract data from the Custom Query and throw an + * IllegalArgumentException if the desired data item is not found. + */ - return vnfService; + protected GenericVnf getVnfItem(SoModelInfo soModelInfo) { + // @formatter:off + return getItem(OperationProperties.AAI_VNF, + cq -> cq.getGenericVnfByVfModuleModelInvariantId(soModelInfo.getModelInvariantId()), + "missing generic VNF"); + // @formatter:on } - protected Tenant getDefaultTenant(AaiCqResponse aaiCqResponse) { - Tenant tenant = aaiCqResponse.getDefaultTenant(); - if (tenant == null) { - throw new IllegalArgumentException("missing Tenant Item"); - } + protected ServiceInstance getServiceInstance() { + return getItem(OperationProperties.AAI_SERVICE, AaiCqResponse::getServiceInstance, "missing VNF Service Item"); + } - return tenant; + protected Tenant getDefaultTenant() { + // @formatter:off + return getItem(OperationProperties.AAI_DEFAULT_TENANT, + AaiCqResponse::getDefaultTenant, + "missing Default Tenant Item"); + // @formatter:on } - protected CloudRegion getDefaultCloudRegion(AaiCqResponse aaiCqResponse) { - CloudRegion cloudRegion = aaiCqResponse.getDefaultCloudRegion(); - if (cloudRegion == null) { - throw new IllegalArgumentException("missing Cloud Region"); - } + protected CloudRegion getDefaultCloudRegion() { + // @formatter:off + return getItem(OperationProperties.AAI_DEFAULT_CLOUD_REGION, + AaiCqResponse::getDefaultCloudRegion, + "missing Default Cloud Region"); + // @formatter:on + } + + protected ModelVer getVnfModel(GenericVnf vnfItem) { + // @formatter:off + return getItem(OperationProperties.AAI_VNF_MODEL, + cq -> cq.getModelVerByVersionId(vnfItem.getModelVersionId()), + "missing generic VNF Model"); + // @formatter:on + } - return cloudRegion; + protected ModelVer getServiceModel(ServiceInstance vnfServiceItem) { + // @formatter:off + return getItem(OperationProperties.AAI_SERVICE_MODEL, + cq -> cq.getModelVerByVersionId(vnfServiceItem.getModelVersionId()), + "missing Service Model"); + // @formatter:on } // these may be overridden by junit tests - /** - * Gets the wait time, in milliseconds, between "get" requests. - * - * @return the wait time, in milliseconds, between "get" requests - */ - public long getWaitMsGet() { - return TimeUnit.MILLISECONDS.convert(getWaitSecGet(), TimeUnit.SECONDS); + @Override + protected Coder getCoder() { + return coder; } - public int getMaxGets() { - return config.getMaxGets(); - } + private static class SoCoder extends StandardCoder { - public String getPathGet() { - return config.getPathGet(); - } + /** + * Gson object used to encode and decode messages. + */ + private static final Gson SO_GSON; + + /** + * Gson object used to encode messages in "pretty" format. + */ + private static final Gson SO_GSON_PRETTY; + + static { + GsonBuilder builder = GsonMessageBodyHandler + .configBuilder(new GsonBuilder().registerTypeAdapter(StandardCoderObject.class, + new StandardTypeAdapter())) + .registerTypeAdapter(LocalDateTime.class, new SoLocalDateTimeTypeAdapter()); - public int getWaitSecGet() { - return config.getWaitSecGet(); + SO_GSON = builder.create(); + SO_GSON_PRETTY = builder.setPrettyPrinting().create(); + } + + public SoCoder() { + super(SO_GSON, SO_GSON_PRETTY); + } } }