2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 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.
20 * ============LICENSE_END=========================================================
23 package org.onap.appc.workflow.impl;
25 import org.apache.commons.lang.ObjectUtils;
26 import org.onap.appc.common.constant.Constants;
27 import org.onap.appc.configuration.Configuration;
28 import org.onap.appc.configuration.ConfigurationFactory;
29 import org.onap.appc.domainmodel.lcm.RequestContext;
30 import org.onap.appc.domainmodel.lcm.ResponseContext;
31 import org.onap.appc.util.ObjectMapper;
32 import org.onap.appc.workflow.WorkFlowManager;
33 import org.onap.appc.workflow.objects.WorkflowExistsOutput;
34 import org.onap.appc.workflow.objects.WorkflowRequest;
35 import org.onap.appc.workflow.objects.WorkflowResponse;
36 import com.att.eelf.configuration.EELFLogger;
37 import com.att.eelf.configuration.EELFManager;
38 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
39 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
40 import org.onap.ccsdk.sli.core.sli.provider.SvcLogicService;
42 import org.osgi.framework.Bundle;
43 import org.osgi.framework.BundleContext;
44 import org.osgi.framework.FrameworkUtil;
45 import org.osgi.framework.ServiceReference;
46 import java.util.ArrayList;
47 import org.onap.ccsdk.sli.core.dblib.DbLibService;
48 import org.onap.ccsdk.sli.core.sli.SvcLogicGraph;
49 import javax.sql.rowset.CachedRowSet;
50 import java.sql.SQLException;
51 import java.io.ObjectInputStream;
52 import java.io.IOException;
57 import java.text.SimpleDateFormat;
58 import java.util.Arrays;
59 import java.util.Enumeration;
61 import java.util.Properties;
64 public class WorkFlowManagerImpl implements WorkFlowManager{
65 private static final String DRIVER_ERROR = "DriverLoadError";
66 private SvcLogicService svcLogic = null;
67 private final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
68 private final Configuration configuration = ConfigurationFactory.getConfiguration();
70 private WorkflowResolver workflowResolver = new WorkflowResolver(
71 configuration.getIntegerProperty("org.onap.appc.workflow.resolver.refresh_interval", 300)
74 public void setWorkflowResolver(WorkflowResolver workflowResolver){
75 this.workflowResolver = workflowResolver;
78 public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
79 this.svcLogic = svcLogic;
83 * Execute workflow and return response.
84 * This method execute workflow with following steps.
85 * Retrieve workflow(DG) details - module, version and mode from database
86 * based on command and vnf Type from incoming request.
87 * Execute workflow (DG) using SVC Logic Service reference
88 * Return response of workflow (DG) to caller.
90 * @param workflowRequest workflow execution request which contains vnfType,
91 * command, requestId, targetId, payload and (optional) confID;
92 * @return Workflow Response which contains execution status and payload from DG if any
96 public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
97 logger.trace("Entering to executeWorkflow with WorkflowRequest = "
98 + ObjectUtils.toString(workflowRequest.toString()));
99 WorkflowResponse workflowResponse = new WorkflowResponse();
100 workflowResponse.setResponseContext(workflowRequest.getResponseContext());
103 WorkflowKey workflowKey =
104 workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(),
105 workflowRequest.getVnfContext().getType(), null,
106 workflowRequest.getRequestContext().getCommonHeader().getApiVer());
108 Properties workflowParams = new Properties();
109 String actionProperty;
110 String requestIdProperty;
112 if (!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")) {
114 The following method call (populateDGContext) populates DG context with the
115 request parameters to maintain backward compatibility with old DGs,
116 we are not altering the old way of passing (org.onap.appc.vnfId and so on..)
117 This is still a temporary solution, the end solution should be agreed with
118 all stakeholders and implemented.
120 populateDGContext(workflowParams, workflowRequest);
123 configuration.getProperty("org.onap.appc.workflow.action", String.valueOf(Constants.ACTION));
125 configuration.getProperty("org.onap.appc.workflow.request.id",
126 String.valueOf(Constants.REQUEST_ID));
128 configuration.getProperty("org.onap.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
129 String vfTypeProperty =
130 configuration.getProperty("org.onap.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
131 String apiVerProperty =
132 configuration.getProperty("org.onap.appc.workflow.apiVersion",
133 String.valueOf(Constants.API_VERSION));
134 String originatorIdProperty =
135 configuration.getProperty("org.onap.appc.workflow.originatorId", Constants.ORIGINATOR_ID);
136 String subRequestId =
137 configuration.getProperty("org.onap.appc.workflow.subRequestId", Constants.SUB_REQUEST_ID);
139 workflowParams.put(actionProperty, workflowRequest.getRequestContext().getAction().name());
140 workflowParams.put(requestIdProperty,
141 workflowRequest.getRequestContext().getCommonHeader().getRequestId());
142 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
143 workflowParams.put(vfTypeProperty, workflowRequest.getVnfContext().getType());
144 workflowParams.put(apiVerProperty, workflowRequest.getRequestContext().getCommonHeader().getApiVer());
145 workflowParams.put(originatorIdProperty,
146 workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
147 workflowParams.put(subRequestId,
148 workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
150 Object payloadJson = workflowRequest.getRequestContext().getPayload();
151 if (payloadJson != null) {
153 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
154 workflowParams.putAll(payloadProperties);
156 logger.debug("DG properties: " + workflowParams);
157 } catch (Exception e) {
158 logger.error("Error parsing payload json string", e);
159 Properties workflowPrp = new Properties();
160 workflowPrp.setProperty("error-message", "Error parsing payload json string");
161 fillStatus(501, "Error parsing payload json string: " + e.getMessage(),
162 workflowRequest.getResponseContext());
163 logger.trace("Exiting from executeWorkflow with (workflowResponse = "
164 + ObjectUtils.toString(workflowResponse) + ")");
165 return workflowResponse;
168 logger.debug("DG parameters " + actionProperty + ":"
169 + workflowRequest.getRequestContext().getAction().name() + ", "
170 + requestIdProperty + ":"
171 + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + ", "
172 + vfIdProperty + ":" + workflowRequest.getVnfContext().getId());
174 logger.debug("Starting DG Execution for request "
175 + workflowRequest.getRequestContext().getCommonHeader().getRequestId());
177 if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")) {
178 workflowParams.put("isBwcMode", "true");
180 workflowParams.put("isBwcMode", "false");
183 SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams,
185 logger.trace("Completed DG Execution for Request id: "
186 + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + " with response code: "
187 + workflowResponse.getResponseContext().getStatus().getCode());
188 } catch (Exception e) {
189 logger.error("Error Executing DG " + e.getMessage(), e);
190 fillStatus(501, "Error Executing DG " + e.getMessage(), workflowRequest.getResponseContext());
192 logger.trace("Exiting from executeWorkflow with (workflowResponse = "
193 + ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage()) + ")");
194 return workflowResponse;
197 private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
198 workflowParams.put("input.common-header.timestamp",
199 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
200 .format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
201 workflowParams.put("input.common-header.api-ver",
202 workflowRequest.getRequestContext().getCommonHeader().getApiVer());
203 workflowParams.put("input.common-header.request-id",
204 workflowRequest.getRequestContext().getCommonHeader().getRequestId());
205 workflowParams.put("input.common-header.originator-id",
206 workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
207 workflowParams.put("input.common-header.sub-request-id",
208 workflowRequest.getRequestContext().getCommonHeader().getSubRequestId() != null ?
209 workflowRequest.getRequestContext().getCommonHeader().getSubRequestId() : "");
210 workflowParams.put("input.action", workflowRequest.getRequestContext().getAction().toString());
211 workflowParams.put("input.payload",
212 null != workflowRequest.getRequestContext().getPayload() ?
213 workflowRequest.getRequestContext().getPayload() : "");
214 workflowParams.put("input.action-identifiers.vnf-id", workflowRequest.getVnfContext().getId());
215 workflowParams.put("input.action-identifiers.vnfc-name",
216 workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName() != null ?
217 workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName() : "");
218 workflowParams.put("input.action-identifiers.service-instance-id",
219 workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId() != null ?
220 workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId() : "");
221 workflowParams.put("input.action-identifiers.vserver-id",
222 workflowRequest.getRequestContext().getActionIdentifiers().getVserverId() != null ?
223 workflowRequest.getRequestContext().getActionIdentifiers().getVserverId() : "");
224 workflowParams.put("input.action-identifiers.vf-module-id",
225 workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId() != null ?
226 workflowRequest.getRequestContext().getActionIdentifiers().getVfModuleId() : "");
227 final Map<String, String> additionalContext;
228 if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext()) != null) {
229 for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
230 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
236 * Check if workflow (DG) exists in database
238 * @param workflowQueryParams workflow request with command and vnf Type
239 * @return True if workflow exists else False.
242 public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
243 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false, false);
244 logger.trace("Entering to workflowExists with WorkflowRequest = "
245 + ObjectUtils.toString(workflowQueryParams.toString()));
248 WorkflowKey workflowKey = workflowResolver.resolve(
249 workflowQueryParams.getRequestContext().getAction().name(),
250 workflowQueryParams.getVnfContext().getType(),
251 workflowQueryParams.getVnfContext().getVersion(),
252 workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
253 if (workflowKey != null) {
254 workflowExistsOutput.setMappingExist(true);
255 workflowExistsOutput.setWorkflowModule(workflowKey.module());
256 workflowExistsOutput.setWorkflowName(workflowKey.name());
257 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
258 if (isDGExists(workflowKey)) {
259 workflowExistsOutput.setDgExist(true);
262 String.format("SLI doesn't have DG for resolved mapping entry: "
263 + "DG module - '%s', DG name - '%s', DG version - '%s'",
264 workflowKey.module(), workflowKey.name(), workflowKey.version()));
268 String.format("Unable to resolve recipe matching action '%s', VNF type '%s'"
269 + " and VNF version '%s'",
270 workflowQueryParams.getRequestContext().getAction().name(),
271 workflowQueryParams.getVnfContext().getType(), null));
273 } catch (RuntimeException e) {
274 logger.error("Error querying workflow from database" + e.getMessage());
276 } catch (SvcLogicException e) {
277 logger.error("Error querying workflow from database" + e.getMessage());
278 throw new RuntimeException(e);
280 logger.trace("Exiting workflowExists");
281 return workflowExistsOutput;
285 private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
286 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
290 private void restartDbLibProvider() {
292 Bundle bundle = FrameworkUtil.getBundle(org.onap.ccsdk.sli.core.dblib.DbLibService.class);
296 //Thread.sleep(5000);
297 } catch (org.osgi.framework.BundleException be) {
298 logger.error("Error restarting db lib" + be.toString());
299 } /*catch (InterruptedException e) {
303 private SvcLogicGraph fetchGraph(String module, String rpc, String version, String mode, StringBuilder sbError)
305 DbLibService dbLibSvc = null;
307 ServiceReference sref = null;
308 BundleContext bctx = null;
310 Bundle bundle = FrameworkUtil.getBundle(WorkFlowManagerImpl.class);
312 if (bundle != null) {
313 bctx = bundle.getBundleContext();
316 sref = bctx.getServiceReference("org.onap.ccsdk.sli.core.dblib.DbLibService");
320 logger.warn("Could not find service reference for DBLIB service");
322 dbLibSvc = (DbLibService) bctx.getService(sref);
323 if (dbLibSvc == null) {
324 logger.warn("Could not find service reference for DBLIB service");
328 if (dbLibSvc == null)
331 logger.info("Retrieving graph(new)");
333 SvcLogicGraph retval = null;
334 CachedRowSet results = null;
336 String fetchVersionGraphSql = "SELECT graph FROM SVC_LOGIC"
337 + " WHERE module = ? AND rpc = ? AND mode = ? AND version = ?";
339 String fetchActiveGraphSql = "SELECT graph FROM SVC_LOGIC"
340 + " WHERE module = ? AND rpc = ? AND mode = ? AND active = 'Y'";
343 String fetchGraphStmt;
345 ArrayList<String> params = new ArrayList<>();
350 if (version == null) {
351 fetchGraphStmt = fetchActiveGraphSql;
354 fetchGraphStmt = fetchVersionGraphSql;
357 StringBuilder sqlBuilder = new StringBuilder(fetchGraphStmt);
359 results = dbLibSvc.getData(sqlBuilder.toString(), new ArrayList(params), "sdnctl");
361 if (results.next()) {
363 ObjectInputStream gStream = new ObjectInputStream(results.getBinaryStream("graph"));
365 Object graphObj = gStream.readObject();
368 if (graphObj instanceof SvcLogicGraph) {
369 retval = (SvcLogicGraph) graphObj;
371 logger.error("invalid type for graph " + graphObj.getClass().getName());
378 } catch (SQLException e) {
379 logger.error("query " + sqlBuilder + " :: " + e.getMessage() + " Will retry");
380 //sbError.append(DRIVER_ERROR);
382 } catch (IOException e) {
383 logger.error("IOException " + " :: " + e.getMessage() + " Will retry");
384 //sbError.append(DRIVER_ERROR);
386 } catch (Exception e) {
387 logger.error("Exception " + " :: " + e.getMessage() + " Will retry");
388 sbError.append(DRIVER_ERROR);
396 protected Properties workflowExecute(String module, String rpc, String version, String mode, Properties props)
397 throws SvcLogicException {
398 logger.info("Fetching service logic from data store");
399 //logger.info("Trial Restart ");
400 //restartDbLibProvider();
401 //logger.info("Trial Restart End");
403 StringBuilder sbError = new StringBuilder();
404 SvcLogicGraph graph = fetchGraph(module, rpc, version, mode, sbError);
405 if (sbError.toString().equals(DRIVER_ERROR))
407 restartDbLibProvider();
408 sbError = new StringBuilder();
409 graph = fetchGraph(module, rpc, version, mode, sbError);
412 Properties retProps = new Properties();
413 retProps.setProperty("error-code", "401");
414 retProps.setProperty("error-message",
415 "No service logic found for [" + module + "," + rpc + "," + version + "," + mode + "]");
419 SvcLogicContext ctx = new SvcLogicContext(props);
420 ctx.setAttribute("currentGraph", graph.toString());
421 ctx.setAttribute("X-ONAP-RequestID", MDC.get("X-ONAP-RequestID"));
422 svcLogic.execute(graph, ctx);
423 return (ctx.toProperties());
426 private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext,
427 Properties workflowParams, WorkflowResponse workflowResponse) {
428 logger.trace("Entering SVCLogicServiceExecute");
430 Properties respProps = null;
433 respProps = workflowExecute(workflowKey.module(), workflowKey.name(), workflowKey.version(),
434 "sync", workflowParams);
435 } catch (Exception e) {
436 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure",
437 "Unexpected SLI Adapter failure", 200);
440 if (logger.isDebugEnabled()) {
441 stk = Arrays.toString(e.getStackTrace());
442 logger.debug("Error while executing DG " + e.getMessage() + stk);
444 logger.error("Error in DG", e.getMessage() + stk, e);
447 if (respProps != null) {
448 if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
449 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
452 final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
453 final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
454 String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
455 int specificStatusCode = 0;
456 if (dgOutputStatusCode != null) {
457 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
460 setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage,
463 logger.debug("DG Execution Status: " + commonStatus);
466 logger.trace("Exiting from SVCLogicServiceExecute");
470 * Filling response context by output.* fields from DG context. Works only for 2.* API version
472 * @param responseContext response context which you need to fill
473 * @param respProps DG context in a properties format
475 private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext,
476 Properties respProps) {
478 Enumeration<?> e = respProps.propertyNames();
479 while (e.hasMoreElements()) {
480 String key = (String) e.nextElement();
481 if (key.startsWith("output.")) {
482 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")) {
484 if (key.equalsIgnoreCase("output.payload")) {
485 responseContext.setPayload(respProps.getProperty(key));
487 responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
495 * Filling responseContext status code and message according to response messages and codes from DG.
497 * @param responseContext response cotext
498 * @param commonStatus common status message from DG ("success" or "failure")
499 * @param specificStatusMessage specific status message from specific DG node
500 * @param specificStatusCode specific status code from specific DG node
502 private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus,
503 String specificStatusMessage, int specificStatusCode) {
504 if (null == specificStatusMessage) { specificStatusMessage = ""; }
505 if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)) {
506 if (specificStatusCode != 0) {
507 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
509 fillStatus(400, commonStatus, responseContext);
512 if (specificStatusCode != 0) {
513 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
515 fillStatus(401, specificStatusMessage, responseContext);
521 * filling responseContext by status code and status message
523 * @param code 3-digit status code
524 * @param message explanation of a status code
525 * @param responseContext response context which will be store status code and status message
527 private void fillStatus(int code, String message, ResponseContext responseContext) {
528 responseContext.getStatus().setCode(code);
529 responseContext.getStatus().setMessage(message);