2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.drools.apps.controller.usecases.step;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.BiConsumer;
30 import java.util.function.Consumer;
33 import org.apache.commons.lang3.StringUtils;
34 import org.onap.aai.domain.yang.CloudRegion;
35 import org.onap.aai.domain.yang.GenericVnf;
36 import org.onap.aai.domain.yang.ModelVer;
37 import org.onap.aai.domain.yang.ServiceInstance;
38 import org.onap.aai.domain.yang.Tenant;
39 import org.onap.aai.domain.yang.Vserver;
40 import org.onap.policy.aai.AaiCqResponse;
41 import org.onap.policy.common.utils.coder.StandardCoderObject;
42 import org.onap.policy.controlloop.VirtualControlLoopEvent;
43 import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
44 import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation;
45 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
46 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
47 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
48 import org.onap.policy.controlloop.eventmanager.Step;
49 import org.onap.policy.controlloop.eventmanager.StepContext;
50 import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants;
53 * Steps specific to the usecases controller. The {@link #setProperties()} method is used
54 * to load the various properties into the operation, extracting enrichment data where
55 * appropriate, and extracting other data from the step's context. For each property,
56 * there is a getXxx() method for extracting the value and a loadXxx() method for loading
57 * the extracted value into the operation. In addition, the
58 * {@link #success(OperationOutcome)} method is responsible for extracting responses from
59 * an operation outcome and recording the data in the step's context for use by subsequent
62 public class Step2 extends Step {
63 public static final String TARGET_MODEL_VERSION_ID = "modelVersionId";
64 public static final String TARGET_MODEL_CUSTOMIZATION_ID = "modelCustomizationId";
65 public static final String TARGET_MODEL_INVARIANT_ID = "modelInvariantId";
66 public static final String TARGET_RESOURCE_ID = "resourceID";
67 public static final String TARGET_INFO_MSG = "Target Entity IDs";
68 public static final String ENRICHMENT_PREFIX = "enrichment/";
69 public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
70 public static final String RESOURCE_LINK = "resource-link";
71 public static final String RESULT_DATA = "result-data";
73 private static final Map<String, BiConsumer<Step2, String>> PROPERTY_LOADER;
74 private static final Map<String, Consumer<Step2>> PROPERTY_SAVER;
78 * Populate map for PROPERTY_LOADER.
80 Map<String, BiConsumer<Step2, String>> map = new HashMap<>();
82 map.put(OperationProperties.AAI_DEFAULT_CLOUD_REGION, Step2::loadCloudRegion);
83 map.put(OperationProperties.AAI_DEFAULT_TENANT, Step2::loadTenant);
84 map.put(OperationProperties.AAI_PNF, Step2::loadPnf);
85 map.put(OperationProperties.AAI_RESOURCE_VNF, Step2::loadResourceVnf);
86 map.put(OperationProperties.AAI_SERVICE, Step2::loadService);
87 map.put(OperationProperties.AAI_SERVICE_MODEL, Step2::loadServiceModel);
88 map.put(OperationProperties.AAI_TARGET_ENTITY, Step2::loadTargetEntity);
89 map.put(OperationProperties.AAI_VNF, Step2::loadVnf);
90 map.put(OperationProperties.AAI_VNF_MODEL, Step2::loadVnfModel);
91 map.put(OperationProperties.AAI_VSERVER_LINK, Step2::loadVserverLink);
92 map.put(OperationProperties.DATA_VF_COUNT, Step2::loadVfCount);
93 map.put(OperationProperties.EVENT_ADDITIONAL_PARAMS, Step2::loadAdditionalEventParams);
94 map.put(OperationProperties.EVENT_PAYLOAD, Step2::loadEventPayload);
95 map.put(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES, Step2::loadOptCdsGrpcAaiProperties);
97 map.put(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF, Step2::loadDefaultGenericVnf);
99 PROPERTY_LOADER = Collections.unmodifiableMap(map);
103 * Populate map for PROPERTY_SAVER.
105 Map<String, Consumer<Step2>> map2 = new HashMap<>();
107 map2.put(OperationProperties.DATA_VF_COUNT, Step2::storeVfCount);
109 PROPERTY_SAVER = Collections.unmodifiableMap(map2);
113 protected final StepContext stepContext;
114 protected final VirtualControlLoopEvent event;
117 * {@code True} if the associated preprocessing steps have been loaded, {@code false}
122 private boolean preprocessed;
125 * Actions to take to store the Operation's properties back into the context.
127 private List<Consumer<Step2>> postProcessors = new LinkedList<>();
131 * Constructs the object. This is used when constructing the step for the policy's
134 * @param stepContext the step's context
135 * @param params operation parameters
136 * @param event the event being processed
138 public Step2(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
139 super(params, new AtomicReference<>());
140 this.stepContext = stepContext;
145 * Constructs the object using information from another step. This is used when
146 * constructing a preprocessing step.
148 * @param otherStep step whose information should be used
149 * @param actor actor name
150 * @param operation operation name
152 public Step2(Step2 otherStep, String actor, String operation) {
153 super(otherStep, actor, operation);
154 this.stepContext = otherStep.stepContext;
155 this.event = otherStep.event;
159 * Determines if starting this step indicates acceptance of the event. The default
160 * method simply invokes {@link #isPolicyStep()}.
162 * @return {@code true} if this step accepts the event, {@code false} if it is still
165 public boolean acceptsEvent() {
166 return isPolicyStep();
170 * Indicates that the step succeeded with the given outcome. Invoked by the rules. The
171 * default method invokes the post processors.
173 * @param outcome operation's outcome
175 public void success(OperationOutcome outcome) {
176 for (Consumer<Step2> proc : postProcessors) {
182 * Gets the names of the properties required by the operation. The default method just
183 * delegates to the operation to identify the properties.
185 * @return the names of the properties required by the operation
187 public List<String> getPropertyNames() {
188 return getOperation().getPropertyNames();
192 * Sets the operation's properties. This is invoked <i>after</i> any preprocessor
193 * steps have been performed. It also adds items to {@link #postProcessors}.
195 public void setProperties() {
196 postProcessors.clear();
198 for (String propName : getPropertyNames()) {
199 // identify the saver, if any
200 Consumer<Step2> saver = PROPERTY_SAVER.get(propName);
202 postProcessors.add(saver);
207 if (propName.startsWith(ENRICHMENT_PREFIX)) {
208 loadEnrichment(propName);
212 BiConsumer<Step2, String> loader = PROPERTY_LOADER.get(propName);
213 if (loader == null) {
214 throw new IllegalArgumentException("unknown property " + propName + " needed by " + getActorName() + "."
215 + getOperationName());
218 loader.accept(this, propName);
222 protected void loadCloudRegion(String propName) {
223 getOperation().setProperty(propName, getCloudRegion());
226 protected void loadTenant(String propName) {
227 getOperation().setProperty(propName, getTenant());
230 protected void loadPnf(String propName) {
231 getOperation().setProperty(propName, getPnf());
234 protected void loadResourceVnf(String propName) {
235 getOperation().setProperty(propName, getResourceVnf());
238 protected void loadService(String propName) {
239 getOperation().setProperty(propName, getService());
242 protected void loadServiceModel(String propName) {
243 getOperation().setProperty(propName, getServiceModel());
246 protected void loadTargetEntity(String propName) {
247 getOperation().setProperty(propName, getTargetEntity());
250 protected void loadVnf(String propName) {
251 getOperation().setProperty(propName, getVnf());
254 protected void loadVnfModel(String propName) {
255 getOperation().setProperty(propName, getVnfModel());
258 protected void loadVserverLink(String propName) {
259 getOperation().setProperty(propName, getVserverLink());
262 protected void loadVfCount(String propName) {
263 getOperation().setProperty(propName, getVfCount());
266 protected void loadEnrichment(String propName) {
267 getOperation().setProperty(propName, getEnrichment(propName));
270 protected void loadAdditionalEventParams(String propName) {
271 getOperation().setProperty(propName, getAdditionalEventParams());
274 protected void loadEventPayload(String propName) {
275 getOperation().setProperty(propName, getEventPayload());
278 protected void loadOptCdsGrpcAaiProperties(String propName) {
282 protected void loadDefaultGenericVnf(String propName) {
283 getOperation().setProperty(propName, getDefaultGenericVnf());
286 protected CloudRegion getCloudRegion() {
287 AaiCqResponse aaicq = getCustomQueryData();
288 return verifyNotNull("default cloud region in A&AI response", aaicq.getDefaultCloudRegion());
291 protected Tenant getTenant() {
292 AaiCqResponse aaicq = getCustomQueryData();
293 return verifyNotNull("default tenant in A&AI response", aaicq.getDefaultTenant());
296 protected StandardCoderObject getPnf() {
297 String target = getTargetEntity();
298 return verifyNotNull("PNF for " + target, stepContext.getProperty(AaiGetPnfOperation.getKey(target)));
301 protected GenericVnf getResourceVnf() {
302 verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
304 String resourceId = params.getTargetEntityIds().get(TARGET_RESOURCE_ID);
306 verifyNotNull("Target resource ID", resourceId);
308 AaiCqResponse aaicq = getCustomQueryData();
309 return verifyNotNull("VNF for " + resourceId, aaicq.getGenericVnfByModelInvariantId(resourceId));
312 protected ServiceInstance getService() {
313 AaiCqResponse aaicq = getCustomQueryData();
314 return verifyNotNull("service instance in A&AI response", aaicq.getServiceInstance());
317 protected ModelVer getServiceModel() {
318 AaiCqResponse aaicq = getCustomQueryData();
319 ServiceInstance service = getService();
320 String modelVersionId = verifyNotNull("service model version ID in A&AI response", service.getModelVersionId());
321 return verifyNotNull("model version for service in A&AI response",
322 aaicq.getModelVerByVersionId(modelVersionId));
325 protected Vserver getVServer() {
326 AaiCqResponse aaicq = getCustomQueryData();
327 return verifyNotNull("vserver in A&AI response", aaicq.getVserver());
331 * The default method assumes there is only one target entity and that it's stored
332 * within the step's context.
334 protected String getTargetEntity() {
335 return verifyNotNull("A&AI target entity", stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY));
338 protected GenericVnf getVnf() {
339 verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
341 String modelInvariantId = params.getTargetEntityIds().get(TARGET_MODEL_INVARIANT_ID);
343 verifyNotNull(TARGET_MODEL_INVARIANT_ID, modelInvariantId);
345 AaiCqResponse aaicq = getCustomQueryData();
346 return verifyNotNull("generic VNF in A&AI response for " + modelInvariantId,
347 aaicq.getGenericVnfByVfModuleModelInvariantId(modelInvariantId));
350 protected ModelVer getVnfModel() {
351 GenericVnf vnf = getVnf();
352 String modelVersionId =
353 verifyNotNull("model version ID for generic VNF in A&AI response", vnf.getModelVersionId());
354 AaiCqResponse aaicq = getCustomQueryData();
355 return verifyNotNull("model version for generic VNF in A&AI response",
356 aaicq.getModelVerByVersionId(modelVersionId));
359 protected String getVserverLink() {
360 String vserver = event.getAai().get(VSERVER_VSERVER_NAME);
361 if (StringUtils.isBlank(vserver)) {
362 throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data");
365 StandardCoderObject tenant = stepContext.getProperty(AaiGetTenantOperation.getKey(vserver));
366 verifyNotNull("tenant data", tenant);
368 var resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
369 verifyNotNull("tenant data resource-link", resourceLink);
371 return stripPrefix(resourceLink, 3);
374 protected Integer getVfCount() {
375 if (stepContext.contains(OperationProperties.DATA_VF_COUNT)) {
376 return stepContext.getProperty(OperationProperties.DATA_VF_COUNT);
379 verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
381 String modelCustomizationId = params.getTargetEntityIds().get(TARGET_MODEL_CUSTOMIZATION_ID);
382 String modelInvariantId = params.getTargetEntityIds().get(TARGET_MODEL_INVARIANT_ID);
383 String modelVersionId = params.getTargetEntityIds().get(TARGET_MODEL_VERSION_ID);
385 verifyNotNull("target modelCustomizationId", modelCustomizationId);
386 verifyNotNull("target modelInvariantId", modelInvariantId);
387 verifyNotNull("target modelVersionId", modelVersionId);
389 AaiCqResponse aaicq = getCustomQueryData();
390 return aaicq.getVfModuleCount(modelCustomizationId, modelInvariantId, modelVersionId);
393 protected String getEnrichment(String propName) {
394 var enrichmentKey = propName.substring(ENRICHMENT_PREFIX.length());
395 String value = event.getAai().get(enrichmentKey);
396 verifyNotNull(propName, value);
401 protected Map<String, String> getAdditionalEventParams() {
402 return event.getAdditionalEventParams();
405 protected String getEventPayload() {
406 return event.getPayload();
409 protected GenericVnf getDefaultGenericVnf() {
410 AaiCqResponse aaicq = getCustomQueryData();
411 return verifyNotNull("generic VNF in A&AI response", aaicq.getDefaultGenericVnf());
414 protected AaiCqResponse getCustomQueryData() {
415 AaiCqResponse aaicq = stepContext.getProperty(AaiCqResponse.CONTEXT_KEY);
416 verifyNotNull("custom query data", aaicq);
421 protected void storeVfCount() {
422 if (!getOperation().containsProperty(OperationProperties.DATA_VF_COUNT)) {
426 int vfcount = getOperation().getProperty(OperationProperties.DATA_VF_COUNT);
427 stepContext.setProperty(OperationProperties.DATA_VF_COUNT, vfcount);
430 protected <T> T verifyNotNull(String propName, T value) {
432 throw new IllegalArgumentException(
433 "missing " + propName + " for " + getActorName() + "." + getOperationName());
439 protected static String stripPrefix(String resourceLink, int ncomponents) {
441 for (var nslashes = 0; nslashes < ncomponents; ++nslashes) {
442 int idx = resourceLink.indexOf('/', previdx + 1);
450 return resourceLink.substring(Math.max(0, previdx));