2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2020 Wipro Limited.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.controlloop.actor.so;
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import java.time.LocalDateTime;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.List;
31 import java.util.Optional;
32 import javax.ws.rs.core.MediaType;
33 import javax.ws.rs.core.Response;
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.policy.common.gson.GsonMessageBodyHandler;
40 import org.onap.policy.common.utils.coder.Coder;
41 import org.onap.policy.common.utils.coder.CoderException;
42 import org.onap.policy.common.utils.coder.StandardCoder;
43 import org.onap.policy.common.utils.coder.StandardCoderObject;
44 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
45 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
46 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
47 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
48 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
49 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpPollingConfig;
50 import org.onap.policy.so.SoCloudConfiguration;
51 import org.onap.policy.so.SoModelInfo;
52 import org.onap.policy.so.SoRequest;
53 import org.onap.policy.so.SoRequestInfo;
54 import org.onap.policy.so.SoRequestParameters;
55 import org.onap.policy.so.SoRequestStatus;
56 import org.onap.policy.so.SoResponse;
57 import org.onap.policy.so.util.SoLocalDateTimeTypeAdapter;
60 * Superclass for SDNC Operators. Note: subclasses should invoke {@link #resetPollCount()}
61 * each time they issue an HTTP request.
63 public abstract class SoOperation extends HttpOperation<SoResponse> {
64 private static final Coder coder = new SoCoder();
66 public static final String FAILED = "FAILED";
67 public static final String COMPLETE = "COMPLETE";
68 public static final int SO_RESPONSE_CODE = 999;
70 // fields within the policy payload
71 public static final String REQ_PARAM_NM = "requestParameters";
72 public static final String CONFIG_PARAM_NM = "configurationParameters";
74 /* Values extracted from the parameter Target. These fields are required by any
75 subclasses that make use of prepareSoModelInfo().
77 private final String modelCustomizationId;
78 private final String modelInvariantId;
79 private final String modelVersionId;
80 private final String modelName;
81 private final String modelVersion;
86 * Constructs the object.
88 * @param params operation parameters
89 * @param config configuration for this operation
90 * @param propertyNames names of properties required by this operation
92 public SoOperation(ControlLoopOperationParams params, HttpPollingConfig config, List<String> propertyNames) {
93 super(params, config, SoResponse.class, propertyNames);
95 this.modelCustomizationId = null;
96 this.modelInvariantId = null;
97 this.modelVersionId = null;
98 this.modelVersion = null;
99 this.modelName = null;
101 verifyNotNull("Target information", params.getTargetType());
105 * Constructs the object.
107 * @param params operation parameters
108 * @param config configuration for this operation
109 * @param propertyNames names of properties required by this operation
110 * @param targetEntityIds Target Entity information
112 public SoOperation(ControlLoopOperationParams params, HttpPollingConfig config, List<String> propertyNames,
113 Map<String, String> targetEntityIds) {
114 super(params, config, SoResponse.class, propertyNames);
116 verifyNotNull("Target entity Ids information", targetEntityIds);
118 this.modelCustomizationId = targetEntityIds
119 .get(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_CUSTOMIZATION_ID);
120 this.modelInvariantId = targetEntityIds
121 .get(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_INVARIANT_ID);
122 this.modelVersionId = targetEntityIds
123 .get(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_VERSION_ID);
124 this.modelVersion = targetEntityIds
125 .get(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_VERSION);
126 this.modelName = targetEntityIds
127 .get(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_NAME);
129 verifyNotNull("Target information", params.getTargetType());
133 protected void resetPollCount() {
134 super.resetPollCount();
135 setSubRequestId(null);
139 * Validates that the parameters contain the required target information to construct
142 protected void validateTarget() {
143 verifyNotNull(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_CUSTOMIZATION_ID, modelCustomizationId);
144 verifyNotNull(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_INVARIANT_ID, modelInvariantId);
145 verifyNotNull(ControlLoopOperationParams.PARAMS_ENTITY_MODEL_VERSION_ID, modelVersionId);
148 private void verifyNotNull(String type, Object value) {
150 throw new IllegalArgumentException("missing Target." + type);
154 protected int getVfCount() {
155 return getRequiredProperty(OperationProperties.DATA_VF_COUNT, "VF Count");
158 protected void setVfCount(int vfCount) {
159 setProperty(OperationProperties.DATA_VF_COUNT, vfCount);
163 protected Status detmStatus(Response rawResponse, SoResponse response) {
164 if (rawResponse.getStatus() == 200) {
165 String requestState = getRequestState(response);
166 if (COMPLETE.equalsIgnoreCase(requestState)) {
167 extractSubRequestId(response);
168 return Status.SUCCESS;
171 if (FAILED.equalsIgnoreCase(requestState)) {
172 extractSubRequestId(response);
173 return Status.FAILURE;
179 // need a request ID with which to query
180 if (getSubRequestId() == null && !extractSubRequestId(response)) {
181 throw new IllegalArgumentException("missing request ID in response");
184 return Status.STILL_WAITING;
188 protected String getPollingPath() {
189 return super.getPollingPath() + getSubRequestId();
193 public void generateSubRequestId(int attempt) {
194 setSubRequestId(null);
197 private boolean extractSubRequestId(SoResponse response) {
198 if (response == null || response.getRequestReferences() == null
199 || response.getRequestReferences().getRequestId() == null) {
203 setSubRequestId(response.getRequestReferences().getRequestId());
208 * Gets the request state of a response.
210 * @param response response from which to get the state
211 * @return the request state of the response, or {@code null} if it does not exist
213 protected String getRequestState(SoResponse response) {
214 SoRequest request = response.getRequest();
215 if (request == null) {
219 SoRequestStatus status = request.getRequestStatus();
220 if (status == null) {
224 return status.getRequestState();
228 * Treats everything as a success, so we always go into
229 * {@link #postProcessResponse(OperationOutcome, String, Response, SoResponse)}.
232 protected boolean isSuccess(Response rawResponse, SoResponse response) {
237 * Prepends the message with the http status code.
240 public OperationOutcome setOutcome(OperationOutcome outcome, OperationResult result, Response rawResponse,
241 SoResponse response) {
243 // set default result and message
244 setOutcome(outcome, result);
246 int code = (result == OperationResult.FAILURE_TIMEOUT ? SO_RESPONSE_CODE : rawResponse.getStatus());
248 outcome.setResponse(response);
249 outcome.setMessage(code + " " + outcome.getMessage());
253 protected SoModelInfo prepareSoModelInfo() {
254 SoModelInfo soModelInfo = new SoModelInfo();
255 soModelInfo.setModelCustomizationId(modelCustomizationId);
256 soModelInfo.setModelInvariantId(modelInvariantId);
257 soModelInfo.setModelName(modelName);
258 soModelInfo.setModelVersion(modelVersion);
259 soModelInfo.setModelVersionId(modelVersionId);
260 soModelInfo.setModelType("vfModule");
265 * Construct requestInfo for the SO requestDetails.
267 * @return SO request information
269 protected SoRequestInfo constructRequestInfo() {
270 SoRequestInfo soRequestInfo = new SoRequestInfo();
271 soRequestInfo.setSource("POLICY");
272 soRequestInfo.setSuppressRollback(false);
273 soRequestInfo.setRequestorId("policy");
274 return soRequestInfo;
278 * Builds the request parameters from the policy payload.
280 protected Optional<SoRequestParameters> buildRequestParameters() {
281 if (params.getPayload() == null) {
282 return Optional.empty();
285 Object data = params.getPayload().get(REQ_PARAM_NM);
287 return Optional.empty();
291 return Optional.of(coder.decode(data.toString(), SoRequestParameters.class));
292 } catch (CoderException e) {
293 throw new IllegalArgumentException("invalid payload value: " + REQ_PARAM_NM);
298 * Builds the configuration parameters from the policy payload.
300 protected Optional<List<Map<String, String>>> buildConfigurationParameters() {
301 if (params.getPayload() == null) {
302 return Optional.empty();
305 Object data = params.getPayload().get(CONFIG_PARAM_NM);
307 return Optional.empty();
311 @SuppressWarnings("unchecked")
312 List<Map<String, String>> result = coder.decode(data.toString(), ArrayList.class);
313 return Optional.of(result);
314 } catch (CoderException | RuntimeException e) {
315 throw new IllegalArgumentException("invalid payload value: " + CONFIG_PARAM_NM);
320 * Construct cloudConfiguration for the SO requestDetails.
322 * @param tenantItem tenant item from A&AI named-query response
323 * @return SO cloud configuration
325 protected SoCloudConfiguration constructCloudConfiguration(Tenant tenantItem, CloudRegion cloudRegionItem) {
326 SoCloudConfiguration cloudConfiguration = new SoCloudConfiguration();
327 cloudConfiguration.setTenantId(tenantItem.getTenantId());
328 cloudConfiguration.setLcpCloudRegionId(cloudRegionItem.getCloudRegionId());
329 return cloudConfiguration;
333 * Create simple HTTP headers for unauthenticated requests to SO.
335 * @return the HTTP headers
337 protected Map<String, Object> createSimpleHeaders() {
338 Map<String, Object> headers = new HashMap<>();
339 headers.put("Accept", MediaType.APPLICATION_JSON);
344 * These methods extract data from the Custom Query and throw an
345 * IllegalArgumentException if the desired data item is not found.
348 protected GenericVnf getVnfItem(SoModelInfo soModelInfo) {
349 return getRequiredProperty(OperationProperties.AAI_VNF, "generic VNF");
352 protected ServiceInstance getServiceInstance() {
353 return getRequiredProperty(OperationProperties.AAI_SERVICE, "VNF Service Item");
356 protected Tenant getDefaultTenant() {
357 return getRequiredProperty(OperationProperties.AAI_DEFAULT_TENANT, "Default Tenant Item");
360 protected CloudRegion getDefaultCloudRegion() {
361 return getRequiredProperty(OperationProperties.AAI_DEFAULT_CLOUD_REGION, "Default Cloud Region");
364 protected ModelVer getVnfModel() {
365 return getRequiredProperty(OperationProperties.AAI_VNF_MODEL, "generic VNF Model");
368 protected ModelVer getServiceModel() {
369 return getRequiredProperty(OperationProperties.AAI_SERVICE_MODEL, "Service Model");
372 // these may be overridden by junit tests
375 protected Coder getCoder() {
379 private static class SoCoder extends StandardCoder {
382 * Gson object used to encode and decode messages.
384 private static final Gson SO_GSON;
387 * Gson object used to encode messages in "pretty" format.
389 private static final Gson SO_GSON_PRETTY;
392 GsonBuilder builder = GsonMessageBodyHandler
393 .configBuilder(new GsonBuilder().registerTypeAdapter(StandardCoderObject.class,
394 new StandardTypeAdapter()))
395 .registerTypeAdapter(LocalDateTime.class, new SoLocalDateTimeTypeAdapter());
397 SO_GSON = builder.create();
398 SO_GSON_PRETTY = builder.setPrettyPrinting().create();
402 super(SO_GSON, SO_GSON_PRETTY);