2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * ================================================================================
9 * Modifications (C) 2019 Ericsson
10 * =============================================================================
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
23 * ============LICENSE_END=========================================================
26 package org.onap.appc.workflow.impl;
28 import org.apache.commons.lang.ObjectUtils;
29 import org.onap.appc.common.constant.Constants;
30 import org.onap.appc.configuration.Configuration;
31 import org.onap.appc.configuration.ConfigurationFactory;
32 import org.onap.appc.domainmodel.lcm.RequestContext;
33 import org.onap.appc.domainmodel.lcm.ResponseContext;
34 import org.onap.appc.util.ObjectMapper;
35 import org.onap.appc.workflow.WorkFlowManager;
36 import org.onap.appc.workflow.objects.WorkflowExistsOutput;
37 import org.onap.appc.workflow.objects.WorkflowRequest;
38 import org.onap.appc.workflow.objects.WorkflowResponse;
39 import com.att.eelf.configuration.EELFLogger;
40 import com.att.eelf.configuration.EELFManager;
41 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
42 import org.onap.ccsdk.sli.core.sli.provider.SvcLogicService;
44 import java.text.SimpleDateFormat;
45 import java.util.Arrays;
46 import java.util.Enumeration;
48 import java.util.Properties;
51 public class WorkFlowManagerImpl implements WorkFlowManager{
52 private SvcLogicService svcLogic = null;
53 private final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
54 private final Configuration configuration = ConfigurationFactory.getConfiguration();
56 private WorkflowResolver workflowResolver = new WorkflowResolver(
57 configuration.getIntegerProperty("org.onap.appc.workflow.resolver.refresh_interval", 300)
60 public void setWorkflowResolver(WorkflowResolver workflowResolver){
61 this.workflowResolver = workflowResolver;
64 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
65 this.svcLogic = svcLogic;
69 * Execute workflow and return response.
70 * This method execute workflow with following steps.
71 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
72 * Execute workflow (DG) using SVC Logic Service reference
73 * Return response of workflow (DG) to caller.
75 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
76 * @return Workflow Response which contains execution status and payload from DG if any
80 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
81 if (logger.isTraceEnabled()) {
82 logger.trace("Entering to executeWorkflow with WorkflowRequest = " + ObjectUtils.toString(workflowRequest.toString()));
84 WorkflowResponse workflowResponse = new WorkflowResponse();
85 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
88 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
90 Properties workflowParams = new Properties();
91 String actionProperty;
92 String requestIdProperty;
94 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
96 The following method call (populateDGContext) populates DG context with the
97 request parameters to maintain backward compatibility with old DGs,
98 we are not altering the old way of passing (org.onap.appc.vnfId and so on..)
99 This is still a temporary solution, the end solution should be agreed with
100 all stakeholders and implemented.
102 populateDGContext(workflowParams,workflowRequest);
104 actionProperty = configuration.getProperty("org.onap.appc.workflow.action", String.valueOf(Constants.ACTION));
105 requestIdProperty = configuration.getProperty("org.onap.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
106 vfIdProperty = configuration.getProperty("org.onap.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
107 String vfTypeProperty = configuration.getProperty("org.onap.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
108 String apiVerProperty = configuration.getProperty("org.onap.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
109 String originatorIdProperty = configuration.getProperty("org.onap.appc.workflow.originatorId", Constants.ORIGINATOR_ID);
110 String subRequestId = configuration.getProperty("org.onap.appc.workflow.subRequestId", Constants.SUB_REQUEST_ID);
112 workflowParams.put(actionProperty, workflowRequest.getRequestContext().getAction().name());
113 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
114 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
115 workflowParams.put(vfTypeProperty, workflowRequest.getVnfContext().getType());
116 workflowParams.put(apiVerProperty, workflowRequest.getRequestContext().getCommonHeader().getApiVer());
117 workflowParams.put(originatorIdProperty, workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
118 workflowParams.put(subRequestId, workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
120 Object payloadJson = workflowRequest.getRequestContext().getPayload();
121 if(payloadJson != null) {
123 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
124 workflowParams.putAll(payloadProperties);
126 logger.debug("DG properties: " + workflowParams);
127 } catch (Exception e) {
128 logger.error("Error parsing payload json string", e);
129 Properties workflowPrp = new Properties();
130 workflowPrp.setProperty("error-message", "Error parsing payload json string");
131 fillStatus(501, "Error parsing payload json string: " + e.getMessage(), workflowRequest.getResponseContext());
132 logger.trace("Exiting from executeWorkflow with (workflowResponse = " + ObjectUtils.toString(workflowResponse) + ")");
133 return workflowResponse;
136 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name() + ", "+
137 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId() + ", " +
138 vfIdProperty + ":" + workflowRequest.getVnfContext().getId());
140 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
142 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
143 workflowParams.put("isBwcMode", "true");
145 workflowParams.put("isBwcMode", "false");
148 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
149 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId()
150 + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
151 }catch (Exception e){
152 logger.error("Error Executing DG " + e.getMessage(), e);
153 fillStatus(501, "Error Executing DG "+ e.getMessage(), workflowRequest.getResponseContext());
155 logger.trace("Exiting from executeWorkflow with (workflowResponse = " +
156 ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage()) + ")");
157 return workflowResponse;
160 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
161 workflowParams.put("input.common-header.timestamp", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
162 workflowParams.put("input.common-header.api-ver", workflowRequest.getRequestContext().getCommonHeader().getApiVer());
163 workflowParams.put("input.common-header.request-id", workflowRequest.getRequestContext().getCommonHeader().getRequestId());
164 workflowParams.put("input.common-header.originator-id", workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
165 workflowParams.put("input.common-header.sub-request-id", workflowRequest.getRequestContext().getCommonHeader().getSubRequestId() != null ?
166 workflowRequest.getRequestContext().getCommonHeader().getSubRequestId() : "");
167 workflowParams.put("input.action", workflowRequest.getRequestContext().getAction().toString());
168 workflowParams.put("input.payload", null != workflowRequest.getRequestContext().getPayload() ?
169 workflowRequest.getRequestContext().getPayload() : "");
170 workflowParams.put("input.action-identifiers.vnf-id", workflowRequest.getVnfContext().getId());
171 workflowParams.put("input.action-identifiers.vnfc-name", workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName() != null ?
172 workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName() : "");
173 workflowParams.put("input.action-identifiers.service-instance-id", workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId() !=null ?
174 workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId() : "");
175 workflowParams.put("input.action-identifiers.vserver-id", workflowRequest.getRequestContext().getActionIdentifiers().getVserverId() !=null ?
176 workflowRequest.getRequestContext().getActionIdentifiers().getVserverId() : "");
177 workflowParams.put("input.action-identifiers.vf-module-id",workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId() !=null ?
178 workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId() : "");
179 final Map<String, String> additionalContext;
180 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
181 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
182 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
188 * Check if workflow (DG) exists in database
190 * @param workflowQueryParams workflow request with command and vnf Type
191 * @return True if workflow exists else False.
194 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
195 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
196 logger.trace("Entering to workflowExists with WorkflowRequest = " + ObjectUtils.toString(workflowQueryParams.toString()));
199 WorkflowKey workflowKey = workflowResolver.resolve(
200 workflowQueryParams.getRequestContext().getAction().name(),
201 workflowQueryParams.getVnfContext().getType(),
202 workflowQueryParams.getVnfContext().getVersion(),
203 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
204 if (workflowKey != null) {
205 workflowExistsOutput.setMappingExist(true);
206 workflowExistsOutput.setWorkflowModule(workflowKey.module());
207 workflowExistsOutput.setWorkflowName(workflowKey.name());
208 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
209 if (isDGExists(workflowKey)) {
210 workflowExistsOutput.setDgExist(true);
213 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
214 workflowKey.module(), workflowKey.name(), workflowKey.version()));
218 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
219 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
221 } catch (RuntimeException e) {
222 logger.error("Error querying workflow from database"+e.getMessage());
224 }catch (SvcLogicException e) {
225 logger.error("Error querying workflow from database"+e.getMessage());
226 throw new RuntimeException(e);
228 logger.trace("Exiting workflowExists");
229 return workflowExistsOutput;
233 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
234 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
237 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
238 logger.trace("Entering SVCLogicServiceExecute");
240 Properties respProps = null;
243 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
244 } catch (Exception e) {
245 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
246 if (logger.isDebugEnabled()) {
247 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
248 logger.error("Error in DG", e.getMessage()+ Arrays.toString(e.getStackTrace()),e);
252 if (respProps != null) {
253 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
254 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
257 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
258 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
259 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
260 int specificStatusCode = 0;
261 if (dgOutputStatusCode != null) {
262 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
265 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
267 logger.debug("DG Execution Status: " + commonStatus);
270 logger.trace("Exiting from SVCLogicServiceExecute");
274 * Filling response context by output.* fields from DG context. Works only for 2.* API version
276 * @param responseContext response context which you need to fill
277 * @param respProps DG context in a properties format
279 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
281 Enumeration<?> e = respProps.propertyNames();
282 while (e.hasMoreElements()){
283 String key = (String) e.nextElement();
284 if (key.startsWith("output.")){
285 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
287 if (key.equalsIgnoreCase("output.payload")){
288 responseContext.setPayload(respProps.getProperty(key));
290 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
298 * Filling responceContext status code amd message according to responce messages and codes from DG.
300 * @param responseContext response cotext
301 * @param commonStatus common status message from DG ("success" or "failure")
302 * @param specificStatusMessage specific status message from specific DG node
303 * @param specificStatusCode specific status code from specific DG node
305 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
306 if (null == specificStatusMessage) { specificStatusMessage = ""; }
307 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
308 if (specificStatusCode != 0 ){
309 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
311 fillStatus(400, commonStatus, responseContext);
314 if (specificStatusCode != 0){
315 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
317 fillStatus(401, specificStatusMessage, responseContext);
323 * filling responseContext by status code and status message
325 * @param code 3-digit status code
326 * @param message explanation of a status code
327 * @param responceContext response context which will be store status code and status message
329 private void fillStatus(int code, String message, ResponseContext responceContext) {
330 responceContext.getStatus().setCode(code);
331 responceContext.getStatus().setMessage(message);