Updating licenses in all files
[appc.git] / appc-dispatcher / appc-workflow-management / appc-workflow-management-core / src / main / java / org / openecomp / appc / workflow / impl / WorkFlowManagerImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * APPC
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
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
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.
21  */
22
23 package org.openecomp.appc.workflow.impl;
24
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;
42
43 import java.text.SimpleDateFormat;
44 import java.util.Enumeration;
45 import java.util.Map;
46 import java.util.Properties;
47
48
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();
53
54         private final WorkflowResolver workflowResolver = new WorkflowResolver(
55                         configuration.getIntegerProperty("org.openecomp.appc.workflow.resolver.refresh_interval", 300)
56         );
57
58         public void setSvcLogicServiceRef(SvcLogicService svcLogic) {
59                 this.svcLogic = svcLogic;
60         }
61
62         /**
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.
68      *
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
71          */
72
73         @Override
74         public WorkflowResponse executeWorkflow(WorkflowRequest workflowRequest) {
75                 if (logger.isTraceEnabled()) {
76                         logger.trace("Entering to executeWorkflow with WorkflowRequest = "+ ObjectUtils.toString(workflowRequest.toString()));
77                 }
78                 WorkflowResponse workflowResponse = new WorkflowResponse();
79         workflowResponse.setResponseContext(workflowRequest.getResponseContext());
80
81                 try {
82
83
84             WorkflowKey workflowKey = workflowResolver.resolve(workflowRequest.getRequestContext().getAction().name(), workflowRequest.getVnfContext().getType(), null,workflowRequest.getRequestContext().getCommonHeader().getApiVer());
85
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.")){
91                                 /*
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.
97                          */
98                                 populateDGContext(workflowParams,workflowRequest);
99             } else {
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);
108
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());
116
117                 Object payloadJson = workflowRequest.getRequestContext().getPayload();
118                                 if(payloadJson!=null) {
119                                         try {
120                                                 Map<String, String> payloadProperties = ObjectMapper.map(payloadJson);
121                                                 workflowParams.putAll(payloadProperties);
122
123                                                 if (logger.isDebugEnabled()) {
124                                                         logger.debug("DG properties: " + workflowParams);
125                                                 }
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)+")");
133                                                 }
134                                                 return workflowResponse;
135                                         }
136                                 }
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());
141
142                     logger.debug("Starting DG Execution for request "+workflowRequest.getRequestContext().getCommonHeader().getRequestId());
143                                 }
144                         }
145             if (workflowRequest.getRequestContext().getCommonHeader().getApiVer().startsWith("1.")){
146                 workflowParams.put("isBwcMode","true");
147             } else {
148                 workflowParams.put("isBwcMode", "false");
149             }
150
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());
154                         }
155                 }catch (Exception e){
156                         logger.error("Error Executing DG " +e.getMessage());
157             fillStatus(501, "Error Executing DG "+e.getMessage(), workflowRequest.getResponseContext());
158                 }
159                 if (logger.isTraceEnabled()) {
160             logger.trace("Exiting from executeWorkflow with (workflowResponse = "+ ObjectUtils.toString(workflowResponse.getResponseContext().getStatus().getMessage())+")");
161                 }
162                 return workflowResponse;
163         }
164
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() : "");
181         }
182         }
183     }
184
185         /**
186          * Check if workflow (DG) exists in database
187      *
188          * @param workflowQueryParams workflow request with command and vnf Type
189          * @return True if workflow exists else False.
190          */
191         @Override
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()));
196                 }
197
198                 try {
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);
211                                 }else{
212                                         logger.warn(
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()));
215                                 }
216                         }else{
217                                 logger.warn(
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));
220                         }
221                 } catch (RuntimeException e) {
222                         logger.error("Error querying workflow from database"+e.getMessage());
223                         throw e;
224                 }catch (SvcLogicException e) {
225                         logger.error("Error querying workflow from database"+e.getMessage());
226                         throw new RuntimeException(e);
227                 }
228                 if (logger.isTraceEnabled()) {
229                         logger.trace("Exiting workflowExists");
230                 }
231                 return workflowExistsOutput;
232         }
233
234
235         private boolean isDGExists(WorkflowKey workflowKey) throws SvcLogicException {
236                 return svcLogic.hasGraph(workflowKey.module(), workflowKey.name(), workflowKey.version(), "sync");
237         }
238
239     private void SVCLogicServiceExecute(WorkflowKey workflowKey, RequestContext requestContext, Properties workflowParams, WorkflowResponse workflowResponse) {
240                 if (logger.isTraceEnabled()) {
241                         logger.trace("Entering SVCLogicServiceExecute");
242                 }
243
244         Properties respProps = null;
245
246                 try {
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);
250
251                         if (logger.isDebugEnabled()) {
252                 logger.debug("Error while executing DG " + e.getMessage() + e.getStackTrace());
253             }
254             logger.error("Error in DG", e.getMessage()+e.getStackTrace().toString());
255         }
256
257         if (respProps != null) {
258             if (!requestContext.getCommonHeader().getApiVer().startsWith("1.")) {
259                 fillResponseContextByOutputFieldsFromDgContext(workflowResponse.getResponseContext(), respProps);
260             }
261
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);
268                         }
269
270             setWorkFlowResponseStatus(workflowResponse.getResponseContext(), commonStatus, specificStatusMessage, specificStatusCode);
271
272                         if (logger.isDebugEnabled()) {
273                 logger.debug("DG Execution Status: " + commonStatus);
274                         }
275                 }
276
277                 if (logger.isTraceEnabled()) {
278                         logger.trace("Exiting from SVCLogicServiceExecute");
279                 }
280         }
281
282     /**
283      * Filling response context by output.* fields from DG context. Works only for 2.* API version
284      *
285      * @param responseContext response context which you need to fill
286      * @param respProps DG context in a properties format
287      */
288     private void fillResponseContextByOutputFieldsFromDgContext(ResponseContext responseContext, Properties respProps) {
289
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.")){
295
296                     if (key.equalsIgnoreCase("output.payload")){
297                         responseContext.setPayload(respProps.getProperty(key));
298                     } else {
299                         responseContext.addKeyValueToAdditionalContext(key, respProps.getProperty(key));
300                 }
301                 }
302             }
303         }
304     }
305
306     /**
307      * Filling responceContext status code amd message according to responce messages and codes from DG.
308      *
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
313      */
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);
319             } else {
320                 fillStatus(400, commonStatus, responseContext);
321             }
322         } else {
323                         String errorMsg = StringUtils.isEmpty(specificStatusMessage) ? "DG execution failure" : specificStatusMessage;
324             if (specificStatusCode != 0){
325                 fillStatus(specificStatusCode, specificStatusMessage, responseContext);
326             } else {
327                 fillStatus(401, specificStatusMessage, responseContext);
328             }
329                 }
330         }
331
332     /**
333      * filling responseContext by status code and status message
334      *
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
338      */
339     private void fillStatus(int code, String message, ResponseContext responceContext) {
340         responceContext.setStatus(new Status(code, message));
341     }
342
343 }