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.onap.ccsdk.sli.core.sli.SvcLogicException;
43 import org.onap.ccsdk.sli.core.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.vf-module-id",workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId():"");
179 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
180 final Map<String, String> additionalContext;
181 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
182 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
183 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
189 * Check if workflow (DG) exists in database
191 * @param workflowQueryParams workflow request with command and vnf Type
192 * @return True if workflow exists else False.
195 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
196 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
197 if (logger.isTraceEnabled()) {
198 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
202 WorkflowKey workflowKey = workflowResolver.resolve(
203 workflowQueryParams.getRequestContext().getAction().name(),
204 workflowQueryParams.getVnfContext().getType(),
205 workflowQueryParams.getVnfContext().getVersion(),
206 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
207 if (workflowKey != null) {
208 workflowExistsOutput.setMappingExist(true);
209 workflowExistsOutput.setWorkflowModule(workflowKey.module());
210 workflowExistsOutput.setWorkflowName(workflowKey.name());
211 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
212 if (isDGExists(workflowKey)) {
213 workflowExistsOutput.setDgExist(true);
216 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
217 workflowKey.module(), workflowKey.name(), workflowKey.version()));
221 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
222 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
224 } catch (RuntimeException e) {
225 logger.error("Error querying workflow from database"+e.getMessage());
227 }catch (SvcLogicException e) {
228 logger.error("Error querying workflow from database"+e.getMessage());
229 throw new RuntimeException(e);
231 if (logger.isTraceEnabled()) {
232 logger.trace("Exiting workflowExists");
234 return workflowExistsOutput;
238 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
239 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
242 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
243 if (logger.isTraceEnabled()) {
244 logger.trace("Entering SVCLogicServiceExecute");
247 Properties respProps = null;
250 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
251 } catch (Exception e) {
252 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
254 if (logger.isDebugEnabled()) {
255 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
257 logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
260 if (respProps != null) {
261 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
262 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
265 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
266 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
267 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
268 int specificStatusCode = 0;
269 if (dgOutputStatusCode != null) {
270 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
273 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
275 if (logger.isDebugEnabled()) {
276 logger.debug("DG Execution Status: " + commonStatus);
280 if (logger.isTraceEnabled()) {
281 logger.trace("Exiting from SVCLogicServiceExecute");
286 * Filling response context by output.* fields from DG context. Works only for 2.* API version
288 * @param responseContext response context which you need to fill
289 * @param respProps DG context in a properties format
291 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
293 Enumeration<?> e = respProps.propertyNames();
294 while (e.hasMoreElements()){
295 String key = (String) e.nextElement();
296 if (key.startsWith("output.")){
297 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
299 if (key.equalsIgnoreCase("output.payload")){
300 responseContext.setPayload(respProps.getProperty(key));
302 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
310 * Filling responceContext status code amd message according to responce messages and codes from DG.
312 * @param responseContext response cotext
313 * @param commonStatus common status message from DG ("success" or "failure")
314 * @param specificStatusMessage specific status message from specific DG node
315 * @param specificStatusCode specific status code from specific DG node
317 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
318 if (null == specificStatusMessage) { specificStatusMessage = ""; }
319 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
320 if (specificStatusCode != 0 ){
321 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
323 fillStatus(400, commonStatus, responseContext);
326 String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
327 if (specificStatusCode != 0){
328 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
330 fillStatus(401, specificStatusMessage, responseContext);
336 * filling responseContext by status code and status message
338 * @param code 3-digit status code
339 * @param message explanation of a status code
340 * @param responceContext response context which will be store status code and status message
342 private void fillStatus(int code, String message, ResponseContext responceContext) {
343 responceContext.setStatus(new Status(code, message));