Modify Actors to use properties when provided 00/110900/5
authorJim Hahn <jrh3@att.com>
Tue, 4 Aug 2020 20:27:18 +0000 (16:27 -0400)
committerJim Hahn <jrh3@att.com>
Thu, 6 Aug 2020 23:19:46 +0000 (19:19 -0400)
Modified the Actors to use properties when the application provides them
instead of going to the event context for the data.  This sometimes entailed
moving code out of the Operation subclass constructor that used or validated
the context data.
Combined some property names and renamed others.
Changed VF Count from AtomicInteger to Integer.

Issue-ID: POLICY-2746
Change-Id: Ib8730538309bb77d2f4f6161e9a20a49362d8972
Signed-off-by: Jim Hahn <jrh3@att.com>
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) {