2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Amdocs
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=========================================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.appc.workflow.impl;
25 import org.apache.commons.lang.ObjectUtils;
26 import org.apache.commons.lang3.StringUtils;
27 import org.openecomp.appc.common.constant.Constants;
28 import org.openecomp.appc.configuration.Configuration;
29 import org.openecomp.appc.configuration.ConfigurationFactory;
30 import org.openecomp.appc.domainmodel.lcm.RequestContext;
31 import org.openecomp.appc.domainmodel.lcm.ResponseContext;
32 import org.openecomp.appc.domainmodel.lcm.Status;
33 import org.openecomp.appc.util.ObjectMapper;
34 import org.openecomp.appc.workflow.WorkFlowManager;
35 import org.openecomp.appc.workflow.objects.WorkflowExistsOutput;
36 import org.openecomp.appc.workflow.objects.WorkflowRequest;
37 import org.openecomp.appc.workflow.objects.WorkflowResponse;
38 import com.att.eelf.configuration.EELFLogger;
39 import com.att.eelf.configuration.EELFManager;
40 import org.openecomp.sdnc.sli.SvcLogicException;
41 import org.openecomp.sdnc.sli.provider.SvcLogicService;
43 import java.text.SimpleDateFormat;
44 import java.util.Enumeration;
46 import java.util.Properties;
49 public class WorkFlowManagerImpl implements WorkFlowManager{
50 private SvcLogicService svcLogic = null;
51 private static final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
52 private static final Configuration configuration = ConfigurationFactory.getConfiguration();
54 private final WorkflowResolver workflowResolver = new WorkflowResolver(
55 configuration.getIntegerProperty("org.openecomp.appc.workflow.resolver.refresh_interval", 300)
58 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
59 this.svcLogic = svcLogic;
63 * Execute workflow and return response.
64 * This method execute workflow with following steps.
65 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
66 * Execute workflow (DG) using SVC Logic Service reference
67 * Return response of workflow (DG) to caller.
69 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
70 * @return Workflow Response which contains execution status and payload from DG if any
74 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
75 if (logger.isTraceEnabled()) {
76 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
78 WorkflowResponse workflowResponse = new WorkflowResponse();
79 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
84 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
86 Properties workflowParams = new Properties();
87 String actionProperty = null;
88 String requestIdProperty=null;
89 String vfIdProperty =null;
90 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
92 The following method call (populateDGContext) populates DG context with the
93 request parameters to maintain backward compatibility with old DGs,
94 we are not altering the old way of passing (org.openecomp.appc.vnfId and so on..)
95 This is still a temporary solution, the end solution should be agreed with
96 all stakeholders and implemented.
98 populateDGContext(workflowParams,workflowRequest);
100 actionProperty = configuration.getProperty("org.openecomp.appc.workflow.action", String.valueOf(Constants.ACTION));
101 requestIdProperty = configuration.getProperty("org.openecomp.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
102 vfIdProperty = configuration.getProperty("org.openecomp.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
103 String payloadProperty = configuration.getProperty("org.openecomp.appc.workflow.payload", String.valueOf(Constants.PAYLOAD));
104 String vfTypeProperty = configuration.getProperty("org.openecomp.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
105 String apiVerProperty = configuration.getProperty("org.openecomp.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
106 String originatorIdProperty = configuration.getProperty("org.openecomp.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
107 String subRequestId = configuration.getProperty("org.openecomp.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
109 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
110 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
111 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
112 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
113 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
114 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
115 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
117 Object payloadJson = workflowRequest.getRequestContext().getPayload();
118 if(payloadJson!=null) {
120 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
121 workflowParams.putAll(payloadProperties);
123 if (logger.isDebugEnabled()) {
124 logger.debug("DG properties: " + workflowParams);
126 } catch (Exception e) {
127 logger.error("Error parsing payload json string", e);
128 Properties workflowPrp = new Properties();
129 workflowPrp.setProperty("error-message", "Error parsing payload json string");
130 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
131 if (logger.isTraceEnabled()) {
132 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
134 return workflowResponse;
137 if (logger.isDebugEnabled()) {
138 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
139 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
140 vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
142 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
145 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
146 workflowParams.put("isBwcMode","true");
148 workflowParams.put("isBwcMode", "false");
151 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
152 if (logger.isTraceEnabled()) {
153 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
155 }catch (Exception e){
156 logger.error("Error Executing DG " +e.getMessage());
157 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
159 if (logger.isTraceEnabled()) {
160 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
162 return workflowResponse;
165 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
166 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
167 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
168 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
169 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
170 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId()!=null ? workflowRequest.getRequestContext().getCommonHeader().getSubRequestId():"");
171 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
172 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
173 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
174 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
175 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
176 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
177 final Map<String, String> additionalContext;
178 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
179 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
180 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
186 * Check if workflow (DG) exists in database
188 * @param workflowQueryParams workflow request with command and vnf Type
189 * @return True if workflow exists else False.
192 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
193 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
194 if (logger.isTraceEnabled()) {
195 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
199 WorkflowKey workflowKey = workflowResolver.resolve(
200 workflowQueryParams.getRequestContext().getAction().name(),
201 workflowQueryParams.getVnfContext().getType(),
202 workflowQueryParams.getVnfContext().getVersion(),
203 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
204 if (workflowKey != null) {
205 workflowExistsOutput.setMappingExist(true);
206 workflowExistsOutput.setWorkflowModule(workflowKey.module());
207 workflowExistsOutput.setWorkflowName(workflowKey.name());
208 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
209 if (isDGExists(workflowKey)) {
210 workflowExistsOutput.setDgExist(true);
213 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
214 workflowKey.module(), workflowKey.name(), workflowKey.version()));
218 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
219 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
221 } catch (RuntimeException e) {
222 logger.error("Error querying workflow from database"+e.getMessage());
224 }catch (SvcLogicException e) {
225 logger.error("Error querying workflow from database"+e.getMessage());
226 throw new RuntimeException(e);
228 if (logger.isTraceEnabled()) {
229 logger.trace("Exiting workflowExists");
231 return workflowExistsOutput;
235 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
236 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
239 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
240 if (logger.isTraceEnabled()) {
241 logger.trace("Entering SVCLogicServiceExecute");
244 Properties respProps = null;
247 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
248 } catch (Exception e) {
249 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
251 if (logger.isDebugEnabled()) {
252 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
254 logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
257 if (respProps != null) {
258 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
259 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
262 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
263 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
264 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
265 int specificStatusCode = 0;
266 if (dgOutputStatusCode != null) {
267 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
270 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
272 if (logger.isDebugEnabled()) {
273 logger.debug("DG Execution Status: " + commonStatus);
277 if (logger.isTraceEnabled()) {
278 logger.trace("Exiting from SVCLogicServiceExecute");
283 * Filling response context by output.* fields from DG context. Works only for 2.* API version
285 * @param responseContext response context which you need to fill
286 * @param respProps DG context in a properties format
288 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
290 Enumeration<?> e = respProps.propertyNames();
291 while (e.hasMoreElements()){
292 String key = (String) e.nextElement();
293 if (key.startsWith("output.")){
294 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
296 if (key.equalsIgnoreCase("output.payload")){
297 responseContext.setPayload(respProps.getProperty(key));
299 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
307 * Filling responceContext status code amd message according to responce messages and codes from DG.
309 * @param responseContext response cotext
310 * @param commonStatus common status message from DG ("success" or "failure")
311 * @param specificStatusMessage specific status message from specific DG node
312 * @param specificStatusCode specific status code from specific DG node
314 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
315 if (null == specificStatusMessage) { specificStatusMessage = ""; }
316 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
317 if (specificStatusCode != 0 ){
318 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
320 fillStatus(400, commonStatus, responseContext);
323 String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
324 if (specificStatusCode != 0){
325 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
327 fillStatus(401, specificStatusMessage, responseContext);
333 * filling responseContext by status code and status message
335 * @param code 3-digit status code
336 * @param message explanation of a status code
337 * @param responceContext response context which will be store status code and status message
339 private void fillStatus(int code, String message, ResponseContext responceContext) {
340 responceContext.setStatus(new Status(code, message));