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 java.text.SimpleDateFormat;
25 import java.util.Enumeration;
27 import java.util.Properties;
29 import org.apache.commons.lang.ObjectUtils;
30 import org.apache.commons.lang3.StringUtils;
31 import org.openecomp.appc.common.constant.Constants;
32 import org.openecomp.appc.configuration.Configuration;
33 import org.openecomp.appc.configuration.ConfigurationFactory;
34 import org.openecomp.appc.domainmodel.lcm.RequestContext;
35 import org.openecomp.appc.domainmodel.lcm.ResponseContext;
36 import org.openecomp.appc.util.ObjectMapper;
37 import org.openecomp.appc.workflow.WorkFlowManager;
38 import org.openecomp.appc.workflow.objects.WorkflowExistsOutput;
39 import org.openecomp.appc.workflow.objects.WorkflowRequest;
40 import org.openecomp.appc.workflow.objects.WorkflowResponse;
41 import com.att.eelf.configuration.EELFLogger;
42 import com.att.eelf.configuration.EELFManager;
43 import org.openecomp.sdnc.sli.SvcLogicException;
44 import org.openecomp.sdnc.sli.provider.SvcLogicService;
47 public class WorkFlowManagerImpl implements WorkFlowManager{
48 private SvcLogicService svcLogic = null;
49 private static final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
50 private static final Configuration configuration = ConfigurationFactory.getConfiguration();
52 private final WorkflowResolver workflowResolver = new WorkflowResolver(
53 configuration.getIntegerProperty("org.openecomp.appc.workflow.resolver.refresh_interval", 300)
56 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
57 this.svcLogic = svcLogic;
61 * Execute workflow and return response.
62 * This method execute workflow with following steps.
63 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
64 * Execute workflow (DG) using SVC Logic Service reference
65 * Return response of workflow (DG) to caller.
67 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
68 * @return Workflow Response which contains execution status and payload from DG if any
72 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
73 if (logger.isTraceEnabled()) {
74 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
76 WorkflowResponse workflowResponse = new WorkflowResponse();
77 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
82 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
84 Properties workflowParams = new Properties();
85 String actionProperty = null;
86 String requestIdProperty=null;
87 String vfIdProperty =null;
88 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
90 The following method call (populateDGContext) populates DG context with the
91 request parameters to maintain backward compatibility with old DGs,
92 we are not altering the old way of passing (org.openecomp.appc.vnfId and so on..)
93 This is still a temporary solution, the end solution should be agreed with
94 all stakeholders and implemented.
96 populateDGContext(workflowParams,workflowRequest);
98 actionProperty = configuration.getProperty("org.openecomp.appc.workflow.action", String.valueOf(Constants.ACTION));
99 requestIdProperty = configuration.getProperty("org.openecomp.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
100 vfIdProperty = configuration.getProperty("org.openecomp.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
101 String payloadProperty = configuration.getProperty("org.openecomp.appc.workflow.payload", String.valueOf(Constants.PAYLOAD));
102 String vfTypeProperty = configuration.getProperty("org.openecomp.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
103 String apiVerProperty = configuration.getProperty("org.openecomp.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
104 String originatorIdProperty = configuration.getProperty("org.openecomp.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
105 String subRequestId = configuration.getProperty("org.openecomp.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
107 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
108 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
109 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
110 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
111 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
112 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
113 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
115 Object payloadJson = workflowRequest.getRequestContext().getPayload();
116 if(payloadJson!=null) {
118 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
119 workflowParams.putAll(payloadProperties);
121 if (logger.isDebugEnabled()) {
122 logger.debug("DG properties: " + workflowParams);
124 } catch (Exception e) {
125 logger.error("Error parsing payload json string", e);
126 Properties workflowPrp = new Properties();
127 workflowPrp.setProperty("error-message", "Error parsing payload json string");
128 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
129 if (logger.isTraceEnabled()) {
130 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
132 return workflowResponse;
135 if (logger.isDebugEnabled()) {
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());
143 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
144 workflowParams.put("isBwcMode","true");
146 workflowParams.put("isBwcMode", "false");
149 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
150 if (logger.isTraceEnabled()) {
151 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
153 }catch (Exception e){
154 logger.error("Error Executing DG " +e.getMessage());
155 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
157 if (logger.isTraceEnabled()) {
158 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
160 return workflowResponse;
163 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
164 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
165 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
166 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
167 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
168 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
169 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
170 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
171 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
172 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
173 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
174 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
175 final Map<String, String> additionalContext;
176 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
177 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
178 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
184 * Check if workflow (DG) exists in database
186 * @param workflowQueryParams workflow request with command and vnf Type
187 * @return True if workflow exists else False.
190 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
191 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
192 if (logger.isTraceEnabled()) {
193 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
197 WorkflowKey workflowKey = workflowResolver.resolve(
198 workflowQueryParams.getRequestContext().getAction().name(),
199 workflowQueryParams.getVnfContext().getType(),
200 workflowQueryParams.getVnfContext().getVersion(),
201 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
202 if (workflowKey != null) {
203 workflowExistsOutput.setMappingExist(true);
204 workflowExistsOutput.setWorkflowModule(workflowKey.module());
205 workflowExistsOutput.setWorkflowName(workflowKey.name());
206 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
207 if (isDGExists(workflowKey)) {
208 workflowExistsOutput.setDgExist(true);
211 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
212 workflowKey.module(), workflowKey.name(), workflowKey.version()));
216 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
217 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
219 } catch (RuntimeException e) {
220 logger.error("Error querying workflow from database"+e.getMessage());
222 }catch (SvcLogicException e) {
223 logger.error("Error querying workflow from database"+e.getMessage());
224 throw new RuntimeException(e);
226 if (logger.isTraceEnabled()) {
227 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 if (logger.isTraceEnabled()) {
239 logger.trace("Entering SVCLogicServiceExecute");
242 Properties respProps = null;
245 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
246 } catch (Exception e) {
247 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
249 if (logger.isDebugEnabled()) {
250 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
252 logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
255 if (respProps != null) {
256 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
257 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
260 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
261 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
262 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
263 int specificStatusCode = 0;
264 if (dgOutputStatusCode != null) {
265 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
268 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
270 if (logger.isDebugEnabled()) {
271 logger.debug("DG Execution Status: " + commonStatus);
275 if (logger.isTraceEnabled()) {
276 logger.trace("Exiting from SVCLogicServiceExecute");
281 * Filling response context by output.* fields from DG context. Works only for 2.* API version
283 * @param responseContext response context which you need to fill
284 * @param respProps DG context in a properties format
286 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
288 Enumeration<?> e = respProps.propertyNames();
289 while (e.hasMoreElements()){
290 String key = (String) e.nextElement();
291 if (key.startsWith("output.")){
292 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
294 if (key.equalsIgnoreCase("output.payload")){
295 responseContext.setPayload(respProps.getProperty(key));
297 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
305 * Filling responceContext status code amd message according to responce messages and codes from DG.
307 * @param responseContext response cotext
308 * @param commonStatus common status message from DG ("success" or "failure")
309 * @param specificStatusMessage specific status message from specific DG node
310 * @param specificStatusCode specific status code from specific DG node
312 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
313 if (null == specificStatusMessage) { specificStatusMessage = ""; }
314 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
315 if (specificStatusCode != 0 ){
316 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
318 fillStatus(400, commonStatus, responseContext);
321 String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
322 if (specificStatusCode != 0){
323 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
325 fillStatus(401, specificStatusMessage, responseContext);
331 * filling responseContext by status code and status message
333 * @param code 3-digit status code
334 * @param message explanation of a status code
335 * @param responceContext response context which will be store status code and status message
337 private void fillStatus(int code, String message, ResponseContext responceContext) {
338 responceContext.getStatus().setCode(code);
339 responceContext.getStatus().setMessage(message);