2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 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 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.openecomp.appc.workflow.impl;
27 import org.apache.commons.lang.ObjectUtils;
28 import org.apache.commons.lang3.StringUtils;
29 import org.openecomp.appc.common.constant.Constants;
30 import org.openecomp.appc.configuration.Configuration;
31 import org.openecomp.appc.configuration.ConfigurationFactory;
32 import org.openecomp.appc.domainmodel.lcm.RequestContext;
33 import org.openecomp.appc.domainmodel.lcm.ResponseContext;
34 import org.openecomp.appc.domainmodel.lcm.Status;
35 import org.openecomp.appc.util.ObjectMapper;
36 import org.openecomp.appc.workflow.WorkFlowManager;
37 import org.openecomp.appc.workflow.objects.WorkflowExistsOutput;
38 import org.openecomp.appc.workflow.objects.WorkflowRequest;
39 import org.openecomp.appc.workflow.objects.WorkflowResponse;
40 import com.att.eelf.configuration.EELFLogger;
41 import com.att.eelf.configuration.EELFManager;
42 import org.openecomp.sdnc.sli.SvcLogicException;
43 import org.openecomp.sdnc.sli.provider.SvcLogicService;
45 import java.text.SimpleDateFormat;
46 import java.util.Enumeration;
48 import java.util.Properties;
51 public class WorkFlowManagerImpl implements WorkFlowManager{
52 private SvcLogicService svcLogic = null;
53 private static final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
54 private static final Configuration configuration = ConfigurationFactory.getConfiguration();
56 private final WorkflowResolver workflowResolver = new WorkflowResolver(
57 configuration.getIntegerProperty("org.openecomp.appc.workflow.resolver.refresh_interval", 300)
60 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
61 this.svcLogic = svcLogic;
65 * Execute workflow and return response.
66 * This method execute workflow with following steps.
67 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
68 * Execute workflow (DG) using SVC Logic Service reference
69 * Return response of workflow (DG) to caller.
71 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
72 * @return Workflow Response which contains execution status and payload from DG if any
76 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
77 if (logger.isTraceEnabled()) {
78 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
80 WorkflowResponse workflowResponse = new WorkflowResponse();
81 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
86 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
88 Properties workflowParams = new Properties();
89 String actionProperty = null;
90 String requestIdProperty=null;
91 String vfIdProperty =null;
92 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
94 The following method call (populateDGContext) populates DG context with the
95 request parameters to maintain backward compatibility with old DGs,
96 we are not altering the old way of passing (org.openecomp.appc.vnfId and so on..)
97 This is still a temporary solution, the end solution should be agreed with
98 all stakeholders and implemented.
100 populateDGContext(workflowParams,workflowRequest);
102 actionProperty = configuration.getProperty("org.openecomp.appc.workflow.action", String.valueOf(Constants.ACTION));
103 requestIdProperty = configuration.getProperty("org.openecomp.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
104 vfIdProperty = configuration.getProperty("org.openecomp.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
105 String payloadProperty = configuration.getProperty("org.openecomp.appc.workflow.payload", String.valueOf(Constants.PAYLOAD));
106 String vfTypeProperty = configuration.getProperty("org.openecomp.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
107 String apiVerProperty = configuration.getProperty("org.openecomp.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
108 String originatorIdProperty = configuration.getProperty("org.openecomp.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
109 String subRequestId = configuration.getProperty("org.openecomp.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
111 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
112 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
113 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
114 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
115 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
116 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
117 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
119 Object payloadJson = workflowRequest.getRequestContext().getPayload();
120 if(payloadJson!=null) {
122 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
123 workflowParams.putAll(payloadProperties);
125 if (logger.isDebugEnabled()) {
126 logger.debug("DG properties: " + workflowParams);
128 } catch (Exception e) {
129 logger.error("Error parsing payload json string", e);
130 Properties workflowPrp = new Properties();
131 workflowPrp.setProperty("error-message", "Error parsing payload json string");
132 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
133 if (logger.isTraceEnabled()) {
134 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
136 return workflowResponse;
139 if (logger.isDebugEnabled()) {
140 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
141 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
142 vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
144 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
147 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
148 workflowParams.put("isBwcMode","true");
150 workflowParams.put("isBwcMode", "false");
153 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
154 if (logger.isTraceEnabled()) {
155 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
157 }catch (Exception e){
158 logger.error("Error Executing DG " +e.getMessage());
159 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
161 if (logger.isTraceEnabled()) {
162 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
164 return workflowResponse;
167 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
168 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
169 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
170 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
171 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
172 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId()!=null ? workflowRequest.getRequestContext().getCommonHeader().getSubRequestId():"");
173 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
174 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
175 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
176 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
177 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
178 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
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 if (logger.isTraceEnabled()) {
197 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
201 WorkflowKey workflowKey = workflowResolver.resolve(
202 workflowQueryParams.getRequestContext().getAction().name(),
203 workflowQueryParams.getVnfContext().getType(),
204 workflowQueryParams.getVnfContext().getVersion(),
205 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
206 if (workflowKey != null) {
207 workflowExistsOutput.setMappingExist(true);
208 workflowExistsOutput.setWorkflowModule(workflowKey.module());
209 workflowExistsOutput.setWorkflowName(workflowKey.name());
210 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
211 if (isDGExists(workflowKey)) {
212 workflowExistsOutput.setDgExist(true);
215 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
216 workflowKey.module(), workflowKey.name(), workflowKey.version()));
220 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
221 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
223 } catch (RuntimeException e) {
224 logger.error("Error querying workflow from database"+e.getMessage());
226 }catch (SvcLogicException e) {
227 logger.error("Error querying workflow from database"+e.getMessage());
228 throw new RuntimeException(e);
230 if (logger.isTraceEnabled()) {
231 logger.trace("Exiting workflowExists");
233 return workflowExistsOutput;
237 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
238 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
241 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
242 if (logger.isTraceEnabled()) {
243 logger.trace("Entering SVCLogicServiceExecute");
246 Properties respProps = null;
249 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
250 } catch (Exception e) {
251 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
253 if (logger.isDebugEnabled()) {
254 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
256 logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
259 if (respProps != null) {
260 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
261 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
264 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
265 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
266 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
267 int specificStatusCode = 0;
268 if (dgOutputStatusCode != null) {
269 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
272 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
274 if (logger.isDebugEnabled()) {
275 logger.debug("DG Execution Status: " + commonStatus);
279 if (logger.isTraceEnabled()) {
280 logger.trace("Exiting from SVCLogicServiceExecute");
285 * Filling response context by output.* fields from DG context. Works only for 2.* API version
287 * @param responseContext response context which you need to fill
288 * @param respProps DG context in a properties format
290 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
292 Enumeration<?> e = respProps.propertyNames();
293 while (e.hasMoreElements()){
294 String key = (String) e.nextElement();
295 if (key.startsWith("output.")){
296 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
298 if (key.equalsIgnoreCase("output.payload")){
299 responseContext.setPayload(respProps.getProperty(key));
301 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
309 * Filling responceContext status code amd message according to responce messages and codes from DG.
311 * @param responseContext response cotext
312 * @param commonStatus common status message from DG ("success" or "failure")
313 * @param specificStatusMessage specific status message from specific DG node
314 * @param specificStatusCode specific status code from specific DG node
316 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
317 if (null == specificStatusMessage) { specificStatusMessage = ""; }
318 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
319 if (specificStatusCode != 0 ){
320 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
322 fillStatus(400, commonStatus, responseContext);
325 String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
326 if (specificStatusCode != 0){
327 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
329 fillStatus(401, specificStatusMessage, responseContext);
335 * filling responseContext by status code and status message
337 * @param code 3-digit status code
338 * @param message explanation of a status code
339 * @param responceContext response context which will be store status code and status message
341 private void fillStatus(int code, String message, ResponseContext responceContext) {
342 responceContext.setStatus(new Status(code, message));