diff options
author | Jim Hahn <jrh3@att.com> | 2020-08-21 13:43:08 -0400 |
---|---|---|
committer | Jim Hahn <jrh3@att.com> | 2020-10-27 14:55:15 -0400 |
commit | 19ef8b24a98c09a349e6ae7309f535a0135463f6 (patch) | |
tree | d988e5a58865ae6f3a38dcb31e4f195f18e59946 /models-interactions/model-actors/actorServiceProvider/src/main | |
parent | 6b29d2c19e288148171db0c0e446e18dcd46effd (diff) |
Make Actors event-agnostic
Removed event and event-context code from the Actor code. Also removed
the preprocessing steps from the Actor code, giving the application
complete control over any preprocessing.
Also fixed a bug wherein the APPC actor was treating the
AAI_RESOURCE_VNF property as a String instead of as a GenericVnf.
Issue-ID: POLICY-2746-actor
Change-Id: Ibc05fe39ffedc0bc461abf10e6a960861ac70119
Signed-off-by: Jim Hahn <jrh3@att.com>
Diffstat (limited to 'models-interactions/model-actors/actorServiceProvider/src/main')
4 files changed, 26 insertions, 352 deletions
diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/OperationProperties.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/OperationProperties.java index 718daedb1..d4dea7c48 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/OperationProperties.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/OperationProperties.java @@ -54,7 +54,7 @@ public class OperationProperties { public static final String AAI_PNF = "AAI/pnf"; /** - * A&AI VNF id for the target resource ID. Obtained as follows: + * A&AI [Generic] VNF for the target resource ID. Obtained as follows: * <ol> * <li>using the target resource ID, invoke the custom query * getGenericVnfByModelInvariantId() method to get the generic VNF</li> diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java deleted file mode 100644 index f7b58c11e..000000000 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java +++ /dev/null @@ -1,168 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.controlloop.actorserviceprovider.controlloop; - -import java.io.Serializable; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import org.onap.policy.controlloop.VirtualControlLoopEvent; -import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; -import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; - -/** - * Context associated with a control loop event. - */ -@Getter -@Setter -public class ControlLoopEventContext implements Serializable { - private static final long serialVersionUID = 1L; - - - private final VirtualControlLoopEvent event; - - /** - * Enrichment data extracted from the event. Never {@code null}, though it may be - * immutable. - */ - private final Map<String, String> enrichment; - - /** - * Set of properties that have been stored in the context. - */ - @Getter(AccessLevel.NONE) - @Setter(AccessLevel.NONE) - private Map<String, Serializable> properties = new ConcurrentHashMap<>(); - - /** - * When {@link #obtain(String, ControlLoopOperationParams)} is invoked and the - * specified property is not found in {@link #properties}, it is retrieved. This holds - * the futures for the operations retrieving the properties. - */ - @Getter(AccessLevel.NONE) - @Setter(AccessLevel.NONE) - private transient Map<String, CompletableFuture<OperationOutcome>> retrievers = new ConcurrentHashMap<>(); - - /** - * Request ID extracted from the event, or a generated value if the event has no - * request id; never {@code null}. - */ - private final UUID requestId; - - - /** - * Constructs the object. - * - * @param event event with which this is associated - */ - public ControlLoopEventContext(@NonNull VirtualControlLoopEvent event) { - this.event = event; - this.requestId = (event.getRequestId() != null ? event.getRequestId() : UUID.randomUUID()); - this.enrichment = (event.getAai() != null ? event.getAai() : Map.of()); - } - - /** - * Determines if the context contains a property. - * - * @param name name of the property of interest - * @return {@code true} if the context contains the property, {@code false} otherwise - */ - public boolean contains(String name) { - return properties.containsKey(name); - } - - /** - * Gets a property, casting it to the desired type. - * - * @param <T> desired type - * @param name name of the property whose value is to be retrieved - * @return the property's value, or {@code null} if it does not yet have a value - */ - @SuppressWarnings("unchecked") - public <T> T getProperty(String name) { - return (T) properties.get(name); - } - - /** - * Sets a property's value. - * - * @param name property name - * @param value new property value - */ - public void setProperty(String name, Serializable value) { - properties.put(name, value); - } - - /** - * Removes a property. - * @param name property name - */ - public void removeProperty(String name) { - properties.remove(name); - } - - /** - * Obtains the given property. - * - * @param name name of the desired property - * @param params parameters needed to perform the operation to retrieve the desired - * property - * @return a future for retrieving the property, {@code null} if the property has - * already been retrieved - */ - public CompletableFuture<OperationOutcome> obtain(String name, ControlLoopOperationParams params) { - if (properties.containsKey(name)) { - return null; - } - - /* - * Return any existing future, if it wasn't canceled. Otherwise, start a new - * request. - */ - - // @formatter:off - CompletableFuture<OperationOutcome> oldFuture = - retrievers.computeIfPresent(name, (key, future) -> future.isCancelled() ? null : future); - // @formatter:on - - if (oldFuture != null) { - return oldFuture; - } - - /* - * Note: must NOT invoke params.start() within retrievers.compute(), as start() - * may invoke obtain() which would cause a recursive update to the retrievers map. - */ - CompletableFuture<OperationOutcome> future = params.start(); - - if ((oldFuture = retrievers.putIfAbsent(name, future)) != null) { - future.cancel(false); - return oldFuture; - } - - return future; - } -} diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java index c81575f62..e9f6b024c 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java @@ -24,7 +24,6 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -65,9 +64,7 @@ import org.slf4j.LoggerFactory; * Partial implementation of an operator. In general, it's preferable that subclasses * would override {@link #startOperationAsync(int, OperationOutcome) * startOperationAsync()}. However, if that proves to be too difficult, then they can - * simply override {@link #doOperation(int, OperationOutcome) doOperation()}. In addition, - * if the operation requires any preprocessor steps, the subclass may choose to override - * {@link #startPreprocessorAsync()}. + * simply override {@link #doOperation(int, OperationOutcome) doOperation()}. * <p/> * The futures returned by the methods within this class can be canceled, and will * propagate the cancellation to any subtasks. Thus it is also expected that any futures @@ -159,153 +156,36 @@ public abstract class OperationPartial implements Operation { return (T) properties.get(name); } - @Override - public CompletableFuture<OperationOutcome> start() { - // allocate a controller for the entire operation - final PipelineControllerFuture<OperationOutcome> controller = new PipelineControllerFuture<>(); - - CompletableFuture<OperationOutcome> preproc = startPreprocessorAsync(); - if (preproc == null) { - // no preprocessor required - just start the operation - return startOperationAttempt(controller, 1); - } - - /* - * Do preprocessor first and then, if successful, start the operation. Note: - * operations create their own outcome, ignoring the outcome from any previous - * steps. - * - * Wrap the preprocessor to ensure "stop" is propagated to it. - */ - // @formatter:off - controller.wrap(preproc) - .exceptionally(fromException("preprocessor of operation")) - .thenCompose(handlePreprocessorFailure(controller)) - .thenCompose(unusedOutcome -> startOperationAttempt(controller, 1)) - .whenCompleteAsync(controller.delayedComplete(), params.getExecutor()); - // @formatter:on - - return controller; - } - /** - * Handles a failure in the preprocessor pipeline. If a failure occurred, then it - * invokes the call-backs, marks the controller complete, and returns an incomplete - * future, effectively halting the pipeline. Otherwise, it returns the outcome that it - * received. - * <p/> - * Assumes that no callbacks have been invoked yet. + * Gets a property value, throwing an exception if it's missing. * - * @param controller pipeline controller - * @return a function that checks the outcome status and continues, if successful, or - * indicates a failure otherwise + * @param name property name + * @param propertyType property type, used in an error message if the property value + * is {@code null} + * @return the property value */ - private Function<OperationOutcome, CompletableFuture<OperationOutcome>> handlePreprocessorFailure( - PipelineControllerFuture<OperationOutcome> controller) { - - return outcome -> { - - if (isSuccess(outcome)) { - logger.info("{}: preprocessor succeeded for {}", getFullName(), params.getRequestId()); - return CompletableFuture.completedFuture(outcome); - } - - logger.warn("preprocessor failed, discontinuing operation {} for {}", getFullName(), params.getRequestId()); - - final Executor executor = params.getExecutor(); - final CallbackManager callbacks = new CallbackManager(); - - // propagate "stop" to the callbacks - controller.add(callbacks); - - final OperationOutcome outcome2 = params.makeOutcome(getTargetEntity()); - - // TODO need a FAILURE_MISSING_DATA (e.g., A&AI) - - outcome2.setFinalOutcome(true); - outcome2.setResult(OperationResult.FAILURE_GUARD); - outcome2.setMessage(outcome != null ? outcome.getMessage() : null); - - // @formatter:off - CompletableFuture.completedFuture(outcome2) - .whenCompleteAsync(callbackStarted(callbacks), executor) - .whenCompleteAsync(callbackCompleted(callbacks), executor) - .whenCompleteAsync(controller.delayedComplete(), executor); - // @formatter:on - - return new CompletableFuture<>(); - }; - } - - /** - * Invokes the operation's preprocessor step(s) as a "future". This method simply - * returns {@code null}. - * <p/> - * This method assumes the following: - * <ul> - * <li>the operator is alive</li> - * <li>exceptions generated within the pipeline will be handled by the invoker</li> - * </ul> - * - * @return a function that will start the preprocessor and returns its outcome, or - * {@code null} if this operation needs no preprocessor - */ - protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { - return null; - } - - /** - * Invokes the operation's guard step(s) as a "future". - * <p/> - * This method assumes the following: - * <ul> - * <li>the operator is alive</li> - * <li>exceptions generated within the pipeline will be handled by the invoker</li> - * </ul> - * - * @return a function that will start the guard checks and returns its outcome, or - * {@code null} if this operation has no guard - */ - protected CompletableFuture<OperationOutcome> startGuardAsync() { - if (params.isPreprocessed()) { - return null; + @SuppressWarnings("unchecked") + protected <T> T getRequiredProperty(String name, String propertyType) { + T value = (T) properties.get(name); + if (value == null) { + throw new IllegalStateException("missing " + propertyType); } - // get the guard payload - Map<String, Object> payload = makeGuardPayload(); - - /* - * Note: can't use constants from actor.guard, because that would create a - * circular dependency. - */ - return params.toBuilder().actor(GUARD_ACTOR_NAME).operation(GUARD_OPERATION_NAME).retry(null).timeoutSec(null) - .payload(payload).build().start(); + return value; } - /** - * Creates a payload to execute a guard operation. - * - * @return a new guard payload - */ - protected Map<String, Object> makeGuardPayload() { - // TODO delete this once preprocessing is done by the application - Map<String, Object> guard = new LinkedHashMap<>(); - guard.put("actor", params.getActor()); - guard.put("operation", params.getOperation()); - guard.put("target", getTargetEntity()); - guard.put("requestId", params.getRequestId()); - - String clname = params.getContext().getEvent().getClosedLoopControlName(); - if (clname != null) { - guard.put("clname", clname); - } + @Override + public CompletableFuture<OperationOutcome> start() { + // allocate a controller for the entire operation + final PipelineControllerFuture<OperationOutcome> controller = new PipelineControllerFuture<>(); - return guard; + // start attempt #1 + return startOperationAttempt(controller, 1); } /** - * Starts the operation attempt, with no preprocessor. When all retries complete, it - * will complete the controller. + * Starts the operation attempt. When all retries complete, it will complete the + * controller. * * @param controller controller for all operation attempts * @param attempt attempt number, typically starting with 1 diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java index 0e4f09b66..67f68036b 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java @@ -33,13 +33,11 @@ import lombok.Getter; import org.onap.policy.common.parameters.BeanValidationResult; import org.onap.policy.common.parameters.BeanValidator; import org.onap.policy.common.parameters.annotations.NotNull; -import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.actorserviceprovider.ActorService; import org.onap.policy.controlloop.actorserviceprovider.Operation; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.TargetType; import org.onap.policy.controlloop.actorserviceprovider.Util; -import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,14 +72,10 @@ public class ControlLoopOperationParams { private ActorService actorService; /** - * Event for which the operation applies. - */ - // TODO to be removed - private ControlLoopEventContext context; - - /** - * If {@code null}, this value is extracted from the context. + * Request ID with which all actor operations are associated. Used to track requests + * across various components/servers. */ + @NotNull private UUID requestId; /** @@ -106,6 +100,7 @@ public class ControlLoopOperationParams { * {@code True} if the preprocessing steps have already been executed, {@code false} * otherwise. */ + // TODO remove this once the rules no longer reference it private boolean preprocessed; /** @@ -194,11 +189,6 @@ public class ControlLoopOperationParams { * @return the event's request ID, or {@code null} if no request ID is available */ public UUID getRequestId() { - if (requestId == null && context != null && context.getEvent() != null) { - // cache the request ID - requestId = context.getEvent().getRequestId(); - } - return requestId; } @@ -266,34 +256,6 @@ public class ControlLoopOperationParams { * @return the validation result */ public BeanValidationResult validate() { - BeanValidationResult result = - new BeanValidator().validateTop(ControlLoopOperationParams.class.getSimpleName(), this); - - // validate that we have a request ID, or that we can get it from the context's - // event - - if (context == null) { - // no context specified - invoker must provide a request ID then - result.validateNotNull("requestId", requestId); - - } else if (requestId == null) { - // have a context, but no request ID - check the context's event for the - // request ID - BeanValidationResult contextResult = new BeanValidationResult("context", context); - VirtualControlLoopEvent event = context.getEvent(); - contextResult.validateNotNull("event", event); - - if (event != null) { - // cache the request id for later use - BeanValidationResult eventResult = new BeanValidationResult("event", event); - eventResult.validateNotNull("requestId", event.getRequestId()); - - contextResult.addResult(eventResult); - } - - result.addResult(contextResult); - } - - return result; + return new BeanValidator().validateTop(ControlLoopOperationParams.class.getSimpleName(), this); } } |