2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
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.openecomp.appc.workflow.impl;
24 import org.apache.commons.lang.ObjectUtils;
25 import org.apache.commons.lang3.StringUtils;
26 import org.openecomp.appc.common.constant.Constants;
27 import org.openecomp.appc.configuration.Configuration;
28 import org.openecomp.appc.configuration.ConfigurationFactory;
29 import org.openecomp.appc.domainmodel.lcm.RequestContext;
30 import org.openecomp.appc.domainmodel.lcm.ResponseContext;
31 import org.openecomp.appc.domainmodel.lcm.Status;
32 import org.openecomp.appc.util.ObjectMapper;
33 import org.openecomp.appc.workflow.WorkFlowManager;
34 import org.openecomp.appc.workflow.objects.WorkflowExistsOutput;
35 import org.openecomp.appc.workflow.objects.WorkflowRequest;
36 import org.openecomp.appc.workflow.objects.WorkflowResponse;
37 import com.att.eelf.configuration.EELFLogger;
38 import com.att.eelf.configuration.EELFManager;
39 import org.openecomp.sdnc.sli.SvcLogicException;
40 import org.openecomp.sdnc.sli.provider.SvcLogicService;
42 import java.text.SimpleDateFormat;
43 import java.util.Enumeration;
45 import java.util.Properties;
48 public class WorkFlowManagerImpl implements WorkFlowManager{
49 private SvcLogicService svcLogic = null;
50 private static final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
51 private static final Configuration configuration = ConfigurationFactory.getConfiguration();
53 private final WorkflowResolver workflowResolver = new WorkflowResolver(
54 configuration.getIntegerProperty("org.openecomp.appc.workflow.resolver.refresh_interval", 300)
57 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
58 this.svcLogic = svcLogic;
62 * Execute workflow and return response.
63 * This method execute workflow with following steps.
64 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
65 * Execute workflow (DG) using SVC Logic Service reference
66 * Return response of workflow (DG) to caller.
68 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
69 * @return Workflow Response which contains execution status and payload from DG if any
73 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
74 if (logger.isTraceEnabled()) {
75 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
77 WorkflowResponse workflowResponse = new WorkflowResponse();
78 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
83 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
85 Properties workflowParams = new Properties();
86 String actionProperty = null;
87 String requestIdProperty=null;
88 String vfIdProperty =null;
89 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
91 The following method call (populateDGContext) populates DG context with the
92 request parameters to maintain backward compatibility with old DGs,
93 we are not altering the old way of passing (org.openecomp.appc.vnfId and so on..)
94 This is still a temporary solution, the end solution should be agreed with
95 all stakeholders and implemented.
97 populateDGContext(workflowParams,workflowRequest);
99 actionProperty = configuration.getProperty("org.openecomp.appc.workflow.action", String.valueOf(Constants.ACTION));
100 requestIdProperty = configuration.getProperty("org.openecomp.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
101 vfIdProperty = configuration.getProperty("org.openecomp.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
102 String payloadProperty = configuration.getProperty("org.openecomp.appc.workflow.payload", String.valueOf(Constants.PAYLOAD));
103 String vfTypeProperty = configuration.getProperty("org.openecomp.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
104 String apiVerProperty = configuration.getProperty("org.openecomp.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
105 String originatorIdProperty = configuration.getProperty("org.openecomp.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
106 String subRequestId = configuration.getProperty("org.openecomp.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
108 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
109 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
110 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
111 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
112 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
113 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
114 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
116 Object payloadJson = workflowRequest.getRequestContext().getPayload();
117 if(payloadJson!=null) {
119 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
120 workflowParams.putAll(payloadProperties);
122 if (logger.isDebugEnabled()) {
123 logger.debug("DG properties: " + workflowParams);
125 } catch (Exception e) {
126 logger.error("Error parsing payload json string", e);
127 Properties workflowPrp = new Properties();
128 workflowPrp.setProperty("error-message", "Error parsing payload json string");
129 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
130 if (logger.isTraceEnabled()) {
131 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
133 return workflowResponse;
136 if (logger.isDebugEnabled()) {
137 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
138 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
139 vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
141 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
144 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
145 workflowParams.put("isBwcMode","true");
147 workflowParams.put("isBwcMode", "false");
150 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
151 if (logger.isTraceEnabled()) {
152 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
154 }catch (Exception e){
155 logger.error("Error Executing DG " +e.getMessage());
156 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
158 if (logger.isTraceEnabled()) {
159 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
161 return workflowResponse;
164 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
165 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
166 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
167 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
168 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
169 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId()!=null ? workflowRequest.getRequestContext().getCommonHeader().getSubRequestId():"");
170 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
171 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
172 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
173 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
174 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
175 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
176 final Map<String, String> additionalContext;
177 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
178 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
179 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
185 * Check if workflow (DG) exists in database
187 * @param workflowQueryParams workflow request with command and vnf Type
188 * @return True if workflow exists else False.
191 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
192 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
193 if (logger.isTraceEnabled()) {
194 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
198 WorkflowKey workflowKey = workflowResolver.resolve(
199 workflowQueryParams.getRequestContext().getAction().name(),
200 workflowQueryParams.getVnfContext().getType(),
201 workflowQueryParams.getVnfContext().getVersion(),
202 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
203 if (workflowKey != null) {
204 workflowExistsOutput.setMappingExist(true);
205 workflowExistsOutput.setWorkflowModule(workflowKey.module());
206 workflowExistsOutput.setWorkflowName(workflowKey.name());
207 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
208 if (isDGExists(workflowKey)) {
209 workflowExistsOutput.setDgExist(true);
212 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
213 workflowKey.module(), workflowKey.name(), workflowKey.version()));
217 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
218 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
220 } catch (RuntimeException e) {
221 logger.error("Error querying workflow from database"+e.getMessage());
223 }catch (SvcLogicException e) {
224 logger.error("Error querying workflow from database"+e.getMessage());
225 throw new RuntimeException(e);
227 if (logger.isTraceEnabled()) {
228 logger.trace("Exiting workflowExists");
230 return workflowExistsOutput;
234 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
235 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
238 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
239 if (logger.isTraceEnabled()) {
240 logger.trace("Entering SVCLogicServiceExecute");
243 Properties respProps = null;
246 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
247 } catch (Exception e) {
248 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
250 if (logger.isDebugEnabled()) {
251 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
253 logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
256 if (respProps != null) {
257 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
258 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
261 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
262 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
263 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
264 int specificStatusCode = 0;
265 if (dgOutputStatusCode != null) {
266 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
269 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
271 if (logger.isDebugEnabled()) {
272 logger.debug("DG Execution Status: " + commonStatus);
276 if (logger.isTraceEnabled()) {
277 logger.trace("Exiting from SVCLogicServiceExecute");
282 * Filling response context by output.* fields from DG context. Works only for 2.* API version
284 * @param responseContext response context which you need to fill
285 * @param respProps DG context in a properties format
287 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
289 Enumeration<?> e = respProps.propertyNames();
290 while (e.hasMoreElements()){
291 String key = (String) e.nextElement();
292 if (key.startsWith("output.")){
293 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
295 if (key.equalsIgnoreCase("output.payload")){
296 responseContext.setPayload(respProps.getProperty(key));
298 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
306 * Filling responceContext status code amd message according to responce messages and codes from DG.
308 * @param responseContext response cotext
309 * @param commonStatus common status message from DG ("success" or "failure")
310 * @param specificStatusMessage specific status message from specific DG node
311 * @param specificStatusCode specific status code from specific DG node
313 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
314 if (null == specificStatusMessage) { specificStatusMessage = ""; }
315 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
316 if (specificStatusCode != 0 ){
317 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
319 fillStatus(400, commonStatus, responseContext);
322 String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
323 if (specificStatusCode != 0){
324 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
326 fillStatus(401, specificStatusMessage, responseContext);
332 * filling responseContext by status code and status message
334 * @param code 3-digit status code
335 * @param message explanation of a status code
336 * @param responceContext response context which will be store status code and status message
338 private void fillStatus(int code, String message, ResponseContext responceContext) {
339 responceContext.setStatus(new Status(code, message));