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.onap.appc.workflow.impl;
27 import org.apache.commons.lang.ObjectUtils;
28 import org.apache.commons.lang3.StringUtils;
29 import org.onap.appc.common.constant.Constants;
30 import org.onap.appc.configuration.Configuration;
31 import org.onap.appc.configuration.ConfigurationFactory;
32 import org.onap.appc.domainmodel.lcm.RequestContext;
33 import org.onap.appc.domainmodel.lcm.ResponseContext;
34 import org.onap.appc.domainmodel.lcm.Status;
35 import org.onap.appc.util.ObjectMapper;
36 import org.onap.appc.workflow.WorkFlowManager;
37 import org.onap.appc.workflow.objects.WorkflowExistsOutput;
38 import org.onap.appc.workflow.objects.WorkflowRequest;
39 import org.onap.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.Date;
47 import java.util.Enumeration;
49 import java.util.Properties;
52 public class WorkFlowManagerImpl implements WorkFlowManager{
53 private SvcLogicService svcLogic = null;
54 private static final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
55 private static final Configuration configuration = ConfigurationFactory.getConfiguration();
57 private final WorkflowResolver workflowResolver = new WorkflowResolver(
58 configuration.getIntegerProperty("org.onap.appc.workflow.resolver.refresh_interval", 300)
61 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
62 this.svcLogic = svcLogic;
66 * Execute workflow and return response.
67 * This method execute workflow with following steps.
68 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
69 * Execute workflow (DG) using SVC Logic Service reference
70 * Return response of workflow (DG) to caller.
72 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
73 * @return Workflow Response which contains execution status and payload from DG if any
77 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
78 if (logger.isTraceEnabled()) {
79 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
81 WorkflowResponse workflowResponse = new WorkflowResponse();
82 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
87 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
89 Properties workflowParams = new Properties();
90 String actionProperty = null;
91 String requestIdProperty=null;
92 String vfIdProperty =null;
93 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
95 The following method call (populateDGContext) populates DG context with the
96 request parameters to maintain backward compatibility with old DGs,
97 we are not altering the old way of passing (org.onap.appc.vnfId and so on..)
98 This is still a temporary solution, the end solution should be agreed with
99 all stakeholders and implemented.
101 populateDGContext(workflowParams,workflowRequest);
103 actionProperty = configuration.getProperty("org.onap.appc.workflow.action", String.valueOf(Constants.ACTION));
104 requestIdProperty = configuration.getProperty("org.onap.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
105 vfIdProperty = configuration.getProperty("org.onap.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
106 String payloadProperty = configuration.getProperty("org.onap.appc.workflow.payload", String.valueOf(Constants.PAYLOAD));
107 String vfTypeProperty = configuration.getProperty("org.onap.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
108 String apiVerProperty = configuration.getProperty("org.onap.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
109 String originatorIdProperty = configuration.getProperty("org.onap.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
110 String subRequestId = configuration.getProperty("org.onap.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
112 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
113 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
114 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
115 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
116 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
117 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
118 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
120 Object payloadJson = workflowRequest.getRequestContext().getPayload();
121 if(payloadJson!=null) {
123 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
124 workflowParams.putAll(payloadProperties);
126 if (logger.isDebugEnabled()) {
127 logger.debug("DG properties: " + workflowParams);
129 } catch (Exception e) {
130 logger.error("Error parsing payload json string", e);
131 Properties workflowPrp = new Properties();
132 workflowPrp.setProperty("error-message", "Error parsing payload json string");
133 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
134 if (logger.isTraceEnabled()) {
135 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
137 return workflowResponse;
140 if (logger.isDebugEnabled()) {
141 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
142 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
143 vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
145 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
148 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
149 workflowParams.put("isBwcMode","true");
151 workflowParams.put("isBwcMode", "false");
154 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
155 if (logger.isTraceEnabled()) {
156 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
158 }catch (Exception e){
159 logger.error("Error Executing DG " +e.getMessage());
160 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
162 if (logger.isTraceEnabled()) {
163 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
165 return workflowResponse;
168 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
169 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(Date.from(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp())));
170 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
171 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
172 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
173 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId()!=null ? workflowRequest.getRequestContext().getCommonHeader().getSubRequestId():"");
174 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
175 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
176 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
177 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
178 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
179 workflowParams.put("input.action-identifiers.vf-module-id",workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId():"");
180 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
181 final Map<String, String> additionalContext;
182 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
183 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
184 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
190 * Check if workflow (DG) exists in database
192 * @param workflowQueryParams workflow request with command and vnf Type
193 * @return True if workflow exists else False.
196 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
197 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
198 if (logger.isTraceEnabled()) {
199 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
203 WorkflowKey workflowKey = workflowResolver.resolve(
204 workflowQueryParams.getRequestContext().getAction().name(),
205 workflowQueryParams.getVnfContext().getType(),
206 workflowQueryParams.getVnfContext().getVersion(),
207 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
208 if (workflowKey != null) {
209 workflowExistsOutput.setMappingExist(true);
210 workflowExistsOutput.setWorkflowModule(workflowKey.module());
211 workflowExistsOutput.setWorkflowName(workflowKey.name());
212 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
213 if (isDGExists(workflowKey)) {
214 workflowExistsOutput.setDgExist(true);
217 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
218 workflowKey.module(), workflowKey.name(), workflowKey.version()));
222 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
223 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
225 } catch (RuntimeException e) {
226 logger.error("Error querying workflow from database"+e.getMessage());
228 }catch (SvcLogicException e) {
229 logger.error("Error querying workflow from database"+e.getMessage());
230 throw new RuntimeException(e);
232 if (logger.isTraceEnabled()) {
233 logger.trace("Exiting workflowExists");
235 return workflowExistsOutput;
239 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
240 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
243 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
244 if (logger.isTraceEnabled()) {
245 logger.trace("Entering SVCLogicServiceExecute");
248 Properties respProps = null;
251 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
252 } catch (Exception e) {
253 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
255 if (logger.isDebugEnabled()) {
256 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
258 logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
261 if (respProps != null) {
262 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
263 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
266 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
267 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
268 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
269 int specificStatusCode = 0;
270 if (dgOutputStatusCode != null) {
271 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
274 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
276 if (logger.isDebugEnabled()) {
277 logger.debug("DG Execution Status: " + commonStatus);
281 if (logger.isTraceEnabled()) {
282 logger.trace("Exiting from SVCLogicServiceExecute");
287 * Filling response context by output.* fields from DG context. Works only for 2.* API version
289 * @param responseContext response context which you need to fill
290 * @param respProps DG context in a properties format
292 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
294 Enumeration<?> e = respProps.propertyNames();
295 while (e.hasMoreElements()){
296 String key = (String) e.nextElement();
297 if (key.startsWith("output.")){
298 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
300 if (key.equalsIgnoreCase("output.payload")){
301 responseContext.setPayload(respProps.getProperty(key));
303 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
311 * Filling responceContext status code amd message according to responce messages and codes from DG.
313 * @param responseContext response cotext
314 * @param commonStatus common status message from DG ("success" or "failure")
315 * @param specificStatusMessage specific status message from specific DG node
316 * @param specificStatusCode specific status code from specific DG node
318 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
319 if (null == specificStatusMessage) { specificStatusMessage = ""; }
320 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
321 if (specificStatusCode != 0 ){
322 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
324 fillStatus(400, commonStatus, responseContext);
327 String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
328 if (specificStatusCode != 0){
329 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
331 fillStatus(401, specificStatusMessage, responseContext);
337 * filling responseContext by status code and status message
339 * @param code 3-digit status code
340 * @param message explanation of a status code
341 * @param responceContext response context which will be store status code and status message
343 private void fillStatus(int code, String message, ResponseContext responceContext) {
344 responceContext.setStatus(new Status(code, message));