Merge "Modify Actors to use properties when provided"
authorPamela Dragosh <pdragosh@research.att.com>
Fri, 7 Aug 2020 22:02:24 +0000 (22:02 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 7 Aug 2020 22:02:24 +0000 (22:02 +0000)
26 files changed:
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java
models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperation.java
models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperationTest.java
models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java
models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java
models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperation.java
models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperation.java
models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperation.java
models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperationTest.java
models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperationTest.java
models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java
models-interactions/model-actors/actor.sdnc/src/test/resources/bod.json
models-interactions/model-actors/actor.sdnr/src/main/java/org/onap/policy/controlloop/actor/sdnr/SdnrOperation.java
models-interactions/model-actors/actor.sdnr/src/test/java/org/onap/policy/controlloop/actor/sdnr/SdnrOperationTest.java
models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java
models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java
models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleDelete.java
models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java
models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java
models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleDeleteTest.java
models-interactions/model-actors/actor.vfc/src/main/java/org/onap/policy/controlloop/actor/vfc/VfcOperation.java
models-interactions/model-actors/actor.vfc/src/test/java/org/onap/policy/controlloop/actor/vfc/RestartTest.java
models-interactions/model-actors/actor.vfc/src/test/java/org/onap/policy/controlloop/actor/vfc/VfcOperationTest.java
models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/OperationProperties.java
models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java

index 151f7a2..c8e0870 100644 (file)
@@ -29,7 +29,6 @@ import javax.ws.rs.client.Invocation.Builder;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import lombok.Getter;
 import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.aai.AaiConstants;
 import org.onap.policy.aai.AaiCqResponse;
@@ -64,9 +63,6 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
     // TODO make this configurable
     private static final String PREFIX = "/aai/v16";
 
-    @Getter
-    private final String vserver;
-
     /**
      * Constructs the object.
      *
@@ -75,11 +71,20 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
      */
     public AaiCustomQueryOperation(ControlLoopOperationParams params, HttpConfig config) {
         super(params, config, String.class, PROPERTY_NAMES);
+    }
 
-        this.vserver = params.getContext().getEnrichment().get(VSERVER_VSERVER_NAME);
-        if (StringUtils.isBlank(this.vserver)) {
+    /**
+     * Gets the vserver name from the enrichment data.
+     *
+     * @return the vserver name
+     */
+    protected String getVserver() {
+        String vserver = this.params.getContext().getEnrichment().get(VSERVER_VSERVER_NAME);
+        if (StringUtils.isBlank(vserver)) {
             throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data");
         }
+
+        return vserver;
     }
 
     /**
@@ -91,6 +96,7 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
             return null;
         }
 
+        String vserver = getVserver();
         ControlLoopOperationParams tenantParams =
                         params.toBuilder().actor(AaiConstants.ACTOR_NAME).operation(AaiGetTenantOperation.NAME)
                                         .targetEntity(vserver).payload(null).retry(null).timeoutSec(null).build();
@@ -146,16 +152,33 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
      * Constructs the custom query using the previously retrieved tenant data.
      */
     private Map<String, String> makeRequest() {
+        return Map.of("start", getVserverLink(), "query", "query/closed-loop");
+    }
+
+    /**
+     * Gets the vserver link, first checking the properties, and then the tenant data.
+     *
+     * @return the vserver link
+     */
+    protected String getVserverLink() {
+        String resourceLink = getProperty(OperationProperties.AAI_VSERVER_LINK);
+        if (resourceLink != null) {
+            return resourceLink;
+        }
+
+        String vserver = getVserver();
         StandardCoderObject tenant = params.getContext().getProperty(AaiGetTenantOperation.getKey(vserver));
+        if (tenant == null) {
+            throw new IllegalStateException("cannot perform custom query - cannot determine resource-link");
+        }
 
-        String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
+        resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
         if (resourceLink == null) {
             throw new IllegalArgumentException("cannot perform custom query - no resource-link");
         }
 
         resourceLink = resourceLink.replace(PREFIX, "");
-
-        return Map.of("start", resourceLink, "query", "query/closed-loop");
+        return resourceLink;
     }
 
     @Override
index 476e643..f122537 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.policy.controlloop.actor.aai;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -113,11 +114,12 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation {
         HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/query").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        preloadTenantData();
-
-        params = params.toBuilder().targetEntity(SIM_VSERVER).retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().targetEntity(SIM_VSERVER).retry(0).timeoutSec(5).executor(blockingExecutor)
+                        .preprocessed(true).build();
         oper = new AaiCustomQueryOperation(params, config);
 
+        oper.setProperty(OperationProperties.AAI_VSERVER_LINK, MY_LINK);
+
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
 
@@ -129,15 +131,19 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation {
     public void testConstructor() {
         assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
         assertEquals(AaiCustomQueryOperation.NAME, oper.getName());
-        assertEquals(MY_VSERVER, oper.getVserver());
 
         // verify that it works with an empty target entity
         params = params.toBuilder().targetEntity("").build();
         assertThatCode(() -> new AaiCustomQueryOperation(params, config)).doesNotThrowAnyException();
+    }
+
+    @Test
+    public void testGetVserver() {
+        assertEquals(MY_VSERVER, oper.getVserver());
 
         // try without enrichment data
         params.getContext().getEnrichment().remove(AaiCustomQueryOperation.VSERVER_VSERVER_NAME);
-        assertThatIllegalArgumentException().isThrownBy(() -> new AaiCustomQueryOperation(params, config))
+        assertThatIllegalArgumentException().isThrownBy(() -> oper.getVserver())
                         .withMessage("missing " + AaiCustomQueryOperation.VSERVER_VSERVER_NAME + " in enrichment data");
     }
 
@@ -215,7 +221,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation {
 
     @Test
     @SuppressWarnings("unchecked")
-    public void testMakeRequest() throws Exception {
+    public void testMakeRequest_testGetVserverLink() throws Exception {
         // preload
         preloadTenantData();
 
@@ -237,17 +243,24 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation {
     }
 
     @Test
-    @SuppressWarnings("unchecked")
-    public void testMakeRequestNoResourceLink() throws Exception {
-        // pre-load EMPTY tenant data
-        preloadTenantData(new StandardCoderObject());
+    public void testGetVserverLinkViaProperty() throws Exception {
+        oper.setProperty(OperationProperties.AAI_VSERVER_LINK, MY_LINK);
+        assertEquals(MY_LINK, oper.getVserverLink());
+    }
 
-        when(rawResponse.readEntity(String.class)).thenReturn(makeCqReply());
-        when(webAsync.put(any(), any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse, 1));
+    @Test
+    public void testGetVserverLinkNoTenantData() throws Exception {
+        assertThatIllegalStateException().isThrownBy(() -> oper.getVserverLink())
+                        .withMessage("cannot perform custom query - cannot determine resource-link");
+    }
 
-        CompletableFuture<OperationOutcome> future2 = oper.start();
+    @Test
+    public void testGetVserverLinkNoResourceLink() throws Exception {
+        // pre-load EMPTY tenant data
+        preloadTenantData(new StandardCoderObject());
 
-        assertEquals(PolicyResult.FAILURE_EXCEPTION, getResult(future2));
+        assertThatIllegalArgumentException().isThrownBy(() -> oper.getVserverLink())
+                        .withMessage("cannot perform custom query - no resource-link");
     }
 
     private String makeTenantReply() throws Exception {
index 680bd9c..13ddaf4 100644 (file)
@@ -69,7 +69,19 @@ public class ModifyConfigOperation extends AppcOperation {
 
     @Override
     protected Request makeRequest(int attempt) {
+        return makeRequest(attempt, getVnfId());
+    }
+
+    protected String getVnfId() {
+        GenericVnf vnf = this.getProperty(OperationProperties.AAI_RESOURCE_VNF);
+        if (vnf != null) {
+            return vnf.getVnfId();
+        }
+
         AaiCqResponse cq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY);
+        if (cq == null) {
+            throw new IllegalStateException("target vnf-id could not be determined");
+        }
 
         GenericVnf genvnf = cq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID());
         if (genvnf == null) {
@@ -77,6 +89,6 @@ public class ModifyConfigOperation extends AppcOperation {
             throw new IllegalArgumentException("target vnf-id could not be found");
         }
 
-        return makeRequest(attempt, genvnf.getVnfId());
+        return genvnf.getVnfId();
     }
 }
index 9c602f5..3b63514 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.policy.controlloop.actor.appc;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -42,6 +43,7 @@ import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.mockito.Mock;
 import org.onap.aai.domain.yang.GenericVnf;
 import org.onap.policy.aai.AaiCqResponse;
 import org.onap.policy.appc.Request;
@@ -56,8 +58,14 @@ import org.onap.policy.controlloop.policy.PolicyResult;
 
 public class ModifyConfigOperationTest extends BasicAppcOperation {
 
+    @Mock
+    private GenericVnf genvnf;
+    @Mock
+    private AaiCqResponse cq;
+
     private ModifyConfigOperation oper;
 
+
     public ModifyConfigOperationTest() {
         super(DEFAULT_ACTOR, ModifyConfigOperation.NAME);
     }
@@ -77,6 +85,9 @@ public class ModifyConfigOperationTest extends BasicAppcOperation {
     @Override
     public void setUp() throws Exception {
         super.setUp();
+        when(genvnf.getVnfId()).thenReturn(MY_VNF);
+        when(cq.getGenericVnfByModelInvariantId(any())).thenReturn(genvnf);
+
         oper = new ModifyConfigOperation(params, config);
     }
 
@@ -95,14 +106,9 @@ public class ModifyConfigOperationTest extends BasicAppcOperation {
                         BidirectionalTopicParams.builder().sinkTopic(MY_SINK).sourceTopic(MY_SINK).build();
         config = new BidirectionalTopicConfig(blockingExecutor, opParams, topicMgr, AppcOperation.SELECTOR_KEYS);
 
-        AaiCqResponse cq = mock(AaiCqResponse.class);
-        GenericVnf genvnf = mock(GenericVnf.class);
-        when(genvnf.getVnfId()).thenReturn(MY_VNF);
-        when(cq.getGenericVnfByModelInvariantId(any())).thenReturn(genvnf);
-
         params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq);
 
-        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
 
         oper = new ModifyConfigOperation(params, config) {
             @Override
@@ -111,6 +117,8 @@ public class ModifyConfigOperationTest extends BasicAppcOperation {
             }
         };
 
+        oper.setProperty(OperationProperties.AAI_RESOURCE_VNF, genvnf);
+
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
         assertTrue(outcome.getResponse() instanceof Response);
@@ -168,23 +176,41 @@ public class ModifyConfigOperationTest extends BasicAppcOperation {
 
     @Test
     public void testMakeRequest() throws CoderException {
-        AaiCqResponse cq = new AaiCqResponse("{}");
+        oper.setProperty(OperationProperties.AAI_RESOURCE_VNF, genvnf);
+
+        oper.generateSubRequestId(2);
+        Request request = oper.makeRequest(2);
+        assertNotNull(request);
+        assertEquals(MY_VNF, request.getPayload().get(ModifyConfigOperation.VNF_ID_KEY));
+
+        verifyRequest("modifyConfig.json", request, IGNORE_FIELDS);
+    }
+
+    @Test
+    public void testGetVnfIdViaProperty() throws CoderException {
+        oper.setProperty(OperationProperties.AAI_RESOURCE_VNF, genvnf);
+        assertEquals(MY_VNF, oper.getVnfId());
+    }
+
+    @Test
+    public void testGetVnfId() throws CoderException {
+        // no CQ data
+        assertThatIllegalStateException().isThrownBy(() -> oper.getVnfId())
+                        .withMessage("target vnf-id could not be determined");
+
+        cq = new AaiCqResponse("{}");
 
         // missing vnf-id
         params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq);
-        assertThatIllegalArgumentException().isThrownBy(() -> oper.makeRequest(1));
+        assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfId())
+                        .withMessage("target vnf-id could not be found");
 
         // populate the CQ data with a vnf-id
-        GenericVnf genvnf = new GenericVnf();
+        genvnf = new GenericVnf();
         genvnf.setVnfId(MY_VNF);
         genvnf.setModelInvariantId(RESOURCE_ID);
         cq.setInventoryResponseItems(Arrays.asList(genvnf));
 
-        oper.generateSubRequestId(2);
-        Request request = oper.makeRequest(2);
-        assertNotNull(request);
-        assertEquals(MY_VNF, request.getPayload().get(ModifyConfigOperation.VNF_ID_KEY));
-
-        verifyRequest("modifyConfig.json", request, IGNORE_FIELDS);
+        assertEquals(MY_VNF, oper.getVnfId());
     }
 }
index ec8f2ac..d384244 100644 (file)
@@ -44,7 +44,6 @@ import org.onap.policy.aai.AaiConstants;
 import org.onap.policy.aai.AaiCqResponse;
 import org.onap.policy.cds.client.CdsProcessorGrpcClient;
 import org.onap.policy.common.utils.coder.CoderException;
-import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation;
 import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
 import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants;
@@ -91,13 +90,15 @@ public class GrpcOperation extends OperationPartial {
     // @formatter:off
     private static final List<String> PNF_PROPERTY_NAMES = List.of(
                             OperationProperties.AAI_PNF,
-                            OperationProperties.EVENT_ADDITIONAL_PARAMS);
+                            OperationProperties.EVENT_ADDITIONAL_PARAMS,
+                            OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES);
 
 
     private static final List<String> VNF_PROPERTY_NAMES = List.of(
-                            OperationProperties.AAI_MODEL_INVARIANT_GENERIC_VNF,
-                            OperationProperties.AAI_RESOURCE_SERVICE_INSTANCE,
-                            OperationProperties.EVENT_ADDITIONAL_PARAMS);
+                            OperationProperties.AAI_RESOURCE_VNF,
+                            OperationProperties.AAI_SERVICE,
+                            OperationProperties.EVENT_ADDITIONAL_PARAMS,
+                            OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES);
     // @formatter:on
 
     /**
@@ -177,11 +178,15 @@ public class GrpcOperation extends OperationPartial {
      * @return a map of the PNF data
      */
     private Map<String, String> convertPnfToAaiProperties() {
+        Map<String, String> result = this.getProperty(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES);
+        if (result != null) {
+            return result;
+        }
+
         // convert PNF data to a Map
-        StandardCoderObject pnf = params.getContext().getProperty(AaiGetPnfOperation.getKey(params.getTargetEntity()));
-        Map<String, Object> source = Util.translateToMap(getFullName(), pnf);
+        Map<String, Object> source = Util.translateToMap(getFullName(), getPnfData());
 
-        Map<String, String> result = new LinkedHashMap<>();
+        result = new LinkedHashMap<>();
 
         for (Entry<String, Object> ent : source.entrySet()) {
             result.put(AAI_PNF_PREFIX + ent.getKey(), ent.getValue().toString());
@@ -190,6 +195,26 @@ public class GrpcOperation extends OperationPartial {
         return result;
     }
 
+    /**
+     * Gets the PNF from the operation properties, if it exists, or from the context
+     * properties otherwise.
+     *
+     * @return the PNF item
+     */
+    protected Object getPnfData() {
+        Object pnf = getProperty(OperationProperties.AAI_PNF);
+        if (pnf != null) {
+            return pnf;
+        }
+
+        pnf = params.getContext().getProperty(AaiGetPnfOperation.getKey(params.getTargetEntity()));
+        if (pnf == null) {
+            throw new IllegalArgumentException("missing PNF data");
+        }
+
+        return pnf;
+    }
+
     /**
      * Converts the A&AI Custom Query data to a map suitable for passing via the
      * "aaiProperties" field in the CDS request.
@@ -197,24 +222,49 @@ public class GrpcOperation extends OperationPartial {
      * @return a map of the custom query data
      */
     private Map<String, String> convertCqToAaiProperties() {
-        AaiCqResponse aaicq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY);
+        Map<String, String> result = this.getProperty(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES);
+        if (result != null) {
+            return result;
+        }
 
-        Map<String, String> result = new LinkedHashMap<>();
+        result = new LinkedHashMap<>();
+
+        result.put(AAI_SERVICE_INSTANCE_ID_KEY, getServiceInstanceId());
+        result.put(AAI_VNF_ID_KEY, getVnfId());
+
+        return result;
+    }
 
-        ServiceInstance serviceInstance = aaicq.getServiceInstance();
+    protected String getServiceInstanceId() {
+        ServiceInstance serviceInstance = getProperty(OperationProperties.AAI_SERVICE);
+        if (serviceInstance != null) {
+            return serviceInstance.getServiceInstanceId();
+        }
+
+        AaiCqResponse aaicq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY);
+
+        serviceInstance = aaicq.getServiceInstance();
         if (serviceInstance == null) {
             throw new IllegalArgumentException("Target service instance could not be found");
         }
 
-        GenericVnf genericVnf = aaicq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID());
+        return serviceInstance.getServiceInstanceId();
+    }
+
+    protected String getVnfId() {
+        GenericVnf genericVnf = getProperty(OperationProperties.AAI_RESOURCE_VNF);
+        if (genericVnf != null) {
+            return genericVnf.getVnfId();
+        }
+
+        AaiCqResponse aaicq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY);
+
+        genericVnf = aaicq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID());
         if (genericVnf == null) {
             throw new IllegalArgumentException("Target generic vnf could not be found");
         }
 
-        result.put(AAI_SERVICE_INSTANCE_ID_KEY, serviceInstance.getServiceInstanceId());
-        result.put(AAI_VNF_ID_KEY, genericVnf.getVnfId());
-
-        return result;
+        return genericVnf.getVnfId();
     }
 
     @Override
@@ -232,7 +282,7 @@ public class GrpcOperation extends OperationPartial {
          * construct the request first so that we don't have to clean up the "client" if
          * an exception is thrown
          */
-        ExecutionServiceInput request = constructRequest(params);
+        ExecutionServiceInput request = constructRequest();
 
         CompletableFuture<OperationOutcome> future = new CompletableFuture<>();
 
@@ -255,10 +305,9 @@ public class GrpcOperation extends OperationPartial {
      * enriched parameters. TO-DO: Avoid leaking Exceptions to the Kie Session thread. TBD
      * item for Frankfurt release.
      *
-     * @param params the control loop parameters specifying the onset, payload, etc.
      * @return an ExecutionServiceInput instance.
      */
-    public ExecutionServiceInput constructRequest(ControlLoopOperationParams params) {
+    public ExecutionServiceInput constructRequest() {
 
         // For the current operational TOSCA policy model (yaml) CBA name and version are
         // embedded in the payload
@@ -295,8 +344,9 @@ public class GrpcOperation extends OperationPartial {
         request.setAaiProperties(aaiConverter.get());
 
         // Inject any additional event parameters that may be present in the onset event
-        if (params.getContext().getEvent().getAdditionalEventParams() != null) {
-            request.setAdditionalEventParams(params.getContext().getEvent().getAdditionalEventParams());
+        Map<String, String> additionalParams = getAdditionalEventParams();
+        if (additionalParams != null) {
+            request.setAdditionalEventParams(additionalParams);
         }
 
         Builder struct = Struct.newBuilder();
@@ -324,6 +374,14 @@ public class GrpcOperation extends OperationPartial {
                         .setPayload(struct.build()).build();
     }
 
+    protected Map<String, String> getAdditionalEventParams() {
+        if (containsProperty(OperationProperties.EVENT_ADDITIONAL_PARAMS)) {
+            return getProperty(OperationProperties.EVENT_ADDITIONAL_PARAMS);
+        }
+
+        return params.getContext().getEvent().getAdditionalEventParams();
+    }
+
     private Map<String, String> convertPayloadMap(Map<String, Object> payload) {
         Map<String, String> convertedPayload = new HashMap<>();
         for (Entry<String, Object> entry : payload.entrySet()) {
index 06f239b..2e9935f 100644 (file)
@@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -31,6 +32,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -49,6 +51,7 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.Pnf;
 import org.onap.aai.domain.yang.ServiceInstance;
 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput;
@@ -187,6 +190,37 @@ public class GrpcOperationTest {
         assertTrue(outcome.getResponse() instanceof ExecutionServiceOutput);
     }
 
+    /**
+     * Tests "success" case with simulator using properties.
+     */
+    @Test
+    public void testSuccessViaProperties() throws Exception {
+        ControlLoopEventContext context = new ControlLoopEventContext(onset);
+        loadCqData(context);
+
+        Map<String, Object> payload = Map.of("artifact_name", "my_artifact", "artifact_version", "1.0");
+
+        params = ControlLoopOperationParams.builder()
+                        .actor(CdsActorConstants.CDS_ACTOR).operation("subscribe").context(context)
+                        .actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target).retry(0)
+                        .timeoutSec(5).executor(blockingExecutor).payload(payload).preprocessed(true).build();
+
+        cdsProps.setHost("localhost");
+        cdsProps.setPort(sim.getPort());
+        cdsProps.setTimeout(3);
+
+        GrpcConfig config = new GrpcConfig(blockingExecutor, cdsProps);
+
+        operation = new GrpcOperation(params, config);
+
+        // set the properties
+        operation.setProperty(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES, Collections.emptyMap());
+
+        OperationOutcome outcome = operation.start().get();
+        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+        assertTrue(outcome.getResponse() instanceof ExecutionServiceOutput);
+    }
+
     @Test
     public void testGetPropertyNames() {
 
@@ -198,9 +232,10 @@ public class GrpcOperationTest {
         // @formatter:off
         assertThat(operation.getPropertyNames()).isEqualTo(
                         List.of(
-                            OperationProperties.AAI_MODEL_INVARIANT_GENERIC_VNF,
-                            OperationProperties.AAI_RESOURCE_SERVICE_INSTANCE,
-                            OperationProperties.EVENT_ADDITIONAL_PARAMS));
+                            OperationProperties.AAI_RESOURCE_VNF,
+                            OperationProperties.AAI_SERVICE,
+                            OperationProperties.EVENT_ADDITIONAL_PARAMS,
+                            OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES));
         // @formatter:on
 
         /*
@@ -213,10 +248,76 @@ public class GrpcOperationTest {
         assertThat(operation.getPropertyNames()).isEqualTo(
                         List.of(
                             OperationProperties.AAI_PNF,
-                            OperationProperties.EVENT_ADDITIONAL_PARAMS));
+                            OperationProperties.EVENT_ADDITIONAL_PARAMS,
+                            OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES));
         // @formatter:on
     }
 
+    @Test
+    public void testGetPnf() {
+        ControlLoopEventContext context = new ControlLoopEventContext(onset);
+        params = params.toBuilder().context(context).build();
+        operation = new GrpcOperation(params, config);
+
+        // in neither property nor context
+        assertThatIllegalArgumentException().isThrownBy(() -> operation.getPnfData())
+                        .withMessage("missing PNF data");
+
+        // only in context
+        Pnf pnf = new Pnf();
+        params.getContext().setProperty(AaiGetPnfOperation.getKey(params.getTargetEntity()), pnf);
+        assertSame(pnf, operation.getPnfData());
+
+        // both - should choose the property
+        Pnf pnf2 = new Pnf();
+        operation.setProperty(OperationProperties.AAI_PNF, pnf2);
+        assertSame(pnf2, operation.getPnfData());
+    }
+
+    @Test
+    public void testGetServiceInstanceId() {
+        ControlLoopEventContext context = new ControlLoopEventContext(onset);
+        params = params.toBuilder().context(context).build();
+        operation = new GrpcOperation(params, config);
+
+        // in neither property nor custom query
+        context.setProperty(AaiCqResponse.CONTEXT_KEY, mock(AaiCqResponse.class));
+        assertThatIllegalArgumentException().isThrownBy(() -> operation.getServiceInstanceId())
+                        .withMessage("Target service instance could not be found");
+
+        // only in custom query
+        loadCqData(params.getContext());
+        assertEquals(MY_SVC_ID, operation.getServiceInstanceId());
+
+        // both - should choose the property
+        ServiceInstance serviceInstance = new ServiceInstance();
+        serviceInstance.setServiceInstanceId("another-service-id");
+        operation.setProperty(OperationProperties.AAI_SERVICE, serviceInstance);
+        assertEquals("another-service-id", operation.getServiceInstanceId());
+    }
+
+    @Test
+    public void testGetVnfId() {
+        ControlLoopEventContext context = new ControlLoopEventContext(onset);
+        params = params.toBuilder().context(context).build();
+        operation = new GrpcOperation(params, config);
+
+        // in neither property nor custom query
+        context.setProperty(AaiCqResponse.CONTEXT_KEY, mock(AaiCqResponse.class));
+        assertThatIllegalArgumentException().isThrownBy(() -> operation.getVnfId())
+                        .withMessage("Target generic vnf could not be found");
+
+        // only in custom query
+        loadCqData(params.getContext());
+        assertEquals(MY_VNF, operation.getVnfId());
+
+        // both - should choose the property
+        GenericVnf vnf = new GenericVnf();
+        vnf.setVnfId("another-vnf-id");
+        operation.setProperty(OperationProperties.AAI_RESOURCE_VNF, vnf);
+        assertEquals("another-vnf-id", operation.getVnfId());
+    }
+
     @Test
     public void testStartPreprocessorAsync() throws InterruptedException, ExecutionException, TimeoutException {
         AtomicBoolean guardStarted = new AtomicBoolean();
@@ -317,6 +418,29 @@ public class GrpcOperationTest {
         assertThatIllegalArgumentException().isThrownBy(() -> operation.startOperationAsync(1, params.makeOutcome()));
     }
 
+    @Test
+    public void testGetAdditionalEventParams() {
+        operation = new GrpcOperation(params, config);
+
+        // in neither property nor context
+        assertNull(operation.getAdditionalEventParams());
+
+        final Map<String, String> eventParams = Collections.emptyMap();
+
+        // only in context
+        onset.setAdditionalEventParams(eventParams);
+        assertSame(eventParams, operation.getAdditionalEventParams());
+
+        // both - should choose the property, even if it's null
+        operation.setProperty(OperationProperties.EVENT_ADDITIONAL_PARAMS, null);
+        assertNull(operation.getAdditionalEventParams());
+
+        // both - should choose the property
+        final Map<String, String> propParams = Collections.emptyMap();
+        operation.setProperty(OperationProperties.EVENT_ADDITIONAL_PARAMS, propParams);
+        assertSame(propParams, operation.getAdditionalEventParams());
+    }
+
     private void verifyOperation(ControlLoopEventContext context) {
 
         Map<String, Object> payloadMap = Map.of(CdsActorConstants.KEY_CBA_NAME, CDS_BLUEPRINT_NAME,
index 434b3b9..d2a1536 100644 (file)
@@ -23,7 +23,6 @@ package org.onap.policy.controlloop.actor.sdnc;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
-import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 import org.onap.policy.sdnc.SdncHealRequest;
@@ -38,15 +37,18 @@ import org.onap.policy.sdnc.SdncHealVnfInfo;
 import org.onap.policy.sdnc.SdncRequest;
 
 public class BandwidthOnDemandOperation extends SdncOperation {
+
     public static final String NAME = "BandwidthOnDemand";
 
     // fields in the enrichment data
     public static final String SERVICE_ID_KEY = "service-instance.service-instance-id";
+    public static final String BANDWIDTH = "bandwidth";
+    public static final String BANDWIDTH_CHANGE_TIME = "bandwidth-change-time";
     public static final String VNF_ID = "vnfId";
 
     // @formatter:off
     private static final List<String> PROPERTY_NAMES = List.of(
-                            OperationProperties.ENRICHMENT_SERVICE_INSTANCE_ID,
+                            OperationProperties.ENRICHMENT_SERVICE_ID,
                             OperationProperties.ENRICHMENT_BANDWIDTH,
                             OperationProperties.ENRICHMENT_BANDWIDTH_CHANGE_TIME,
                             OperationProperties.ENRICHMENT_VNF_ID);
@@ -64,20 +66,18 @@ public class BandwidthOnDemandOperation extends SdncOperation {
 
     @Override
     protected SdncRequest makeRequest(int attempt) {
-        ControlLoopEventContext context = params.getContext();
-
-        String serviceInstance = context.getEnrichment().get(SERVICE_ID_KEY);
+        String serviceInstance = getOptProperty(OperationProperties.ENRICHMENT_SERVICE_ID, SERVICE_ID_KEY);
         if (StringUtils.isBlank(serviceInstance)) {
             throw new IllegalArgumentException("missing enrichment data, " + SERVICE_ID_KEY);
         }
 
         SdncHealVfModuleParameter bandwidth = new SdncHealVfModuleParameter();
-        bandwidth.setName("bandwidth");
-        bandwidth.setValue(context.getEnrichment().get("bandwidth"));
+        bandwidth.setName(BANDWIDTH);
+        bandwidth.setValue(getOptProperty(OperationProperties.ENRICHMENT_BANDWIDTH, BANDWIDTH));
 
         SdncHealVfModuleParameter timeStamp = new SdncHealVfModuleParameter();
-        timeStamp.setName("bandwidth-change-time");
-        timeStamp.setValue(context.getEnrichment().get("bandwidth-change-time"));
+        timeStamp.setName(BANDWIDTH_CHANGE_TIME);
+        timeStamp.setValue(getOptProperty(OperationProperties.ENRICHMENT_BANDWIDTH_CHANGE_TIME, BANDWIDTH_CHANGE_TIME));
 
         SdncHealVfModuleParametersInfo vfParametersInfo = new SdncHealVfModuleParametersInfo();
         vfParametersInfo.addParameters(bandwidth);
@@ -102,7 +102,7 @@ public class BandwidthOnDemandOperation extends SdncOperation {
         request.setUrl("/" + getPath());
 
         SdncHealVnfInfo vnfInfo = new SdncHealVnfInfo();
-        vnfInfo.setVnfId(context.getEnrichment().get(VNF_ID));
+        vnfInfo.setVnfId(getOptProperty(OperationProperties.ENRICHMENT_VNF_ID, VNF_ID));
 
         SdncHealVfModuleInfo vfModuleInfo = new SdncHealVfModuleInfo();
         vfModuleInfo.setVfModuleId("");
index d26fad8..105a276 100644 (file)
@@ -23,7 +23,6 @@ package org.onap.policy.controlloop.actor.sdnc;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
-import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 import org.onap.policy.sdnc.SdncHealNetworkInfo;
@@ -58,16 +57,14 @@ public class RerouteOperation extends SdncOperation {
 
     @Override
     protected SdncRequest makeRequest(int attempt) {
-        ControlLoopEventContext context = params.getContext();
-
-        String serviceInstance = context.getEnrichment().get(SERVICE_ID_KEY);
+        String serviceInstance = getOptProperty(OperationProperties.ENRICHMENT_SERVICE_ID, SERVICE_ID_KEY);
         if (StringUtils.isBlank(serviceInstance)) {
             throw new IllegalArgumentException("missing enrichment data, " + SERVICE_ID_KEY);
         }
         SdncHealServiceInfo serviceInfo = new SdncHealServiceInfo();
         serviceInfo.setServiceInstanceId(serviceInstance);
 
-        String networkId = context.getEnrichment().get(NETWORK_ID_KEY);
+        String networkId = getOptProperty(OperationProperties.ENRICHMENT_NETWORK_ID, NETWORK_ID_KEY);
         if (StringUtils.isBlank(networkId)) {
             throw new IllegalArgumentException("missing enrichment data, " + NETWORK_ID_KEY);
         }
index 4d8e35e..defbcfb 100644 (file)
@@ -96,4 +96,21 @@ public abstract class SdncOperation extends HttpOperation<SdncResponse> {
     protected boolean isSuccess(Response rawResponse, SdncResponse response) {
         return response.getResponseOutput() != null && "200".equals(response.getResponseOutput().getResponseCode());
     }
+
+    /**
+     * Gets an optional property, first checking the properties, then checking the
+     * enrichment data.
+     *
+     * @param propName property name
+     * @param enrichmentName property name within the enrichment data
+     * @return the property's value, or {@code null} if it is not found
+     */
+    protected String getOptProperty(String propName, String enrichmentName) {
+        if (containsProperty(propName)) {
+            // return the value, even if it's null
+            return getProperty(propName);
+        }
+
+        return params.getContext().getEnrichment().get(enrichmentName);
+    }
 }
index 56b64e4..f80299f 100644 (file)
@@ -32,6 +32,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
 import org.onap.policy.controlloop.policy.PolicyResult;
@@ -39,6 +40,10 @@ import org.onap.policy.sdnc.SdncRequest;
 import org.onap.policy.sdnc.SdncResponse;
 
 public class BandwidthOnDemandOperationTest extends BasicSdncOperation {
+    private static final String MY_SERVICE = "my-service";
+    private static final String MY_VNF = "my-vnf";
+    private static final String MY_BANDWIDTH = "my-bandwidth";
+    private static final String MY_CHANGE_TIME = "my-change-time";
 
     private BandwidthOnDemandOperation oper;
 
@@ -76,7 +81,7 @@ public class BandwidthOnDemandOperationTest extends BasicSdncOperation {
         // @formatter:off
         assertThat(oper.getPropertyNames()).isEqualTo(
                         List.of(
-                            OperationProperties.ENRICHMENT_SERVICE_INSTANCE_ID,
+                            OperationProperties.ENRICHMENT_SERVICE_ID,
                             OperationProperties.ENRICHMENT_BANDWIDTH,
                             OperationProperties.ENRICHMENT_BANDWIDTH_CHANGE_TIME,
                             OperationProperties.ENRICHMENT_VNF_ID));
@@ -93,9 +98,14 @@ public class BandwidthOnDemandOperationTest extends BasicSdncOperation {
                         .path("GENERIC-RESOURCE-API:vf-module-topology-operation").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
         oper = new BandwidthOnDemandOperation(params, config);
 
+        oper.setProperty(OperationProperties.ENRICHMENT_SERVICE_ID, MY_SERVICE);
+        oper.setProperty(OperationProperties.ENRICHMENT_BANDWIDTH, MY_BANDWIDTH);
+        oper.setProperty(OperationProperties.ENRICHMENT_BANDWIDTH_CHANGE_TIME, MY_CHANGE_TIME);
+        oper.setProperty(OperationProperties.ENRICHMENT_VNF_ID, MY_VNF);
+
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
         assertTrue(outcome.getResponse() instanceof SdncResponse);
@@ -105,7 +115,7 @@ public class BandwidthOnDemandOperationTest extends BasicSdncOperation {
     public void testMakeRequest() throws Exception {
         oper.generateSubRequestId(1);
         SdncRequest request = oper.makeRequest(1);
-        assertEquals("my-service", request.getNsInstanceId());
+        assertEquals(MY_SERVICE, request.getNsInstanceId());
         assertEquals(REQ_ID, request.getRequestId());
         assertEquals("/my-path/", request.getUrl());
         assertEquals(oper.getSubRequestId(), request.getHealRequest().getRequestHeaderInfo().getSvcRequestId());
@@ -119,9 +129,26 @@ public class BandwidthOnDemandOperationTest extends BasicSdncOperation {
         verifyRequest("bod.json", verifyOperation(oper), IGNORE_FIELDS);
     }
 
+    @Test
+    public void testMakeRequestViaProperties() throws Exception {
+        // clear the enrichment data and remake the operation
+        event.setAai(null);
+        context = new ControlLoopEventContext(event);
+        params = params.toBuilder().context(context).build();
+        oper = new BandwidthOnDemandOperation(params, config);
+
+        oper.setProperty(OperationProperties.ENRICHMENT_SERVICE_ID, MY_SERVICE);
+        oper.setProperty(OperationProperties.ENRICHMENT_BANDWIDTH, MY_BANDWIDTH);
+        oper.setProperty(OperationProperties.ENRICHMENT_BANDWIDTH_CHANGE_TIME, MY_CHANGE_TIME);
+        oper.setProperty(OperationProperties.ENRICHMENT_VNF_ID, MY_VNF);
+
+        verifyRequest("bod.json", verifyOperation(oper), IGNORE_FIELDS);
+    }
+
     @Override
     protected Map<String, String> makeEnrichment() {
-        return Map.of(BandwidthOnDemandOperation.SERVICE_ID_KEY, "my-service", BandwidthOnDemandOperation.VNF_ID,
-                        "my-vnf");
+        return Map.of(BandwidthOnDemandOperation.SERVICE_ID_KEY, MY_SERVICE, BandwidthOnDemandOperation.BANDWIDTH,
+                        MY_BANDWIDTH, BandwidthOnDemandOperation.BANDWIDTH_CHANGE_TIME, MY_CHANGE_TIME,
+                        BandwidthOnDemandOperation.VNF_ID, MY_VNF);
     }
 }
index 9f06805..b71e567 100644 (file)
@@ -32,6 +32,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
 import org.onap.policy.controlloop.policy.PolicyResult;
@@ -39,6 +40,8 @@ import org.onap.policy.sdnc.SdncRequest;
 import org.onap.policy.sdnc.SdncResponse;
 
 public class RerouteOperationTest extends BasicSdncOperation {
+    private static final String MY_SERVICE = "my-service";
+    private static final String MY_NETWORK = "my-network";
 
     private RerouteOperation oper;
 
@@ -74,9 +77,12 @@ public class RerouteOperationTest extends BasicSdncOperation {
                         .path("GENERIC-RESOURCE-API:network-topology-operation").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
         oper = new RerouteOperation(params, config);
 
+        oper.setProperty(OperationProperties.ENRICHMENT_SERVICE_ID, MY_SERVICE);
+        oper.setProperty(OperationProperties.ENRICHMENT_NETWORK_ID, MY_NETWORK);
+
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
         assertTrue(outcome.getResponse() instanceof SdncResponse);
@@ -102,7 +108,7 @@ public class RerouteOperationTest extends BasicSdncOperation {
     public void testMakeRequest() throws Exception {
         oper.generateSubRequestId(1);
         SdncRequest request = oper.makeRequest(1);
-        assertEquals("my-service", request.getNsInstanceId());
+        assertEquals(MY_SERVICE, request.getNsInstanceId());
         assertEquals(REQ_ID, request.getRequestId());
         assertEquals("/my-path/", request.getUrl());
         assertEquals(oper.getSubRequestId(), request.getHealRequest().getRequestHeaderInfo().getSvcRequestId());
@@ -117,8 +123,22 @@ public class RerouteOperationTest extends BasicSdncOperation {
         verifyRequest("reroute.json", verifyOperation(oper), IGNORE_FIELDS);
     }
 
+    @Test
+    public void testMakeRequestViaProperties() throws Exception {
+        // clear the enrichment data and remake the operation
+        event.setAai(null);
+        context = new ControlLoopEventContext(event);
+        params = params.toBuilder().context(context).build();
+        oper = new RerouteOperation(params, config);
+
+        oper.setProperty(OperationProperties.ENRICHMENT_SERVICE_ID, MY_SERVICE);
+        oper.setProperty(OperationProperties.ENRICHMENT_NETWORK_ID, MY_NETWORK);
+
+        verifyRequest("reroute.json", verifyOperation(oper), IGNORE_FIELDS);
+    }
+
     @Override
     protected Map<String, String> makeEnrichment() {
-        return Map.of(RerouteOperation.SERVICE_ID_KEY, "my-service", RerouteOperation.NETWORK_ID_KEY, "my-network");
+        return Map.of(RerouteOperation.SERVICE_ID_KEY, MY_SERVICE, RerouteOperation.NETWORK_ID_KEY, MY_NETWORK);
     }
 }
index fb9f71b..4ba12c6 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.policy.controlloop.actor.sdnc;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Collections;
@@ -30,6 +31,7 @@ import java.util.Map;
 import java.util.TreeMap;
 import org.junit.Before;
 import org.junit.Test;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.sdnc.SdncHealRequest;
 import org.onap.policy.sdnc.SdncHealRequestHeaderInfo;
 import org.onap.policy.sdnc.SdncRequest;
@@ -101,6 +103,44 @@ public class SdncOperationTest extends BasicSdncOperation {
         assertFalse(oper.isSuccess(null, response));
     }
 
+    @Test
+    public void testGetOptProperty() {
+        // in neither property nor enrichment
+        assertNull(oper.getOptProperty("propA", "propA2"));
+
+        // both - should choose the property
+        remakeOper(Map.of("propB2", "valueB2"));
+        oper.setProperty("propB", "valueB");
+        assertEquals("valueB", oper.getOptProperty("propB", "propB2"));
+
+        // both - should choose the property, even if it's null
+        remakeOper(Map.of("propC2", "valueC2"));
+        oper.setProperty("propC", null);
+        assertNull(oper.getOptProperty("propC", "propC2"));
+
+        // only in enrichment data
+        remakeOper(Map.of("propD2", "valueD2"));
+        assertEquals("valueD2", oper.getOptProperty("propD", "propD2"));
+    }
+
+    /**
+     * Remakes the operation, with the specified A&AI enrichment data.
+     *
+     * @param aai A&AI enrichment data
+     */
+    private void remakeOper(Map<String, String> aai) {
+        event.setAai(aai);
+        context = new ControlLoopEventContext(event);
+        params = params.toBuilder().context(context).build();
+
+        oper = new SdncOperation(params, config, Collections.emptyList()) {
+            @Override
+            protected SdncRequest makeRequest(int attempt) {
+                return request;
+            }
+        };
+    }
+
     @Override
     protected Map<String, String> makeEnrichment() {
         return new TreeMap<>();
index 8c60bbd..8d3545e 100644 (file)
       "vf-module-input-parameters": {
         "param": [
           {
-            "name": "bandwidth"
+            "name": "bandwidth",
+            "value": "my-bandwidth"
           },
           {
-            "name": "bandwidth-change-time"
+            "name": "bandwidth-change-time",
+            "value": "my-change-time"
           }
         ]
       }
index f88f3c3..4511cc3 100644 (file)
@@ -46,7 +46,7 @@ public class SdnrOperation extends BidirectionalTopicOperation<PciMessage, PciMe
      */
     public static final String NAME = "any";
 
-    private static final List<String> PROPERTY_NAMES = List.of(OperationProperties.AAI_VSERVER_LINK);
+    private static final List<String> PROPERTY_NAMES = List.of(OperationProperties.EVENT_PAYLOAD);
 
     /**
      * Keys used to match the response with the request listener. The sub request ID is a
@@ -156,7 +156,7 @@ public class SdnrOperation extends BidirectionalTopicOperation<PciMessage, PciMe
         requestCommonHeader.setSubRequestId(subRequestId);
 
         sdnrRequest.setCommonHeader(requestCommonHeader);
-        sdnrRequest.setPayload(params.getContext().getEvent().getPayload());
+        sdnrRequest.setPayload(getEventPayload());
         sdnrRequest.setAction(params.getOperation());
 
         /*
@@ -169,4 +169,18 @@ public class SdnrOperation extends BidirectionalTopicOperation<PciMessage, PciMe
         /* Return the request to be sent through dmaap. */
         return dmaapRequest;
     }
+
+    /**
+     * Gets the event payload, first checking for it in the properties and then in the
+     * event.
+     *
+     * @return the event payload
+     */
+    protected String getEventPayload() {
+        if (containsProperty(OperationProperties.EVENT_PAYLOAD)) {
+            return getProperty(OperationProperties.EVENT_PAYLOAD);
+        }
+
+        return params.getContext().getEvent().getPayload();
+    }
 }
index 8ec1e4a..abce210 100644 (file)
@@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -90,7 +91,7 @@ public class SdnrOperationTest extends BasicSdnrOperation {
 
     @Test
     public void testGetPropertyNames() {
-        assertThat(operation.getPropertyNames()).isEqualTo(List.of(OperationProperties.AAI_VSERVER_LINK));
+        assertThat(operation.getPropertyNames()).isEqualTo(List.of(OperationProperties.EVENT_PAYLOAD));
     }
 
     @Test
@@ -235,6 +236,24 @@ public class SdnrOperationTest extends BasicSdnrOperation {
         checkOutcome();
     }
 
+    @Test
+    public void testGetEventPayload() {
+        // in neither property nor event
+        assertNull(operation.getEventPayload());
+
+        // only in event
+        event.setPayload("valueA2");
+        assertEquals("valueA2", operation.getEventPayload());
+
+        // both - should choose the property
+        operation.setProperty(OperationProperties.EVENT_PAYLOAD, "valueB");
+        assertEquals("valueB", operation.getEventPayload());
+
+        // both - should choose the property, even if it's null
+        operation.setProperty(OperationProperties.EVENT_PAYLOAD, null);
+        assertNull(operation.getEventPayload());
+    }
+
     protected void checkOutcome() {
         assertSame(outcome, operation.setOutcome(outcome, PolicyResult.SUCCESS, response));
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
index f269ea0..8f0dda3 100644 (file)
@@ -29,10 +29,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 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;
@@ -43,6 +45,7 @@ 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.HttpPollingConfig;
@@ -170,10 +173,19 @@ public abstract class SoOperation extends HttpOperation<SoResponse> {
     }
 
     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);
     }
 
@@ -370,45 +382,77 @@ public abstract class SoOperation extends HttpOperation<SoResponse> {
         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> T getItem(String propName, Function<AaiCqResponse, T> 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
index 4bae1e8..7e95bda 100644 (file)
@@ -29,6 +29,7 @@ import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.tuple.Pair;
 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;
@@ -61,10 +62,12 @@ public class VfModuleCreate extends SoOperation {
 
     // @formatter:off
     private static final List<String> PROPERTY_NAMES = List.of(
-                            OperationProperties.AAI_MODEL_SERVICE,
-                            OperationProperties.AAI_MODEL_VNF,
-                            OperationProperties.AAI_MODEL_CLOUD_REGION,
-                            OperationProperties.AAI_MODEL_TENANT,
+                            OperationProperties.AAI_SERVICE,
+                            OperationProperties.AAI_SERVICE_MODEL,
+                            OperationProperties.AAI_VNF,
+                            OperationProperties.AAI_VNF_MODEL,
+                            OperationProperties.AAI_DEFAULT_CLOUD_REGION,
+                            OperationProperties.AAI_DEFAULT_TENANT,
                             OperationProperties.DATA_VF_COUNT);
     // @formatter:off
 
@@ -156,12 +159,13 @@ public class VfModuleCreate extends SoOperation {
      * @return a pair containing the request URL and the new request
      */
     protected Pair<String, SoRequest> makeRequest() {
-        final AaiCqResponse aaiCqResponse = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY);
         final SoModelInfo soModelInfo = prepareSoModelInfo();
-        final GenericVnf vnfItem = getVnfItem(aaiCqResponse, soModelInfo);
-        final ServiceInstance vnfServiceItem = getServiceInstance(aaiCqResponse);
-        final Tenant tenantItem = getDefaultTenant(aaiCqResponse);
-        final CloudRegion cloudRegionItem = getDefaultCloudRegion(aaiCqResponse);
+        final GenericVnf vnfItem = getVnfItem(soModelInfo);
+        final ServiceInstance vnfServiceItem = getServiceInstance();
+        final Tenant tenantItem = getDefaultTenant();
+        final CloudRegion cloudRegionItem = getDefaultCloudRegion();
+        final ModelVer vnfModel = getVnfModel(vnfItem);
+        final ModelVer vnfServiceModel = getServiceModel(vnfServiceItem);
 
         SoRequest request = new SoRequest();
         request.setOperationType(SoOperationType.SCALE_OUT);
@@ -198,10 +202,8 @@ public class VfModuleCreate extends SoOperation {
                         .setModelInvariantId(vnfServiceItem.getModelInvariantId());
         relatedInstanceListElement1.getRelatedInstance().getModelInfo()
                         .setModelVersionId(vnfServiceItem.getModelVersionId());
-        relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName(
-                        aaiCqResponse.getModelVerByVersionId(vnfServiceItem.getModelVersionId()).getModelName());
-        relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelVersion(
-                        aaiCqResponse.getModelVerByVersionId(vnfServiceItem.getModelVersionId()).getModelVersion());
+        relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName(vnfModel.getModelName());
+        relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelVersion(vnfModel.getModelVersion());
 
         // VNF Item
         relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getVnfId());
@@ -211,10 +213,9 @@ public class VfModuleCreate extends SoOperation {
                         .setModelInvariantId(vnfItem.getModelInvariantId());
         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelVersionId(vnfItem.getModelVersionId());
 
+        relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelName(vnfServiceModel.getModelName());
         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
-                        .setModelName(aaiCqResponse.getModelVerByVersionId(vnfItem.getModelVersionId()).getModelName());
-        relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelVersion(
-                        aaiCqResponse.getModelVerByVersionId(vnfItem.getModelVersionId()).getModelVersion());
+                        .setModelVersion(vnfServiceModel.getModelVersion());
 
         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
                         .setModelCustomizationId(vnfItem.getModelCustomizationId());
index 7db76d2..0ff833c 100644 (file)
@@ -70,10 +70,10 @@ public class VfModuleDelete extends SoOperation {
 
     // @formatter:off
     private static final List<String> PROPERTY_NAMES = List.of(
-                            OperationProperties.AAI_MODEL_SERVICE,
-                            OperationProperties.AAI_MODEL_VNF,
-                            OperationProperties.AAI_MODEL_CLOUD_REGION,
-                            OperationProperties.AAI_MODEL_TENANT,
+                            OperationProperties.AAI_SERVICE,
+                            OperationProperties.AAI_VNF,
+                            OperationProperties.AAI_DEFAULT_CLOUD_REGION,
+                            OperationProperties.AAI_DEFAULT_TENANT,
                             OperationProperties.DATA_VF_COUNT);
     // @formatter:on
 
@@ -239,12 +239,11 @@ public class VfModuleDelete extends SoOperation {
      * @return a pair containing the request URL and the new request
      */
     protected Pair<String, SoRequest> makeRequest() {
-        final AaiCqResponse aaiCqResponse = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY);
         final SoModelInfo soModelInfo = prepareSoModelInfo();
-        final GenericVnf vnfItem = getVnfItem(aaiCqResponse, soModelInfo);
-        final ServiceInstance vnfServiceItem = getServiceInstance(aaiCqResponse);
-        final Tenant tenantItem = getDefaultTenant(aaiCqResponse);
-        final CloudRegion cloudRegionItem = getDefaultCloudRegion(aaiCqResponse);
+        final GenericVnf vnfItem = getVnfItem(soModelInfo);
+        final ServiceInstance vnfServiceItem = getServiceInstance();
+        final Tenant tenantItem = getDefaultTenant();
+        final CloudRegion cloudRegionItem = getDefaultCloudRegion();
 
         SoRequest request = new SoRequest();
         request.setOperationType(SoOperationType.DELETE_VF_MODULE);
index 7314c59..e364246 100644 (file)
@@ -36,12 +36,14 @@ import java.time.Month;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 import org.junit.Before;
 import org.junit.Test;
 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.AaiCqResponse;
@@ -49,6 +51,7 @@ import org.onap.policy.common.utils.coder.Coder;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.controlloop.ControlLoopOperation;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.policy.PolicyResult;
 import org.onap.policy.so.SoModelInfo;
 import org.onap.policy.so.SoRequest;
@@ -63,6 +66,8 @@ public class SoOperationTest extends BasicSoOperation {
 
     private static final List<String> PROP_NAMES = Collections.emptyList();
 
+    private static final String VERSION_ID = "1.2.3";
+
     private SoOperation oper;
 
     /**
@@ -139,6 +144,24 @@ public class SoOperationTest extends BasicSoOperation {
         assertEquals(VF_COUNT + 1, oper.getVfCount());
     }
 
+    /**
+     * Tests the VF Count methods when properties are being used.
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testGetVfCount_testSetVfCount_ViaProperties() throws Exception {
+        oper.setProperty(OperationProperties.DATA_VF_COUNT, VF_COUNT);
+
+        // verify that the count was stored
+        assertEquals(VF_COUNT.intValue(), oper.getVfCount());
+
+        oper.setVfCount(VF_COUNT + 1);
+
+        int count = oper.getProperty(OperationProperties.DATA_VF_COUNT);
+        assertEquals(VF_COUNT + 1, count);
+        assertEquals(VF_COUNT + 1, oper.getVfCount());
+    }
+
     /**
      * Tests obtainVfCount() when it actually has to query.
      */
@@ -286,55 +309,114 @@ public class SoOperationTest extends BasicSoOperation {
     }
 
     @Test
-    public void testGetVnfItem() {
-        // missing data
+    public void testGetItem() {
         AaiCqResponse cq = mock(AaiCqResponse.class);
-        assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfItem(cq, oper.prepareSoModelInfo()))
-                        .withMessage("missing generic VNF");
+        params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq);
 
-        // valid data
-        GenericVnf vnf = new GenericVnf();
-        when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf);
-        assertSame(vnf, oper.getVnfItem(cq, oper.prepareSoModelInfo()));
+        // in neither property nor custom query
+        assertThatIllegalArgumentException().isThrownBy(() -> oper.getItem("propA", cq2 -> null, "not found"))
+                        .withMessage("not found");
+
+        // only in custom query
+        assertEquals("valueB", oper.getItem("propB", cq2 -> "valueB", "failureB"));
+
+        // both - should choose the property
+        oper.setProperty("propC", "valueC");
+        assertEquals("valueC", oper.getItem("propC", cq2 -> "valueC2", "failureC"));
+
+        // both - should choose the property, even if it's null
+        oper.setProperty("propD", null);
+        assertNull(oper.getItem("propD", cq2 -> "valueD2", "failureD"));
     }
 
     @Test
-    public void testGetServiceInstance() {
-        // missing data
-        AaiCqResponse cq = mock(AaiCqResponse.class);
-        assertThatIllegalArgumentException().isThrownBy(() -> oper.getServiceInstance(cq))
-                        .withMessage("missing VNF Service Item");
+    public void testGetVnfItem() {
+        // @formatter:off
+        verifyItems(OperationProperties.AAI_VNF, GenericVnf::new,
+            (cq, instance) -> when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(instance),
+            () -> oper.getVnfItem(oper.prepareSoModelInfo()),
+            "missing generic VNF");
+        // @formatter:on
+    }
 
-        // valid data
-        ServiceInstance instance = new ServiceInstance();
-        when(cq.getServiceInstance()).thenReturn(instance);
-        assertSame(instance, oper.getServiceInstance(cq));
+    @Test
+    public void testGetServiceInstance() {
+        // @formatter:off
+        verifyItems(OperationProperties.AAI_SERVICE, ServiceInstance::new,
+            (cq, instance) -> when(cq.getServiceInstance()).thenReturn(instance),
+            () -> oper.getServiceInstance(),
+            "missing VNF Service Item");
+        // @formatter:on
     }
 
     @Test
     public void testGetDefaultTenant() {
-        // missing data
-        AaiCqResponse cq = mock(AaiCqResponse.class);
-        assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultTenant(cq))
-                        .withMessage("missing Tenant Item");
+        // @formatter:off
+        verifyItems(OperationProperties.AAI_DEFAULT_TENANT, Tenant::new,
+            (cq, tenant) -> when(cq.getDefaultTenant()).thenReturn(tenant),
+            () -> oper.getDefaultTenant(),
+            "missing Default Tenant Item");
+        // @formatter:on
+    }
 
-        // valid data
-        Tenant tenant = new Tenant();
-        when(cq.getDefaultTenant()).thenReturn(tenant);
-        assertSame(tenant, oper.getDefaultTenant(cq));
+    @Test
+    public void testGetVnfModel() {
+        GenericVnf vnf = new GenericVnf();
+        vnf.setModelVersionId(VERSION_ID);
+
+        // @formatter:off
+        verifyItems(OperationProperties.AAI_VNF_MODEL, ModelVer::new,
+            (cq, model) -> when(cq.getModelVerByVersionId(VERSION_ID)).thenReturn(model),
+            () -> oper.getVnfModel(vnf),
+            "missing generic VNF Model");
+        // @formatter:on
+    }
+
+    @Test
+    public void testGetServiceModel() {
+        ServiceInstance service = new ServiceInstance();
+        service.setModelVersionId(VERSION_ID);
+
+        // @formatter:off
+        verifyItems(OperationProperties.AAI_SERVICE_MODEL, ModelVer::new,
+            (cq, model) -> when(cq.getModelVerByVersionId(VERSION_ID)).thenReturn(model),
+            () -> oper.getServiceModel(service),
+            "missing Service Model");
+        // @formatter:on
     }
 
     @Test
     public void testGetDefaultCloudRegion() {
-        // missing data
+        // @formatter:off
+        verifyItems(OperationProperties.AAI_DEFAULT_CLOUD_REGION, CloudRegion::new,
+            (cq, region) -> when(cq.getDefaultCloudRegion()).thenReturn(region),
+            () -> oper.getDefaultCloudRegion(),
+            "missing Default Cloud Region");
+        // @formatter:on
+    }
+
+    private <T> void verifyItems(String propName, Supplier<T> maker, BiConsumer<AaiCqResponse, T> setter,
+                    Supplier<T> getter, String errmsg) {
+
         AaiCqResponse cq = mock(AaiCqResponse.class);
-        assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultCloudRegion(cq))
-                        .withMessage("missing Cloud Region");
+        params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq);
 
-        // valid data
-        CloudRegion region = new CloudRegion();
-        when(cq.getDefaultCloudRegion()).thenReturn(region);
-        assertSame(region, oper.getDefaultCloudRegion(cq));
+        // in neither property nor custom query
+        assertThatIllegalArgumentException().isThrownBy(getter::get).withMessage(errmsg);
+
+        // only in custom query
+        final T item1 = maker.get();
+        setter.accept(cq, item1);
+        assertSame(item1, getter.get());
+
+        // both - should choose the property
+        final T item2 = maker.get();
+        oper.setProperty(propName, item2);
+        assertSame(item2, getter.get());
+
+        // both - should choose the property, even if it's null
+        oper.setProperty(propName, null);
+        assertNull(getter.get());
     }
 
     @Test
index 012f8de..9d80343 100644 (file)
@@ -108,6 +108,51 @@ public class VfModuleCreateTest extends BasicSoOperation {
         assertTrue(outcome.getResponse() instanceof SoResponse);
     }
 
+    /**
+     * Tests "success" case with simulator, using properties instead of custom query data.
+     */
+    @Test
+    public void testSuccessViaProperties() throws Exception {
+        HttpPollingParams opParams = HttpPollingParams.builder().clientName(MY_CLIENT)
+                        .path("serviceInstantiation/v7/serviceInstances").pollPath("orchestrationRequests/v5/")
+                        .maxPolls(2).build();
+        config = new HttpPollingConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
+        params.getContext().removeProperty(AaiCqResponse.CONTEXT_KEY);
+
+        oper = new VfModuleCreate(params, config);
+
+        // set the properties
+        ServiceInstance instance = new ServiceInstance();
+        instance.setServiceInstanceId(SVC_INSTANCE_ID);
+        oper.setProperty(OperationProperties.AAI_SERVICE, instance);
+
+        ModelVer modelVers = new ModelVer();
+        modelVers.setModelName(MODEL_NAME2);
+        modelVers.setModelVersion(MODEL_VERS2);
+
+        oper.setProperty(OperationProperties.AAI_SERVICE_MODEL, modelVers);
+        oper.setProperty(OperationProperties.AAI_VNF_MODEL, modelVers);
+
+        GenericVnf vnf = new GenericVnf();
+        vnf.setVnfId(VNF_ID);
+        oper.setProperty(OperationProperties.AAI_VNF, vnf);
+
+        oper.setProperty(OperationProperties.AAI_DEFAULT_CLOUD_REGION, new CloudRegion());
+        oper.setProperty(OperationProperties.AAI_DEFAULT_TENANT, new Tenant());
+
+        oper.setProperty(OperationProperties.DATA_VF_COUNT, VF_COUNT);
+
+        // run the operation
+        outcome = oper.start().get();
+        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+        assertTrue(outcome.getResponse() instanceof SoResponse);
+
+        int count = oper.getProperty(OperationProperties.DATA_VF_COUNT);
+        assertEquals(VF_COUNT + 1, count);
+    }
+
     @Test
     public void testConstructor() {
         assertEquals(DEFAULT_ACTOR, oper.getActorName());
@@ -124,10 +169,12 @@ public class VfModuleCreateTest extends BasicSoOperation {
         // @formatter:off
         assertThat(oper.getPropertyNames()).isEqualTo(
                         List.of(
-                            OperationProperties.AAI_MODEL_SERVICE,
-                            OperationProperties.AAI_MODEL_VNF,
-                            OperationProperties.AAI_MODEL_CLOUD_REGION,
-                            OperationProperties.AAI_MODEL_TENANT,
+                            OperationProperties.AAI_SERVICE,
+                            OperationProperties.AAI_SERVICE_MODEL,
+                            OperationProperties.AAI_VNF,
+                            OperationProperties.AAI_VNF_MODEL,
+                            OperationProperties.AAI_DEFAULT_CLOUD_REGION,
+                            OperationProperties.AAI_DEFAULT_TENANT,
                             OperationProperties.DATA_VF_COUNT));
         // @formatter:on
     }
index cc2aafa..9335f01 100644 (file)
@@ -137,6 +137,43 @@ public class VfModuleDeleteTest extends BasicSoOperation {
         assertTrue(outcome.getResponse() instanceof SoResponse);
     }
 
+    /**
+     * Tests "success" case with simulator, using properties instead of custom query data.
+     */
+    @Test
+    public void testSuccessViaProperties() throws Exception {
+        HttpPollingParams opParams = HttpPollingParams.builder().clientName(MY_CLIENT).path("serviceInstances/v7")
+                        .pollPath("orchestrationRequests/v5/").maxPolls(2).build();
+        config = new HttpPollingConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
+        params.getContext().removeProperty(AaiCqResponse.CONTEXT_KEY);
+
+        oper = new VfModuleDelete(params, config);
+
+        // set the properties
+        ServiceInstance instance = new ServiceInstance();
+        instance.setServiceInstanceId(SVC_INSTANCE_ID);
+        oper.setProperty(OperationProperties.AAI_SERVICE, instance);
+
+        GenericVnf vnf = new GenericVnf();
+        vnf.setVnfId(VNF_ID);
+        oper.setProperty(OperationProperties.AAI_VNF, vnf);
+
+        oper.setProperty(OperationProperties.AAI_DEFAULT_CLOUD_REGION, new CloudRegion());
+        oper.setProperty(OperationProperties.AAI_DEFAULT_TENANT, new Tenant());
+
+        oper.setProperty(OperationProperties.DATA_VF_COUNT, VF_COUNT);
+
+        // run the operation
+        outcome = oper.start().get();
+        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+        assertTrue(outcome.getResponse() instanceof SoResponse);
+
+        int count = oper.getProperty(OperationProperties.DATA_VF_COUNT);
+        assertEquals(VF_COUNT - 1, count);
+    }
+
     @Test
     public void testConstructor() {
         assertEquals(DEFAULT_ACTOR, oper.getActorName());
@@ -153,10 +190,10 @@ public class VfModuleDeleteTest extends BasicSoOperation {
         // @formatter:off
         assertThat(oper.getPropertyNames()).isEqualTo(
                         List.of(
-                            OperationProperties.AAI_MODEL_SERVICE,
-                            OperationProperties.AAI_MODEL_VNF,
-                            OperationProperties.AAI_MODEL_CLOUD_REGION,
-                            OperationProperties.AAI_MODEL_TENANT,
+                            OperationProperties.AAI_SERVICE,
+                            OperationProperties.AAI_VNF,
+                            OperationProperties.AAI_DEFAULT_CLOUD_REGION,
+                            OperationProperties.AAI_DEFAULT_TENANT,
                             OperationProperties.DATA_VF_COUNT));
         // @formatter:on
     }
index 8bd4630..bb23fdc 100644 (file)
@@ -26,7 +26,6 @@ import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
-import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
@@ -48,7 +47,7 @@ public abstract class VfcOperation extends HttpOperation<VfcResponse> {
 
     // @formatter:off
     private static final List<String> PROPERTY_NAMES = List.of(
-                            OperationProperties.ENRICHMENT_SERVICE_INSTANCE_ID,
+                            OperationProperties.ENRICHMENT_SERVICE_ID,
                             OperationProperties.ENRICHMENT_VSERVER_ID,
                             OperationProperties.ENRICHMENT_VSERVER_NAME,
                             OperationProperties.ENRICHMENT_GENERIC_VNF_ID);
@@ -133,7 +132,7 @@ public abstract class VfcOperation extends HttpOperation<VfcResponse> {
      */
     protected String getRequestState(VfcResponse response) {
         if (response == null || response.getResponseDescriptor() == null
-                || StringUtils.isBlank(response.getResponseDescriptor().getStatus())) {
+                        || StringUtils.isBlank(response.getResponseDescriptor().getStatus())) {
             return null;
         }
         return response.getResponseDescriptor().getStatus();
@@ -153,7 +152,7 @@ public abstract class VfcOperation extends HttpOperation<VfcResponse> {
      */
     @Override
     public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, Response rawResponse,
-            VfcResponse response) {
+                    VfcResponse response) {
 
         // set default result and message
         setOutcome(outcome, result);
@@ -171,14 +170,16 @@ public abstract class VfcOperation extends HttpOperation<VfcResponse> {
      * @return request
      */
     protected VfcRequest constructVfcRequest() {
-        ControlLoopEventContext context = params.getContext();
-        String serviceInstance = context.getEnrichment().get("service-instance.service-instance-id");
-        String vmId = context.getEnrichment().get("vserver.vserver-id");
-        String vmName = context.getEnrichment().get("vserver.vserver-name");
+        final String serviceInstance = getOptProperty(OperationProperties.ENRICHMENT_SERVICE_ID,
+                        "service-instance.service-instance-id");
+        final String vmId = getOptProperty(OperationProperties.ENRICHMENT_VSERVER_ID, "vserver.vserver-id");
+        final String vmName = getOptProperty(OperationProperties.ENRICHMENT_VSERVER_NAME, "vserver.vserver-name");
+        final String vnfId = getOptProperty(OperationProperties.ENRICHMENT_GENERIC_VNF_ID, GENERIC_VNF_ID);
 
         if (StringUtils.isBlank(serviceInstance) || StringUtils.isBlank(vmId) || StringUtils.isBlank(vmName)) {
+            // original code did not check the VNF id, so we won't check it either
             throw new IllegalArgumentException(
-                    "Cannot extract enrichment data for service instance, server id, or server name.");
+                            "Cannot extract enrichment data for service instance, server id, or server name.");
         }
 
         VfcHealActionVmInfo vmActionInfo = new VfcHealActionVmInfo();
@@ -190,7 +191,7 @@ public abstract class VfcOperation extends HttpOperation<VfcResponse> {
         additionalParams.setActionInfo(vmActionInfo);
 
         VfcHealRequest healRequest = new VfcHealRequest();
-        healRequest.setVnfInstanceId(params.getContext().getEnrichment().get(GENERIC_VNF_ID));
+        healRequest.setVnfInstanceId(vnfId);
         healRequest.setCause(getName());
         healRequest.setAdditionalParams(additionalParams);
 
@@ -201,4 +202,21 @@ public abstract class VfcOperation extends HttpOperation<VfcResponse> {
 
         return request;
     }
+
+    /**
+     * Gets an optional property, first checking the properties, then checking the
+     * enrichment data.
+     *
+     * @param propName property name
+     * @param enrichmentName property name within the enrichment data
+     * @return the property's value, or {@code null} if it is not found
+     */
+    protected String getOptProperty(String propName, String enrichmentName) {
+        if (containsProperty(propName)) {
+            // return the value, even if it's null
+            return getProperty(propName);
+        }
+
+        return params.getContext().getEnrichment().get(enrichmentName);
+    }
 }
index 4666645..068ffda 100644 (file)
@@ -32,6 +32,7 @@ import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.onap.policy.aai.AaiCqResponse;
 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
@@ -42,8 +43,14 @@ import org.onap.policy.vfc.VfcRequest;
 import org.onap.policy.vfc.VfcResponse;
 
 public class RestartTest extends BasicVfcOperation {
+    private static final String TEST_SERVICE_INSTANCE_ID = "test-service-instance-id";
+    private static final String TEST_VSERVER_ID = "test-vserver-id";
+    private static final String TEST_VSERVER_NAME = "test-vserver-name";
+    private static final String TEST_GENERIC_VNF_ID = "test-generic-vnf-id";
+
     private Restart restartOper;
 
+
     @BeforeClass
     public static void setUpBeforeClass() throws Exception {
         initBeforeClass();
@@ -60,9 +67,9 @@ public class RestartTest extends BasicVfcOperation {
     @Before
     public void setup() throws Exception {
         super.setUp();
-        params.getContext().getEnrichment().put("service-instance.service-instance-id", "test-service-instance-id");
-        params.getContext().getEnrichment().put("vserver.vserver-id", "test-vserver-id");
-        params.getContext().getEnrichment().put("vserver.vserver-name", "test-vserver-name");
+        params.getContext().getEnrichment().put("service-instance.service-instance-id", TEST_SERVICE_INSTANCE_ID);
+        params.getContext().getEnrichment().put("vserver.vserver-id", TEST_VSERVER_ID);
+        params.getContext().getEnrichment().put("vserver.vserver-name", TEST_VSERVER_NAME);
         restartOper = new Restart(params, config);
     }
 
@@ -84,6 +91,32 @@ public class RestartTest extends BasicVfcOperation {
         assertTrue(outcome.getResponse() instanceof VfcResponse);
     }
 
+    /**
+     * Tests "success" case with simulator, using properties instead of custom query data.
+     */
+    @Test
+    public void testSuccessViaProperties() throws Exception {
+        HttpPollingParams opParams = HttpPollingParams.builder().clientName(MY_CLIENT).path("ns").pollPath("jobs")
+                        .maxPolls(1).build();
+        config = new HttpPollingConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
+        params.getContext().removeProperty(AaiCqResponse.CONTEXT_KEY);
+
+        restartOper = new Restart(params, config);
+
+        // set the properties
+        restartOper.setProperty(OperationProperties.ENRICHMENT_SERVICE_ID, TEST_SERVICE_INSTANCE_ID);
+        restartOper.setProperty(OperationProperties.ENRICHMENT_VSERVER_ID, TEST_VSERVER_ID);
+        restartOper.setProperty(OperationProperties.ENRICHMENT_VSERVER_NAME, TEST_VSERVER_NAME);
+        restartOper.setProperty(OperationProperties.ENRICHMENT_GENERIC_VNF_ID, TEST_GENERIC_VNF_ID);
+
+        // run the operation
+        outcome = restartOper.start().get();
+        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+        assertTrue(outcome.getResponse() instanceof VfcResponse);
+    }
+
     @Test
     public void testConstructor() {
         CompletableFuture<OperationOutcome> futureRes = restartOper.startOperationAsync(1, outcome);
@@ -96,7 +129,7 @@ public class RestartTest extends BasicVfcOperation {
         // @formatter:off
         assertThat(restartOper.getPropertyNames()).isEqualTo(
                         List.of(
-                            OperationProperties.ENRICHMENT_SERVICE_INSTANCE_ID,
+                            OperationProperties.ENRICHMENT_SERVICE_ID,
                             OperationProperties.ENRICHMENT_VSERVER_ID,
                             OperationProperties.ENRICHMENT_VSERVER_NAME,
                             OperationProperties.ENRICHMENT_GENERIC_VNF_ID));
index 425ff91..6f8956f 100644 (file)
@@ -26,9 +26,11 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.vfc.VfcResponse;
 import org.onap.policy.vfc.VfcResponseDescriptor;
 
@@ -87,4 +89,36 @@ public class VfcOperationTest extends BasicVfcOperation {
         assertTrue(oper.isSuccess(rawResponse, response));
     }
 
+    @Test
+    public void testGetOptProperty() {
+        // in neither property nor enrichment
+        assertNull(oper.getOptProperty("propA", "propA2"));
+
+        // both - should choose the property
+        remakeOper(Map.of("propB2", "valueB2"));
+        oper.setProperty("propB", "valueB");
+        assertEquals("valueB", oper.getOptProperty("propB", "propB2"));
+
+        // both - should choose the property, even if it's null
+        remakeOper(Map.of("propC2", "valueC2"));
+        oper.setProperty("propC", null);
+        assertNull(oper.getOptProperty("propC", "propC2"));
+
+        // only in enrichment data
+        remakeOper(Map.of("propD2", "valueD2"));
+        assertEquals("valueD2", oper.getOptProperty("propD", "propD2"));
+    }
+
+    /**
+     * Remakes the operation, with the specified A&AI enrichment data.
+     *
+     * @param aai A&AI enrichment data
+     */
+    private void remakeOper(Map<String, String> aai) {
+        event.setAai(aai);
+        context = new ControlLoopEventContext(event);
+        params = params.toBuilder().context(context).build();
+
+        oper = new VfcOperation(params, config) {};
+    }
 }
index 4284646..c36b61e 100644 (file)
@@ -25,28 +25,112 @@ package org.onap.policy.controlloop.actorserviceprovider;
  * exhaustive, as additional property names may be returned by company-defined Actors.
  */
 public class OperationProperties {
-    public static final String AAI_MODEL_CLOUD_REGION = "AAI/modelInvariantId/cloudRegion";
-    public static final String AAI_MODEL_INVARIANT_GENERIC_VNF = "AAI/modelInvariantId/genericVnf";
-    public static final String AAI_MODEL_SERVICE = "AAI/modelInvariantId/service";
-    public static final String AAI_MODEL_TENANT = "AAI/modelInvariantId/tenant";
-    public static final String AAI_MODEL_VNF = "AAI/modelInvariantId/vnf";
-    public static final String AAI_RESOURCE_SERVICE_INSTANCE = "AAI/resourceId/serviceInstanceId";
-    public static final String AAI_RESOURCE_VNF = "AAI/resourceId/modelInvariantId/vnf";
+
+    /**
+     * A&AI Default Cloud Region. Obtained as follows:
+     * <ol>
+     * <li>invoke the custom query getDefaultCloudRegion() method</li>
+     * </ol>
+     */
+    public static final String AAI_DEFAULT_CLOUD_REGION = "AAI/defaultCloudRegion";
+
+    /**
+     * A&AI Default Tenant. Obtained as follows:
+     * <ol>
+     * <li>invoke the custom query getDefaultTenant() method</li>
+     * </ol>
+     */
+    public static final String AAI_DEFAULT_TENANT = "AAI/defaultTenant";
+
+    /**
+     * A&AI Service instance. Obtained as follows:
+     * <ol>
+     * <li>invoke the custom query getServiceInstance() method</li>
+     * </ol>
+     */
+    public static final String AAI_SERVICE = "AAI/service";
+
+    /**
+     * A&AI Service model. Obtained as follows:
+     * <ol>
+     * <li>invoke the custom query getServiceInstance() method</li>
+     * <li>using the service instance, invoke the getModelVersionId() method</li>
+     * </ol>
+     */
+    public static final String AAI_SERVICE_MODEL = "AAI/service/model";
+
+    /**
+     * A&AI VNF. Obtained as follows:
+     * <ol>
+     * <li>using the target model invariant ID, invoke the custom query
+     * getGenericVnfByModelInvariantId() method to get the VNF</li>
+     * <li>using the VNF item, invoke the getModelVersionId() method to get the
+     * version</li>
+     * </ol>
+     */
+    public static final String AAI_VNF = "AAI/vnf";
+
+    /**
+     * A&AI VNF Model. Obtained as follows:
+     * <ol>
+     * <li>using the target model invariant ID, invoke the custom query
+     * getGenericVnfByModelInvariantId() method to get the VNF</li>
+     * <li>using the VNF item, invoke the getModelVersionId() method to get the
+     * version</li>
+     * <li>using the version, invoke the custom query getModelVerByVersionId() method</li>
+     * </ol>
+     */
+    public static final String AAI_VNF_MODEL = "AAI/vnf/model";
+
+    /**
+     * A&AI VNF id 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>
+     * </ol>
+     */
+    public static final String AAI_RESOURCE_VNF = "AAI/resourceId/vnf";
+
+    /**
+     * A&AI PNF. Obtained as follows:
+     * <ol>
+     * <li>using the target entity, invoke AaiGetPnfOperation</li>
+     * </ol>
+     */
     public static final String AAI_PNF = "AAI/pnf";
+
+    /**
+     * A&AI link to the vserver. Obtained as follows:
+     * <ol>
+     * <li>using the vserver name from the enrichment data, perform an A&AI tenant
+     * query</li>
+     * <li>get the "result-data" field from the tenant output</li>
+     * <li>get the "resource-link" field from that</li>
+     * <li>strip off the "/aai/v16" prefix</li>
+     * </ol>
+     */
     public static final String AAI_VSERVER_LINK = "AAI/vserver/link";
 
+    /**
+     * Optional A&AI properties (Map-String-String) for CDS GRPC. If an application
+     * provides this, it will be used instead of constructing the map from the other
+     * properties.
+     */
+    public static final String OPT_CDS_GRPC_AAI_PROPERTIES = "cds/grpc/aai/properties";
+
     /*
      * These are typically extracted from the event or from the event's enrichment data.
+     *
+     * NOTE: all of the values must be of the form "enrichment/{enrichment-field-name}".
      */
     public static final String ENRICHMENT_BANDWIDTH = "enrichment/bandwidth";
-    public static final String ENRICHMENT_BANDWIDTH_CHANGE_TIME = "enrichment/bandwidth/changeTime";
-    public static final String ENRICHMENT_GENERIC_VNF_ID = "enrichment/genericVnf/id";
-    public static final String ENRICHMENT_NETWORK_ID = "enrichment/network/id";
-    public static final String ENRICHMENT_SERVICE_ID = "enrichment/service/id";
-    public static final String ENRICHMENT_SERVICE_INSTANCE_ID = "enrichment/serviceInstance/id";
-    public static final String ENRICHMENT_VNF_ID = "enrichment/vnf/id";
-    public static final String ENRICHMENT_VSERVER_ID = "enrichment/vserver/id";
-    public static final String ENRICHMENT_VSERVER_NAME = "enrichment/vserver/name";
+    public static final String ENRICHMENT_BANDWIDTH_CHANGE_TIME = "enrichment/bandwidth-change-time";
+    public static final String ENRICHMENT_GENERIC_VNF_ID = "enrichment/generic-vnf.vnf-id";
+    public static final String ENRICHMENT_NETWORK_ID = "enrichment/network-information.network-id";
+    public static final String ENRICHMENT_SERVICE_ID = "enrichment/service-instance.service-instance-id";
+    public static final String ENRICHMENT_VNF_ID = "enrichment/vnfId";
+    public static final String ENRICHMENT_VSERVER_ID = "enrichment/vserver.vserver-id";
+    public static final String ENRICHMENT_VSERVER_NAME = "enrichment/vserver.vserver-name";
 
     public static final String EVENT_ADDITIONAL_PARAMS = "event/additionalParams";
     public static final String EVENT_PAYLOAD = "event/payload";
@@ -54,6 +138,10 @@ public class OperationProperties {
     /*
      * These are data computed and/or tracked by the invoker.
      */
+
+    /**
+     * An Integer containing the count.
+     */
     public static final String DATA_VF_COUNT = "data/vfCount";
 
 
index 9ce53aa..0aa1122 100644 (file)
@@ -139,6 +139,17 @@ public abstract class OperationPartial implements Operation {
         return params.getOperation();
     }
 
+    /**
+     * Determines if a property has been assigned for the operation.
+     *
+     * @param name property name
+     * @return {@code true} if the given property has been assigned for the operation,
+     *         {@code false} otherwise
+     */
+    public boolean containsProperty(String name) {
+        return properties.containsKey(name);
+    }
+
     /**
      * Sets a property.
      *
@@ -326,6 +337,7 @@ public abstract class OperationPartial implements Operation {
 
     /**
      * Generates and sets {@link #subRequestId} to a new subrequest ID.
+     *
      * @param attempt attempt number, typically starting with 1
      */
     public void generateSubRequestId(int attempt) {