2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
 
   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=========================================================
 
  22 package org.openecomp.appc.workflow.impl;
 
  24 import java.text.SimpleDateFormat;
 
  25 import java.util.Enumeration;
 
  27 import java.util.Properties;
 
  29 import org.apache.commons.lang.ObjectUtils;
 
  30 import org.apache.commons.lang3.StringUtils;
 
  31 import org.openecomp.appc.common.constant.Constants;
 
  32 import org.openecomp.appc.configuration.Configuration;
 
  33 import org.openecomp.appc.configuration.ConfigurationFactory;
 
  34 import org.openecomp.appc.domainmodel.lcm.RequestContext;
 
  35 import org.openecomp.appc.domainmodel.lcm.ResponseContext;
 
  36 import org.openecomp.appc.util.ObjectMapper;
 
  37 import org.openecomp.appc.workflow.WorkFlowManager;
 
  38 import org.openecomp.appc.workflow.objects.WorkflowExistsOutput;
 
  39 import org.openecomp.appc.workflow.objects.WorkflowRequest;
 
  40 import org.openecomp.appc.workflow.objects.WorkflowResponse;
 
  41 import com.att.eelf.configuration.EELFLogger;
 
  42 import com.att.eelf.configuration.EELFManager;
 
  43 import org.openecomp.sdnc.sli.SvcLogicException;
 
  44 import org.openecomp.sdnc.sli.provider.SvcLogicService;
 
  47 public class WorkFlowManagerImpl implements WorkFlowManager{
 
  48         private SvcLogicService svcLogic = null;
 
  49         private static final EELFLogger logger = EELFManager.getInstance().getLogger(WorkFlowManagerImpl.class);
 
  50         private static final Configuration configuration = ConfigurationFactory.getConfiguration();
 
  52         private final WorkflowResolver workflowResolver = new WorkflowResolver(
 
  53                         configuration.getIntegerProperty("org.openecomp.appc.workflow.resolver.refresh_interval", 300)
 
  56         public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
 
  57                 this.svcLogic = svcLogic;
 
  61          * Execute workflow and return response.
 
  62          * This method execute workflow with following steps.
 
  63          * Retrieve workflow(DG) details - module, version and mode  from database based on command and vnf Type from incoming request.
 
  64          * Execute workflow (DG) using SVC Logic Service reference
 
  65          * Return response of workflow (DG) to caller.
 
  67          * @param workflowRequest workflow execution request which contains vnfType, command, requestId, targetId, payload and (optional) confID;
 
  68          * @return Workflow Response which contains execution status and payload from DG if any
 
  72         public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
 
  73                 if (logger.isTraceEnabled()) {
 
  74                         logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
 
  76                 WorkflowResponse workflowResponse = new WorkflowResponse();
 
  77         workflowResponse.setResponseContext(workflowRequest.getResponseContext());
 
  82             WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
 
  84                         Properties workflowParams = new Properties();
 
  85                         String actionProperty = null;
 
  86                         String requestIdProperty=null;
 
  87                         String vfIdProperty =null;
 
  88             if(!workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
 
  90                                 The following method call (populateDGContext) populates DG context with the
 
  91                                 request parameters to maintain backward compatibility with old DGs,
 
  92                                  we are not altering the old way of passing (org.openecomp.appc.vnfId and so on..)
 
  93                                 This is still a temporary solution, the end solution should be agreed with
 
  94                                 all stakeholders and implemented.
 
  96                                 populateDGContext(workflowParams,workflowRequest);
 
  98                                 actionProperty = configuration.getProperty("org.openecomp.appc.workflow.action", String.valueOf(Constants.ACTION));
 
  99                                 requestIdProperty = configuration.getProperty("org.openecomp.appc.workflow.request.id", String.valueOf(Constants.REQUEST_ID));
 
 100                                 vfIdProperty = configuration.getProperty("org.openecomp.appc.workflow.vfid", String.valueOf(Constants.VF_ID));
 
 101                                 String payloadProperty = configuration.getProperty("org.openecomp.appc.workflow.payload", String.valueOf(Constants.PAYLOAD));
 
 102                                 String vfTypeProperty = configuration.getProperty("org.openecomp.appc.workflow.vftype", String.valueOf(Constants.VF_TYPE));
 
 103                                 String apiVerProperty = configuration.getProperty("org.openecomp.appc.workflow.apiVersion", String.valueOf(Constants.API_VERSION));
 
 104                                 String originatorIdProperty = configuration.getProperty("org.openecomp.appc.workflow.originatorId",Constants.ORIGINATOR_ID);
 
 105                                 String subRequestId = configuration.getProperty("org.openecomp.appc.workflow.subRequestId",Constants.SUB_REQUEST_ID);
 
 107                 workflowParams.put(actionProperty,workflowRequest.getRequestContext().getAction().name());
 
 108                 workflowParams.put(requestIdProperty, workflowRequest.getRequestContext().getCommonHeader().getRequestId());
 
 109                 workflowParams.put(vfIdProperty, workflowRequest.getVnfContext().getId());
 
 110                 workflowParams.put(vfTypeProperty,workflowRequest.getVnfContext().getType());
 
 111                 workflowParams.put(apiVerProperty,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
 
 112                 workflowParams.put(originatorIdProperty,workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
 
 113                 workflowParams.put(subRequestId,workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
 
 115                 Object payloadJson = workflowRequest.getRequestContext().getPayload();
 
 116                                 if(payloadJson!=null) {
 
 118                                                 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
 
 119                                                 workflowParams.putAll(payloadProperties);
 
 121                                                 if (logger.isDebugEnabled()) {
 
 122                                                         logger.debug("DG properties: " + workflowParams);
 
 124                                         } catch (Exception e) {
 
 125                                                 logger.error("Error parsing payload json string", e);
 
 126                                                 Properties workflowPrp = new Properties();
 
 127                                                 workflowPrp.setProperty("error-message", "Error parsing payload json string");
 
 128                         fillStatus(501, "Error parsing payload json string: "+e.getMessage(), workflowRequest.getResponseContext());
 
 129                                                 if (logger.isTraceEnabled()) {
 
 130                                                         logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ObjectUtils.toString(workflowResponse)+")");
 
 132                                                 return workflowResponse;
 
 135                                 if (logger.isDebugEnabled()) {
 
 136                     logger.debug("DG parameters "+ actionProperty +":"+ workflowRequest.getRequestContext().getAction().name()+", "+
 
 137                             requestIdProperty +":"+ workflowRequest.getRequestContext().getCommonHeader().getRequestId()+", "+
 
 138                             vfIdProperty +":"+ workflowRequest.getVnfContext().getId());
 
 140                     logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
 
 143             if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
 
 144                 workflowParams.put("isBwcMode","true");
 
 146                 workflowParams.put("isBwcMode", "false");
 
 149             SVCLogicServiceExecute(workflowKey, workflowRequest.getRequestContext(), workflowParams , workflowResponse);
 
 150                         if (logger.isTraceEnabled()) {
 
 151                 logger.trace("Completed DG Execution for Request id: " + workflowRequest.getRequestContext().getCommonHeader().getRequestId() + "with response code: " + workflowResponse.getResponseContext().getStatus().getCode());
 
 153                 }catch (Exception e){
 
 154                         logger.error("Error Executing DG " +e.getMessage());
 
 155             fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
 
 157                 if (logger.isTraceEnabled()) {
 
 158             logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
 
 160                 return workflowResponse;
 
 163         private void populateDGContext(Properties workflowParams, WorkflowRequest workflowRequest) {
 
 164         workflowParams.put("input.common-header.timestamp",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(workflowRequest.getRequestContext().getCommonHeader().getTimeStamp()));
 
 165         workflowParams.put("input.common-header.api-ver",workflowRequest.getRequestContext().getCommonHeader().getApiVer());
 
 166         workflowParams.put("input.common-header.request-id",workflowRequest.getRequestContext().getCommonHeader().getRequestId());
 
 167         workflowParams.put("input.common-header.originator-id",workflowRequest.getRequestContext().getCommonHeader().getOriginatorId());
 
 168         workflowParams.put("input.common-header.sub-request-id",workflowRequest.getRequestContext().getCommonHeader().getSubRequestId());
 
 169         workflowParams.put("input.action",workflowRequest.getRequestContext().getAction().toString());
 
 170         workflowParams.put("input.payload",null != workflowRequest.getRequestContext().getPayload() ? workflowRequest.getRequestContext().getPayload() : "");
 
 171         workflowParams.put("input.action-identifiers.vnf-id",workflowRequest.getVnfContext().getId());
 
 172         workflowParams.put("input.action-identifiers.vnfc-name",workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVnfcName():"");
 
 173         workflowParams.put("input.action-identifiers.service-instance-id",workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getServiceInstanceId():"");
 
 174         workflowParams.put("input.action-identifiers.vserver-id",workflowRequest.getRequestContext().getActionIdentifiers().getVserverId()!=null?workflowRequest.getRequestContext().getActionIdentifiers().getVserverId():"");
 
 175         final Map<String, String> additionalContext;
 
 176         if ((additionalContext = workflowRequest.getRequestContext().getAdditionalContext())!=null) {
 
 177             for (Map.Entry<String, String> entry : additionalContext.entrySet()) {
 
 178                 workflowParams.put("input." + entry.getKey(), null != entry.getValue() ? entry.getValue() : "");
 
 184          * Check if workflow (DG) exists in database
 
 186          * @param workflowQueryParams workflow request with command and vnf Type
 
 187          * @return True if workflow exists else False.
 
 190         public WorkflowExistsOutput workflowExists(WorkflowRequest workflowQueryParams) {
 
 191                 WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(false,false);
 
 192                 if (logger.isTraceEnabled()) {
 
 193                         logger.trace("Entering to workflowExists with WorkflowRequest = "+ObjectUtils.toString(workflowQueryParams.toString()));
 
 197             WorkflowKey workflowKey = workflowResolver.resolve(
 
 198                     workflowQueryParams.getRequestContext().getAction().name(),
 
 199                     workflowQueryParams.getVnfContext().getType(),
 
 200                     workflowQueryParams.getVnfContext().getVersion(),
 
 201                     workflowQueryParams.getRequestContext().getCommonHeader().getApiVer());
 
 202                         if (workflowKey != null) {
 
 203                                 workflowExistsOutput.setMappingExist(true);
 
 204                                 workflowExistsOutput.setWorkflowModule(workflowKey.module());
 
 205                                 workflowExistsOutput.setWorkflowName(workflowKey.name());
 
 206                                 workflowExistsOutput.setWorkflowVersion(workflowKey.version());
 
 207                                 if (isDGExists(workflowKey)) {
 
 208                                         workflowExistsOutput.setDgExist(true);
 
 211                                                         String.format("SLI doesn't have DG for resolved mapping entry:  DG module - '%s', DG name - '%s', DG version - '%s'",
 
 212                                                                         workflowKey.module(), workflowKey.name(), workflowKey.version()));
 
 216                                                 String.format("Unable to resolve recipe matching action '%s', VNF type '%s' and VNF version '%s'",
 
 217                                 workflowQueryParams.getRequestContext().getAction().name(), workflowQueryParams.getVnfContext().getType(), null));
 
 219                 } catch (RuntimeException e) {
 
 220                         logger.error("Error querying workflow from database"+e.getMessage());
 
 222                 }catch (SvcLogicException e) {
 
 223                         logger.error("Error querying workflow from database"+e.getMessage());
 
 224                         throw new RuntimeException(e);
 
 226                 if (logger.isTraceEnabled()) {
 
 227                         logger.trace("Exiting workflowExists");
 
 229                 return workflowExistsOutput;
 
 233         private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
 
 234                 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
 
 237     private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
 
 238                 if (logger.isTraceEnabled()) {
 
 239                         logger.trace("Entering SVCLogicServiceExecute");
 
 242         Properties respProps = null;
 
 245             respProps = svcLogic.execute(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync", workflowParams);
 
 246         } catch (Exception e) {
 
 247             setWorkFlowResponseStatus(workflowResponse.getResponseContext(), "failure", "Unexpected SLI Adapter failure", 200);
 
 249                         if (logger.isDebugEnabled()) {
 
 250                 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
 
 252             logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
 
 255         if (respProps != null) {
 
 256             if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
 
 257                 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
 
 260             final String commonStatus = respProps.getProperty(Constants.DG_ATTRIBUTE_STATUS);
 
 261             final String specificStatusMessage = respProps.getProperty(Constants.DG_OUTPUT_STATUS_MESSAGE);
 
 262             String dgOutputStatusCode = respProps.getProperty(Constants.DG_OUTPUT_STATUS_CODE);
 
 263             int specificStatusCode = 0;
 
 264             if (dgOutputStatusCode != null) {
 
 265                 specificStatusCode = Integer.parseInt(dgOutputStatusCode);
 
 268             setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
 
 270                         if (logger.isDebugEnabled()) {
 
 271                 logger.debug("DG Execution Status: " + commonStatus);
 
 275                 if (logger.isTraceEnabled()) {
 
 276                         logger.trace("Exiting from SVCLogicServiceExecute");
 
 281      * Filling response context by output.* fields from DG context. Works only for 2.* API version
 
 283      * @param responseContext response context which you need to fill
 
 284      * @param respProps DG context in a properties format
 
 286     private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
 
 288         Enumeration<?> e = respProps.propertyNames();
 
 289         while (e.hasMoreElements()){
 
 290             String key = (String) e.nextElement();
 
 291             if (key.startsWith("output.")){
 
 292                 if (!key.startsWith("output.common-header.") && !key.startsWith("output.status.")){
 
 294                     if (key.equalsIgnoreCase("output.payload")){
 
 295                         responseContext.setPayload(respProps.getProperty(key));
 
 297                         responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
 
 305      * Filling responceContext status code amd message according to responce messages and codes from DG.
 
 307      * @param responseContext response cotext
 
 308      * @param commonStatus common status message from DG ("success" or "failure")
 
 309      * @param specificStatusMessage specific status message from specific DG node
 
 310      * @param specificStatusCode specific status code from specific DG node
 
 312     private void setWorkFlowResponseStatus(ResponseContext responseContext, String commonStatus, String specificStatusMessage, int specificStatusCode) {
 
 313             if (null == specificStatusMessage) { specificStatusMessage = ""; }
 
 314             if (commonStatus.equalsIgnoreCase(Constants.DG_STATUS_SUCCESS)){
 
 315                     if (specificStatusCode != 0 ){
 
 316                 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
 
 318                 fillStatus(400, commonStatus, responseContext);
 
 321                         String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
 
 322             if (specificStatusCode != 0){
 
 323                 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
 
 325                 fillStatus(401, specificStatusMessage, responseContext);
 
 331      * filling responseContext by status code and status message
 
 333      * @param code 3-digit status code
 
 334      * @param message explanation of a status code
 
 335      * @param responceContext response context which will be store status code and status message
 
 337     private void fillStatus(int code, String message, ResponseContext responceContext) {
 
 338         responceContext.getStatus().setCode(code);
 
 339         responceContext.getStatus().setMessage(message);