Fix sonars in drools-apps
[policy/drools-applications.git] / controlloop / common / controller-usecases / src / main / java / org / onap / policy / drools / apps / controller / usecases / step / Step2.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.drools.apps.controller.usecases.step;
22
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.BiConsumer;
30 import java.util.function.Consumer;
31 import lombok.Getter;
32 import lombok.Setter;
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;
51
52 /**
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
60  * steps.
61  */
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";
72
73     private static final Map<String, BiConsumer<Step2, String>> PROPERTY_LOADER;
74     private static final Map<String, Consumer<Step2>> PROPERTY_SAVER;
75
76     static {
77         /*
78          * Populate map for PROPERTY_LOADER.
79          */
80         Map<String, BiConsumer<Step2, String>> map = new HashMap<>();
81
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);
96
97         map.put(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF, Step2::loadDefaultGenericVnf);
98
99         PROPERTY_LOADER = Collections.unmodifiableMap(map);
100
101
102         /*
103          * Populate map for PROPERTY_SAVER.
104          */
105         Map<String, Consumer<Step2>> map2 = new HashMap<>();
106
107         map2.put(OperationProperties.DATA_VF_COUNT, Step2::storeVfCount);
108
109         PROPERTY_SAVER = Collections.unmodifiableMap(map2);
110     }
111
112
113     protected final StepContext stepContext;
114     protected final VirtualControlLoopEvent event;
115
116     /**
117      * {@code True} if the associated preprocessing steps have been loaded, {@code false}
118      * otherwise.
119      */
120     @Getter
121     @Setter
122     private boolean preprocessed;
123
124     /**
125      * Actions to take to store the Operation's properties back into the context.
126      */
127     private List<Consumer<Step2>> postProcessors = new LinkedList<>();
128
129
130     /**
131      * Constructs the object. This is used when constructing the step for the policy's
132      * actual operation.
133      *
134      * @param stepContext the step's context
135      * @param params operation parameters
136      * @param event the event being processed
137      */
138     public Step2(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
139         super(params, new AtomicReference<>());
140         this.stepContext = stepContext;
141         this.event = event;
142     }
143
144     /**
145      * Constructs the object using information from another step. This is used when
146      * constructing a preprocessing step.
147      *
148      * @param otherStep step whose information should be used
149      * @param actor actor name
150      * @param operation operation name
151      */
152     public Step2(Step2 otherStep, String actor, String operation) {
153         super(otherStep, actor, operation);
154         this.stepContext = otherStep.stepContext;
155         this.event = otherStep.event;
156     }
157
158     /**
159      * Determines if starting this step indicates acceptance of the event. The default
160      * method simply invokes {@link #isPolicyStep()}.
161      *
162      * @return {@code true} if this step accepts the event, {@code false} if it is still
163      *         indeterminate
164      */
165     public boolean acceptsEvent() {
166         return isPolicyStep();
167     }
168
169     /**
170      * Indicates that the step succeeded with the given outcome. Invoked by the rules. The
171      * default method invokes the post processors.
172      *
173      * @param outcome operation's outcome
174      */
175     public void success(OperationOutcome outcome) {
176         for (Consumer<Step2> proc : postProcessors) {
177             proc.accept(this);
178         }
179     }
180
181     /**
182      * Gets the names of the properties required by the operation. The default method just
183      * delegates to the operation to identify the properties.
184      *
185      * @return the names of the properties required by the operation
186      */
187     public List<String> getPropertyNames() {
188         return getOperation().getPropertyNames();
189     }
190
191     /**
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}.
194      */
195     public void setProperties() {
196         postProcessors.clear();
197
198         for (String propName : getPropertyNames()) {
199             // identify the saver, if any
200             Consumer<Step2> saver = PROPERTY_SAVER.get(propName);
201             if (saver != null) {
202                 postProcessors.add(saver);
203             }
204
205
206             // load data
207             if (propName.startsWith(ENRICHMENT_PREFIX)) {
208                 loadEnrichment(propName);
209                 continue;
210             }
211
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());
216             }
217
218             loader.accept(this, propName);
219         }
220     }
221
222     protected void loadCloudRegion(String propName) {
223         getOperation().setProperty(propName, getCloudRegion());
224     }
225
226     protected void loadTenant(String propName) {
227         getOperation().setProperty(propName, getTenant());
228     }
229
230     protected void loadPnf(String propName) {
231         getOperation().setProperty(propName, getPnf());
232     }
233
234     protected void loadResourceVnf(String propName) {
235         getOperation().setProperty(propName, getResourceVnf());
236     }
237
238     protected void loadService(String propName) {
239         getOperation().setProperty(propName, getService());
240     }
241
242     protected void loadServiceModel(String propName) {
243         getOperation().setProperty(propName, getServiceModel());
244     }
245
246     protected void loadTargetEntity(String propName) {
247         getOperation().setProperty(propName, getTargetEntity());
248     }
249
250     protected void loadVnf(String propName) {
251         getOperation().setProperty(propName, getVnf());
252     }
253
254     protected void loadVnfModel(String propName) {
255         getOperation().setProperty(propName, getVnfModel());
256     }
257
258     protected void loadVserverLink(String propName) {
259         getOperation().setProperty(propName, getVserverLink());
260     }
261
262     protected void loadVfCount(String propName) {
263         getOperation().setProperty(propName, getVfCount());
264     }
265
266     protected void loadEnrichment(String propName) {
267         getOperation().setProperty(propName, getEnrichment(propName));
268     }
269
270     protected void loadAdditionalEventParams(String propName) {
271         getOperation().setProperty(propName, getAdditionalEventParams());
272     }
273
274     protected void loadEventPayload(String propName) {
275         getOperation().setProperty(propName, getEventPayload());
276     }
277
278     protected void loadOptCdsGrpcAaiProperties(String propName) {
279         // do nothing
280     }
281
282     protected void loadDefaultGenericVnf(String propName) {
283         getOperation().setProperty(propName, getDefaultGenericVnf());
284     }
285
286     protected CloudRegion getCloudRegion() {
287         AaiCqResponse aaicq = getCustomQueryData();
288         return verifyNotNull("default cloud region in A&AI response", aaicq.getDefaultCloudRegion());
289     }
290
291     protected Tenant getTenant() {
292         AaiCqResponse aaicq = getCustomQueryData();
293         return verifyNotNull("default tenant in A&AI response", aaicq.getDefaultTenant());
294     }
295
296     protected StandardCoderObject getPnf() {
297         String target = getTargetEntity();
298         return verifyNotNull("PNF for " + target, stepContext.getProperty(AaiGetPnfOperation.getKey(target)));
299     }
300
301     protected GenericVnf getResourceVnf() {
302         verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
303
304         String resourceId = params.getTargetEntityIds().get(TARGET_RESOURCE_ID);
305
306         verifyNotNull("Target resource ID", resourceId);
307
308         AaiCqResponse aaicq = getCustomQueryData();
309         return verifyNotNull("VNF for " + resourceId, aaicq.getGenericVnfByModelInvariantId(resourceId));
310     }
311
312     protected ServiceInstance getService() {
313         AaiCqResponse aaicq = getCustomQueryData();
314         return verifyNotNull("service instance in A&AI response", aaicq.getServiceInstance());
315     }
316
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));
323     }
324
325     protected Vserver getVServer() {
326         AaiCqResponse aaicq = getCustomQueryData();
327         return verifyNotNull("vserver in A&AI response", aaicq.getVserver());
328     }
329
330     /**
331      * The default method assumes there is only one target entity and that it's stored
332      * within the step's context.
333      */
334     protected String getTargetEntity() {
335         return verifyNotNull("A&AI target entity", stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY));
336     }
337
338     protected GenericVnf getVnf() {
339         verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
340
341         String modelInvariantId = params.getTargetEntityIds().get(TARGET_MODEL_INVARIANT_ID);
342
343         verifyNotNull(TARGET_MODEL_INVARIANT_ID, modelInvariantId);
344
345         AaiCqResponse aaicq = getCustomQueryData();
346         return verifyNotNull("generic VNF in A&AI response for " + modelInvariantId,
347                         aaicq.getGenericVnfByVfModuleModelInvariantId(modelInvariantId));
348     }
349
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));
357     }
358
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");
363         }
364
365         StandardCoderObject tenant = stepContext.getProperty(AaiGetTenantOperation.getKey(vserver));
366         verifyNotNull("tenant data", tenant);
367
368         var resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
369         verifyNotNull("tenant data resource-link", resourceLink);
370
371         return stripPrefix(resourceLink, 3);
372     }
373
374     protected Integer getVfCount() {
375         if (stepContext.contains(OperationProperties.DATA_VF_COUNT)) {
376             return stepContext.getProperty(OperationProperties.DATA_VF_COUNT);
377         }
378
379         verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
380
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);
384
385         verifyNotNull("target modelCustomizationId", modelCustomizationId);
386         verifyNotNull("target modelInvariantId", modelInvariantId);
387         verifyNotNull("target modelVersionId", modelVersionId);
388
389         AaiCqResponse aaicq = getCustomQueryData();
390         return aaicq.getVfModuleCount(modelCustomizationId, modelInvariantId, modelVersionId);
391     }
392
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);
397
398         return value;
399     }
400
401     protected Map<String, String> getAdditionalEventParams() {
402         return event.getAdditionalEventParams();
403     }
404
405     protected String getEventPayload() {
406         return event.getPayload();
407     }
408
409     protected GenericVnf getDefaultGenericVnf() {
410         AaiCqResponse aaicq = getCustomQueryData();
411         return verifyNotNull("generic VNF in A&AI response", aaicq.getDefaultGenericVnf());
412     }
413
414     protected AaiCqResponse getCustomQueryData() {
415         AaiCqResponse aaicq = stepContext.getProperty(AaiCqResponse.CONTEXT_KEY);
416         verifyNotNull("custom query data", aaicq);
417
418         return aaicq;
419     }
420
421     protected void storeVfCount() {
422         if (!getOperation().containsProperty(OperationProperties.DATA_VF_COUNT)) {
423             return;
424         }
425
426         int vfcount = getOperation().getProperty(OperationProperties.DATA_VF_COUNT);
427         stepContext.setProperty(OperationProperties.DATA_VF_COUNT, vfcount);
428     }
429
430     protected <T> T verifyNotNull(String propName, T value) {
431         if (value == null) {
432             throw new IllegalArgumentException(
433                             "missing " + propName + " for " + getActorName() + "." + getOperationName());
434         }
435
436         return value;
437     }
438
439     protected static String stripPrefix(String resourceLink, int ncomponents) {
440         int previdx = -1;
441         for (var nslashes = 0; nslashes < ncomponents; ++nslashes) {
442             int idx = resourceLink.indexOf('/', previdx + 1);
443             if (idx < 0) {
444                 break;
445             }
446
447             previdx = idx;
448         }
449
450         return resourceLink.substring(Math.max(0, previdx));
451     }
452 }