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.util.ObjectMapper;
35 import org.onap.appc.workflow.WorkFlowManager;
36 import org.onap.appc.workflow.objects.WorkflowExistsOutput;
37 import org.onap.appc.workflow.objects.WorkflowRequest;
38 import org.onap.appc.workflow.objects.WorkflowResponse;
39 import com.att.eelf.configuration.EELFLogger;
40 import com.att.eelf.configuration.EELFManager;
41 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
42 import org.onap.ccsdk.sli.core.sli.provider.SvcLogicService;
44 import java.text.SimpleDateFormat;
45 import java.util.Arrays;
46 import java.util.Enumeration;
48 import java.util.Properties;
51 public class WorkFlowManagerImpl implements WorkFlowManager{
52 private SvcLogicService svcLogic = null;
53 private final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
54 private final Configuration configuration = ConfigurationFactory.getConfiguration();
56 private WorkflowResolver workflowResolver = new WorkflowResolver(
57 configuration.getIntegerProperty("org.onap.appc.workflow.resolver.refresh_interval", 300)
60 public void setWorkflowResolver(WorkflowResolver workflowResolver){
61 this.workflowResolver=workflowResolver;
64 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
65 this.svcLogic = svcLogic;
69 * Execute workflow and return response.
70 * This method execute workflow with following steps.
71 * Retrieve workflow(DG) details - module, version and mode from database based on command and vnf Type from incoming request.
72 * Execute workflow (DG) using SVC Logic Service reference
73 * Return response of workflow (DG) to caller.
75 * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
76 * @return Workflow Response which contains execution status and payload from DG if any
80 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
81 if (logger.isTraceEnabled()) {
82 logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
84 WorkflowResponse workflowResponse = new WorkflowResponse();
85 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
90 WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
92 Properties workflowParams = new Properties();
93 String actionProperty;
94 String requestIdProperty;
96 if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
98 The following method call (populateDGContext) populates DG context with the
99 request parameters to maintain backward compatibility with old DGs,
100 we are not altering the old way of passing (org.onap.appc.vnfId and so on..)
101 This is still a temporary solution, the end solution should be agreed with
102 all stakeholders and implemented.
104 populateDGContext(workflowParams,workflowRequest);
106 actionProperty = configuration.getProperty("org.onap.appc.workflow.action", String.valueOf(Constants.ACTION));
107 requestIdProperty = configuration.getProperty("org.onap.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
108 vfIdProperty = configuration.getProperty("org.onap.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
109 String vfTypeProperty = configuration.getProperty("org.onap.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
110 String apiVerProperty = configuration.getProperty("org.onap.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
111 String originatorIdProperty = configuration.getProperty("org.onap.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
112 String subRequestId = configuration.getProperty("org.onap.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
114 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
115 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
116 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
117 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
118 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
119 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
120 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
122 Object payloadJson = workflowRequest.getRequestContext().getPayload();
123 if(payloadJson!=null) {
125 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
126 workflowParams.putAll(payloadProperties);
128 if (logger.isDebugEnabled()) {
129 logger.debug("DG properties: " + workflowParams);
131 } catch (Exception e) {
132 logger.error("Error parsing payload json string", e);
133 Properties workflowPrp = new Properties();
134 workflowPrp.setProperty("error-message", "Error parsing payload json string");
135 fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
136 if (logger.isTraceEnabled()) {
137 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
139 return workflowResponse;
142 if (logger.isDebugEnabled()) {
143 logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
144 requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
145 vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
147 logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
150 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
151 workflowParams.put("isBwcMode","true");
153 workflowParams.put("isBwcMode", "false");
156 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
157 if (logger.isTraceEnabled()) {
158 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
160 }catch (Exception e){
161 logger.error("Error Executing DG " +e.getMessage(),e);
162 fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
164 if (logger.isTraceEnabled()) {
165 logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
167 return workflowResponse;
170 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
171 workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
172 workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
173 workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
174 workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
175 workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId()!=null ? workflowRequest.getRequestContext().getCommonHeader().getSubRequestId():"");
176 workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
177 workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
178 workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
179 workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
180 workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
181 workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
182 workflowParams.put("input.action-identifiers.vf-module-id",workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId():"");
183 final Map<String, String> additionalContext;
184 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
185 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
186 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
192 * Check if workflow (DG) exists in database
194 * @param workflowQueryParams workflow request with command and vnf Type
195 * @return True if workflow exists else False.
198 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
199 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
200 if (logger.isTraceEnabled()) {
201 logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
205 WorkflowKey workflowKey = workflowResolver.resolve(
206 workflowQueryParams.getRequestContext().getAction().name(),
207 workflowQueryParams.getVnfContext().getType(),
208 workflowQueryParams.getVnfContext().getVersion(),
209 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
210 if (workflowKey != null) {
211 workflowExistsOutput.setMappingExist(true);
212 workflowExistsOutput.setWorkflowModule(workflowKey.module());
213 workflowExistsOutput.setWorkflowName(workflowKey.name());
214 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
215 if (isDGExists(workflowKey)) {
216 workflowExistsOutput.setDgExist(true);
219 String.format("SLI doesn't have DG for resolved mapping entry: DG module - '%s', DG name - '%s', DG version - '%s'",
220 workflowKey.module(), workflowKey.name(), workflowKey.version()));
224 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
225 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
227 } catch (RuntimeException e) {
228 logger.error("Error querying workflow from database"+e.getMessage());
230 }catch (SvcLogicException e) {
231 logger.error("Error querying workflow from database"+e.getMessage());
232 throw new RuntimeException(e);
234 if (logger.isTraceEnabled()) {
235 logger.trace("Exiting workflowExists");
237 return workflowExistsOutput;
241 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
242 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
245 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
246 if (logger.isTraceEnabled()) {
247 logger.trace("Entering SVCLogicServiceExecute");
250 Properties respProps = null;
253 respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
254 } catch (Exception e) {
255 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
257 if (logger.isDebugEnabled()) {
258 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
260 logger.error("Error in DG", e.getMessage()+ Arrays.toString(e.getStackTrace()),e);
263 if (respProps != null) {
264 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
265 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
268 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
269 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
270 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
271 int specificStatusCode = 0;
272 if (dgOutputStatusCode != null) {
273 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
276 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
278 if (logger.isDebugEnabled()) {
279 logger.debug("DG Execution Status: " + commonStatus);
283 if (logger.isTraceEnabled()) {
284 logger.trace("Exiting from SVCLogicServiceExecute");
289 * Filling response context by output.* fields from DG context. Works only for 2.* API version
291 * @param responseContext response context which you need to fill
292 * @param respProps DG context in a properties format
294 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
296 Enumeration<?> e = respProps.propertyNames();
297 while (e.hasMoreElements()){
298 String key = (String) e.nextElement();
299 if (key.startsWith("output.")){
300 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
302 if (key.equalsIgnoreCase("output.payload")){
303 responseContext.setPayload(respProps.getProperty(key));
305 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
313 * Filling responceContext status code amd message according to responce messages and codes from DG.
315 * @param responseContext response cotext
316 * @param commonStatus common status message from DG ("success" or "failure")
317 * @param specificStatusMessage specific status message from specific DG node
318 * @param specificStatusCode specific status code from specific DG node
320 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
321 if (null == specificStatusMessage) { specificStatusMessage = ""; }
322 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
323 if (specificStatusCode != 0 ){
324 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
326 fillStatus(400, commonStatus, responseContext);
329 if (specificStatusCode != 0){
330 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
332 fillStatus(401, specificStatusMessage, responseContext);
338 * filling responseContext by status code and status message
340 * @param code 3-digit status code
341 * @param message explanation of a status code
342 * @param responceContext response context which will be store status code and status message
344 private void fillStatus(int code, String message, ResponseContext responceContext) {
345 responceContext.getStatus().setCode(code);
346 responceContext.getStatus().setMessage(message);