2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ============LICENSE_END=========================================================
24 package org.onap.appc.workflow.impl;
26 import org.apache.commons.lang.ObjectUtils;
27 import org.apache.commons.lang3.StringUtils;
28 import org.onap.appc.common.constant.Constants;
29 import org.onap.appc.configuration.Configuration;
30 import org.onap.appc.configuration.ConfigurationFactory;
31 import org.onap.appc.domainmodel.lcm.RequestContext;
32 import org.onap.appc.domainmodel.lcm.ResponseContext;
33 import org.onap.appc.util.ObjectMapper;
34 import org.onap.appc.workflow.WorkFlowManager;
35 import org.onap.appc.workflow.objects.WorkflowExistsOutput;
36 import org.onap.appc.workflow.objects.WorkflowRequest;
37 import org.onap.appc.workflow.objects.WorkflowResponse;
38 import com.att.eelf.configuration.EELFLogger;
39 import com.att.eelf.configuration.EELFManager;
40 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
41 import org.onap.ccsdk.sli.core.sli.provider.SvcLogicService;
43 import java.text.SimpleDateFormat;
44 import java.util.Arrays;
45 import java.util.Enumeration;
47 import java.util.Properties;
50 public class WorkFlowManagerImpl implements WorkFlowManager{
51 private SvcLogicService svcLogic = null;
52 private final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
53 private final Configuration configuration = ConfigurationFactory.getConfiguration();
55 private WorkflowResolver workflowResolver = new WorkflowResolver(
56 configuration.getIntegerProperty("org.onap.appc.workflow.resolver.refresh_interval", 300)
59 public void setWorkflowResolver(WorkflowResolver workflowResolver){
60 this.workflowResolver=workflowResolver;
63 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
64 this.svcLogic = svcLogic;
68 * Execute workflow and return response.
69 * This method execute workflow with following steps.
70 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
71 * Execute workflow (DG) using SVC Logic Service reference
72 * Return response of workflow (DG) to caller.
74 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
75 * @return Workflow Response which contains execution status and payload from DG if any
79 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
80 if (logger.isTraceEnabled()) {
81 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
83 WorkflowResponse workflowResponse = new WorkflowResponse();
84 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
89 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
91 Properties workflowParams = new Properties();
92 String actionProperty;
93 String requestIdProperty;
95 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
97 The following method call (populateDGContext) populates DG context with the
98 request parameters to maintain backward compatibility with old DGs,
99 we are not altering the old way of passing (org.onap.appc.vnfId and so on..)
100 This is still a temporary solution, the end solution should be agreed with
101 all stakeholders and implemented.
103 populateDGContext(workflowParams,workflowRequest);
105 actionProperty = configuration.getProperty("org.onap.appc.workflow.action", String.valueOf(Constants.ACTION));
106 requestIdProperty = configuration.getProperty("org.onap.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
107 vfIdProperty = configuration.getProperty("org.onap.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
108 String vfTypeProperty = configuration.getProperty("org.onap.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
109 String apiVerProperty = configuration.getProperty("org.onap.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
110 String originatorIdProperty = configuration.getProperty("org.onap.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
111 String subRequestId = configuration.getProperty("org.onap.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
113 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
114 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
115 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
116 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
117 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
118 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
119 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
121 Object payloadJson = workflowRequest.getRequestContext().getPayload();
122 if(payloadJson!=null) {
124 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
125 workflowParams.putAll(payloadProperties);
127 if (logger.isDebugEnabled()) {
128 logger.debug("DG properties: " + workflowParams);
130 } catch (Exception e) {
131 logger.error("Error parsing payload json string", e);
132 Properties workflowPrp = new Properties();
133 workflowPrp.setProperty("error-message", "Error parsing payload json string");
134 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
135 if (logger.isTraceEnabled()) {
136 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
138 return workflowResponse;
141 if (logger.isDebugEnabled()) {
142 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
143 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
144 vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
146 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
149 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
150 workflowParams.put("isBwcMode","true");
152 workflowParams.put("isBwcMode", "false");
155 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
156 if (logger.isTraceEnabled()) {
157 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
159 }catch (Exception e){
160 logger.error("Error Executing DG " +e.getMessage(),e);
161 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
163 if (logger.isTraceEnabled()) {
164 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
166 return workflowResponse;
169 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
170 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
171 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
172 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
173 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
174 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId()!=null ? workflowRequest.getRequestContext().getCommonHeader().getSubRequestId():"");
175 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
176 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
177 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
178 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
179 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
180 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
181 workflowParams.put("input.action-identifiers.vf-module-id",workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId():"");
182 final Map<String, String> additionalContext;
183 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
184 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
185 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
191 * Check if workflow (DG) exists in database
193 * @param workflowQueryParams workflow request with command and vnf Type
194 * @return True if workflow exists else False.
197 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
198 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
199 if (logger.isTraceEnabled()) {
200 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
204 WorkflowKey workflowKey = workflowResolver.resolve(
205 workflowQueryParams.getRequestContext().getAction().name(),
206 workflowQueryParams.getVnfContext().getType(),
207 workflowQueryParams.getVnfContext().getVersion(),
208 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
209 if (workflowKey != null) {
210 workflowExistsOutput.setMappingExist(true);
211 workflowExistsOutput.setWorkflowModule(workflowKey.module());
212 workflowExistsOutput.setWorkflowName(workflowKey.name());
213 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
214 if (isDGExists(workflowKey)) {
215 workflowExistsOutput.setDgExist(true);
218 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
219 workflowKey.module(), workflowKey.name(), workflowKey.version()));
223 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
224 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
226 } catch (RuntimeException e) {
227 logger.error("Error querying workflow from database"+e.getMessage());
229 }catch (SvcLogicException e) {
230 logger.error("Error querying workflow from database"+e.getMessage());
231 throw new RuntimeException(e);
233 if (logger.isTraceEnabled()) {
234 logger.trace("Exiting workflowExists");
236 return workflowExistsOutput;
240 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
241 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
244 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
245 if (logger.isTraceEnabled()) {
246 logger.trace("Entering SVCLogicServiceExecute");
249 Properties respProps = null;
252 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
253 } catch (Exception e) {
254 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
256 if (logger.isDebugEnabled()) {
257 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
259 logger.error("Error in DG", e.getMessage()+ Arrays.toString(e.getStackTrace()),e);
262 if (respProps != null) {
263 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
264 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
267 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
268 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
269 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
270 int specificStatusCode = 0;
271 if (dgOutputStatusCode != null) {
272 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
275 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
277 if (logger.isDebugEnabled()) {
278 logger.debug("DG Execution Status: " + commonStatus);
282 if (logger.isTraceEnabled()) {
283 logger.trace("Exiting from SVCLogicServiceExecute");
288 * Filling response context by output.* fields from DG context. Works only for 2.* API version
290 * @param responseContext response context which you need to fill
291 * @param respProps DG context in a properties format
293 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
295 Enumeration<?> e = respProps.propertyNames();
296 while (e.hasMoreElements()){
297 String key = (String) e.nextElement();
298 if (key.startsWith("output.")){
299 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
301 if (key.equalsIgnoreCase("output.payload")){
302 responseContext.setPayload(respProps.getProperty(key));
304 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
312 * Filling responceContext status code amd message according to responce messages and codes from DG.
314 * @param responseContext response cotext
315 * @param commonStatus common status message from DG ("success" or "failure")
316 * @param specificStatusMessage specific status message from specific DG node
317 * @param specificStatusCode specific status code from specific DG node
319 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
320 if (null == specificStatusMessage) { specificStatusMessage = ""; }
321 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
322 if (specificStatusCode != 0 ){
323 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
325 fillStatus(400, commonStatus, responseContext);
328 if (specificStatusCode != 0){
329 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
331 fillStatus(401, specificStatusMessage, responseContext);
337 * filling responseContext by status code and status message
339 * @param code 3-digit status code
340 * @param message explanation of a status code
341 * @param responceContext response context which will be store status code and status message
343 private void fillStatus(int code, String message, ResponseContext responceContext) {
344 responceContext.getStatus().setCode(code);
345 responceContext.getStatus().setMessage(message);