Merge "Remove unused class StreamHelper"
[appc.git] / appc-dispatcher / appc-request-handler / appc-request-handler-core / src / main / java / org / openecomp / appc / requesthandler / impl / RequestHandlerImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
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  */
21
22 package org.openecomp.appc.requesthandler.impl;
23
24 import org.apache.commons.lang.ObjectUtils;
25 import org.openecomp.appc.common.constant.Constants;
26 import org.openecomp.appc.configuration.Configuration;
27 import org.openecomp.appc.configuration.ConfigurationFactory;
28 import org.openecomp.appc.domainmodel.lcm.*;
29 import org.openecomp.appc.exceptions.APPCException;
30 import org.openecomp.appc.executor.CommandExecutor;
31 import org.openecomp.appc.executor.UnstableVNFException;
32 import org.openecomp.appc.executor.objects.LCMCommandStatus;
33 import org.openecomp.appc.executor.objects.Params;
34 import org.openecomp.appc.executor.objects.UniqueRequestIdentifier;
35 import org.openecomp.appc.i18n.Msg;
36 import org.openecomp.appc.lifecyclemanager.objects.LifecycleException;
37 import org.openecomp.appc.lifecyclemanager.objects.NoTransitionDefinedException;
38 import org.openecomp.appc.lockmanager.api.LockException;
39 import org.openecomp.appc.lockmanager.api.LockManager;
40 import org.openecomp.appc.logging.LoggingConstants;
41 import org.openecomp.appc.logging.LoggingUtils;
42 import org.openecomp.appc.messageadapter.MessageAdapter;
43 import org.openecomp.appc.messageadapter.impl.MessageAdapterDmaapImpl;
44 import org.openecomp.appc.metricservice.MetricRegistry;
45 import org.openecomp.appc.metricservice.MetricService;
46 import org.openecomp.appc.metricservice.metric.DispatchingFuntionMetric;
47 import org.openecomp.appc.metricservice.metric.Metric;
48 import org.openecomp.appc.metricservice.metric.MetricType;
49 import org.openecomp.appc.metricservice.policy.PublishingPolicy;
50 import org.openecomp.appc.metricservice.publisher.LogPublisher;
51 import org.openecomp.appc.requesthandler.RequestHandler;
52 import org.openecomp.appc.requesthandler.exceptions.*;
53 import org.openecomp.appc.requesthandler.helper.RequestRegistry;
54 import org.openecomp.appc.requesthandler.helper.RequestValidator;
55 import org.openecomp.appc.requesthandler.objects.RequestHandlerInput;
56 import org.openecomp.appc.requesthandler.objects.RequestHandlerOutput;
57 import org.openecomp.appc.transactionrecorder.TransactionRecorder;
58 import org.openecomp.appc.transactionrecorder.objects.TransactionRecord;
59 import org.openecomp.appc.workingstatemanager.WorkingStateManager;
60 import org.openecomp.appc.workingstatemanager.objects.VNFWorkingState;
61 import com.att.eelf.configuration.EELFLogger;
62 import com.att.eelf.configuration.EELFManager;
63 import com.att.eelf.i18n.EELFResourceManager;
64 import org.openecomp.sdnc.sli.SvcLogicContext;
65 import org.openecomp.sdnc.sli.SvcLogicException;
66 import org.openecomp.sdnc.sli.SvcLogicResource.QueryStatus;
67 import org.openecomp.sdnc.sli.aai.AAIService;
68 import org.osgi.framework.BundleContext;
69 import org.osgi.framework.FrameworkUtil;
70 import org.osgi.framework.ServiceReference;
71 import org.slf4j.MDC;
72
73 import static com.att.eelf.configuration.Configuration.*;
74
75 import java.net.InetAddress;
76 import java.time.Instant;
77 import java.time.temporal.ChronoUnit;
78 import java.util.Date;
79 import java.util.HashMap;
80 import java.util.Map;
81 import java.util.Properties;
82
83 /**
84  * This class provides application logic for the Request/Response Handler Component.
85  *
86  */
87 public class RequestHandlerImpl implements RequestHandler {
88
89     /**
90      * APP-C VNF lock idle timeout in milliseconds. Applied only when locking VNF using northbound API "lock"
91      */
92     private static final String PROP_IDLE_TIMEOUT = "org.openecomp.appc.lock.idleTimeout";
93
94     private CommandExecutor commandExecutor;
95
96     private TransactionRecorder transactionRecorder;
97     private MessageAdapter messageAdapter;
98     private RequestValidator requestValidator;
99     private static MetricRegistry metricRegistry;
100     private boolean isMetricEnabled = false;
101     private RequestRegistry requestRegistry;
102     private LockManager lockManager;
103     private WorkingStateManager workingStateManager;
104     private AAIService aaiService;
105
106     private static final EELFLogger logger = EELFManager.getInstance().getLogger(RequestHandlerImpl.class);
107
108     public void setAaiService(AAIService aaiService) {
109         this.aaiService = aaiService;
110     }
111
112     public void setTransactionRecorder(TransactionRecorder transactionRecorder) {
113         this.transactionRecorder = transactionRecorder;
114     }
115
116     public void setLockManager(LockManager lockManager) {
117         this.lockManager = lockManager;
118     }
119
120     public void setRequestValidator(RequestValidator requestValidator) {
121         this.requestValidator = requestValidator;
122     }
123
124     public void setMessageAdapter(MessageAdapter messageAdapter) {
125         this.messageAdapter = messageAdapter;
126     }
127
128     private static final Configuration configuration = ConfigurationFactory.getConfiguration();
129
130     public void setWorkingStateManager(WorkingStateManager workingStateManager) {
131         this.workingStateManager = workingStateManager;
132     }
133
134     public RequestHandlerImpl() {
135         requestRegistry = new RequestRegistry();
136         messageAdapter = new MessageAdapterDmaapImpl();
137         messageAdapter.init();
138         Properties properties = configuration.getProperties();
139         if (properties != null && properties.getProperty("metric.enabled") != null) {
140             isMetricEnabled = Boolean.valueOf(properties.getProperty("metric.enabled"));
141         }
142         if (isMetricEnabled) {
143             initMetric();
144         }
145     }
146
147     public void setCommandExecutor(CommandExecutor commandExecutor) {
148         this.commandExecutor = commandExecutor;
149     }
150
151
152     /**
153      * It receives requests from the north-bound REST API (Communication) Layer and
154      * performs following validations.
155      * 1. VNF exists in A&AI for the given targetID (VnfID)
156      * 2. For the current VNF  Orchestration Status, the command can be executed
157      * 3. For the given VNF type and Operation, there exists work-flow definition in the APPC database
158      * If any of the validation fails, it returns appropriate response
159      *
160      * @param input RequestHandlerInput object which contains request header and  other request parameters like command , target Id , payload etc.
161      * @return response for request as enum with Return code and message.
162      */
163     @Override
164     public RequestHandlerOutput handleRequest(RequestHandlerInput input) {
165         if (logger.isTraceEnabled())
166             logger.trace("Entering to handleRequest with RequestHandlerInput = " + ObjectUtils.toString(input) + ")");
167         Params params = null;
168         String vnfId = null, vnfType = null, errorMessage = null;
169         Instant startTime = Instant.now();
170         RequestHandlerOutput output = null;
171         setInitialLogProperties(input.getRequestContext());
172
173         RuntimeContext runtimeContext = new RuntimeContext();
174         runtimeContext.setRequestContext(input.getRequestContext());
175         runtimeContext.setTimeStart(startTime);
176         runtimeContext.setRpcName(input.getRpcName());
177
178         final ResponseContext responseContext = new ResponseContext();
179         responseContext.setStatus(new Status(0, null));
180         responseContext.setAdditionalContext(new HashMap<String, String>(4));
181         responseContext.setCommonHeader(input.getRequestContext().getCommonHeader());
182         runtimeContext.setResponseContext(responseContext);
183         runtimeContext.getResponseContext().setStatus(new Status(0, null));
184
185         vnfId = runtimeContext.getRequestContext().getActionIdentifiers().getVnfId();
186
187         try {
188
189             requestValidator.validateRequest(runtimeContext);
190
191             handleRequest(runtimeContext);
192
193             final int statusCode = runtimeContext.getResponseContext().getStatus().getCode();
194             if (statusCode % 100 == 2 || statusCode % 100 == 3) {
195                 createTransactionRecord(runtimeContext);
196             }
197             output = new RequestHandlerOutput();
198             output.setResponseContext(runtimeContext.getResponseContext());
199
200         } catch (VNFNotFoundException e) {
201             errorMessage = e.getMessage();
202             String logMessage = EELFResourceManager.format(Msg.APPC_NO_RESOURCE_FOUND, vnfId);
203             storeErrorMessageToLog(runtimeContext, LoggingConstants.TargetNames.AAI, "", logMessage);
204             params = new Params().addParam("vnfId", vnfId);
205             output = buildRequestHandlerOutput(LCMCommandStatus.VNF_NOT_FOUND, params);
206         } catch (NoTransitionDefinedException e) {
207             errorMessage = e.getMessage();
208             String logMessage = EELFResourceManager.format(Msg.VF_UNDEFINED_STATE, input.getRequestContext().getCommonHeader().getOriginatorId(), input.getRequestContext().getAction().name());
209             params = new Params().addParam("actionName", input.getRequestContext().getAction()).addParam("currentState", e.currentState);
210             output = buildRequestHandlerOutput(LCMCommandStatus.NO_TRANSITION_DEFINE, params);
211             storeErrorMessageToLog(runtimeContext,
212                     LoggingConstants.TargetNames.APPC,
213                     LoggingConstants.TargetNames.STATE_MACHINE,
214                     logMessage);
215         } catch (LifecycleException e) {
216             errorMessage = e.getMessage();
217             params = new Params().addParam("actionName", input.getRequestContext().getAction()).addParam("currentState", e.currentState);
218             output = buildRequestHandlerOutput(LCMCommandStatus.ACTION_NOT_SUPPORTED, params);
219         } catch (UnstableVNFException e) {
220             errorMessage = e.getMessage();
221             params = new Params().addParam("vnfId", vnfId);
222             output = buildRequestHandlerOutput(LCMCommandStatus.UNSTABLE_VNF, params);
223         } catch (WorkflowNotFoundException e) {
224             errorMessage = e.getMessage();
225             String vnfTypeVersion = e.vnfTypeVersion;
226             params = new Params().addParam("actionName", input.getRequestContext().getAction()).addParam("vnfTypeVersion", vnfTypeVersion);
227             output = buildRequestHandlerOutput(LCMCommandStatus.WORKFLOW_NOT_FOUND, params);
228         } catch (DGWorkflowNotFoundException e) {
229             errorMessage = e.getMessage();
230             String logMessage = EELFResourceManager.format(Msg.APPC_WORKFLOW_NOT_FOUND, vnfType, input.getRequestContext().getAction().name());
231             storeErrorMessageToLog(runtimeContext,
232                     LoggingConstants.TargetNames.APPC,
233                     LoggingConstants.TargetNames.WORKFLOW_MANAGER,
234                     logMessage);
235             params = new Params().addParam("actionName", input.getRequestContext().getAction().name())
236                     .addParam("dgModule", e.workflowModule).addParam("dgName", e.workflowName).addParam("dgVersion", e.workflowVersion);
237             output = buildRequestHandlerOutput(LCMCommandStatus.DG_WORKFLOW_NOT_FOUND, params);
238         } catch (RequestExpiredException e) {
239             errorMessage = e.getMessage();
240             params = new Params().addParam("actionName", input.getRequestContext().getAction().name());
241             output = buildRequestHandlerOutput(LCMCommandStatus.EXPIRED_REQUEST, params);
242         } catch (InvalidInputException e) {
243             errorMessage = e.getMessage() != null ? e.getMessage() : e.toString();
244             params = new Params().addParam("errorMsg", errorMessage);
245             output = buildRequestHandlerOutput(LCMCommandStatus.INVALID_INPUT_PARAMETER, params);
246         } catch (DuplicateRequestException e) {
247             errorMessage = e.getMessage();
248             output = buildRequestHandlerOutput(LCMCommandStatus.DUPLICATE_REQUEST, null);
249         } catch (Exception e) {
250             storeErrorMessageToLog(runtimeContext, "", "", "Exception = " + e.getMessage());
251             errorMessage = e.getMessage() != null ? e.getMessage() : e.toString();
252             params = new Params().addParam("errorMsg", errorMessage);
253             output = buildRequestHandlerOutput(LCMCommandStatus.UNEXPECTED_ERROR, params);
254         } finally {
255             try {
256                 if (logger.isDebugEnabled() && errorMessage != null)
257                     logger.debug("error occurred in handleRequest " + errorMessage);
258                 logger.debug("output.getResponse().getResponseCode().equals(LCMCommandStatus.ACCEPTED.getResponseCode():  " + (output.getResponseContext().getStatus().getCode() == LCMCommandStatus.ACCEPTED.getResponseCode()));
259                 logger.debug("output.getResponse().getResponseCode().equals(LCMCommandStatus.SUCCESS.getResponseCode():  " + (output.getResponseContext().getStatus().getCode() == LCMCommandStatus.SUCCESS.getResponseCode()));
260
261                 runtimeContext.setResponseContext(output.getResponseContext());
262                 if ((null == output) || !(output.getResponseContext().getStatus().getCode() == LCMCommandStatus.ACCEPTED.getResponseCode())) {
263                     if (isMetricEnabled) {
264                         ((DispatchingFuntionMetric) metricRegistry.metric("DISPATCH_FUNCTION")).incrementRejectedRequest();
265                     }
266                     removeRequestFromRegistry(input.getRequestContext().getCommonHeader());
267                 }
268             } finally {
269                 storeAuditLogRecord(runtimeContext);
270                 storeMetricLogRecord(runtimeContext);
271                 clearRequestLogProperties();
272             }
273         }
274         if (logger.isTraceEnabled()) {
275             logger.trace("Exiting from handleRequest with (RequestHandlerOutput = " + ObjectUtils.toString(output.getResponseContext()) + ")");
276         }
277         return output;
278     }
279
280     private void storeErrorMessageToLog(RuntimeContext runtimeContext, String targetEntity, String targetServiceName, String additionalMessage) {
281         LoggingUtils.logErrorMessage(runtimeContext.getResponseContext().getStatus() != null ?
282                         String.valueOf(runtimeContext.getResponseContext().getStatus().getCode()) : "",
283                 runtimeContext.getResponseContext().getStatus() != null ?
284                         String.valueOf(runtimeContext.getResponseContext().getStatus().getMessage()) : "",
285                 targetEntity,
286                 targetServiceName,
287                 additionalMessage,
288                 this.getClass().getCanonicalName());
289     }
290
291     private void createTransactionRecord(RuntimeContext runtimeContext) {
292         TransactionRecord transactionRecord = new TransactionRecord();
293         transactionRecord.setTimeStamp(runtimeContext.getResponseContext().getCommonHeader().getTimeStamp());
294         transactionRecord.setRequestID(runtimeContext.getResponseContext().getCommonHeader().getRequestId());
295         transactionRecord.setStartTime(runtimeContext.getTimeStart());
296         transactionRecord.setEndTime(Instant.now());
297         transactionRecord.setTargetID(runtimeContext.getVnfContext().getId());
298         transactionRecord.setTargetType(runtimeContext.getVnfContext().getType());
299         transactionRecord.setOperation(runtimeContext.getRequestContext().getAction().name());
300         transactionRecord.setResultCode(String.valueOf(runtimeContext.getResponseContext().getStatus().getCode()));
301         transactionRecord.setDescription(runtimeContext.getResponseContext().getStatus().getMessage());
302         transactionRecorder.store(transactionRecord);
303     }
304
305     private void handleRequest(RuntimeContext runtimeContext) {
306
307         switch (runtimeContext.getRequestContext().getAction()) {
308             case Lock:
309                 try {
310                     lockWithTimeout(runtimeContext.getVnfContext().getId(), runtimeContext.getRequestContext().getCommonHeader().getRequestId());
311                     fillStatus(runtimeContext,LCMCommandStatus.SUCCESS, null);
312                 } catch (LockException e) {
313                     Params params = new Params().addParam("errorMsg", e.getMessage());
314                     fillStatus(runtimeContext, LCMCommandStatus.LOCKING_FAILURE, params);
315                     storeErrorMessageToLog(runtimeContext,
316                             LoggingConstants.TargetNames.APPC,
317                             LoggingConstants.TargetNames.LOCK_MANAGER,
318                             EELFResourceManager.format(Msg.VF_SERVER_BUSY, runtimeContext.getVnfContext().getId()));
319                 }
320
321                 break;
322
323             case Unlock:
324                 try {
325                     releaseVNFLock(runtimeContext.getVnfContext().getId(), runtimeContext.getRequestContext().getCommonHeader().getRequestId());
326                     fillStatus(runtimeContext,LCMCommandStatus.SUCCESS, null);
327                 } catch (LockException e) {
328                     //TODO add proper error code and message
329                     //  logger.error(EELFResourceManager.format(Msg.VF_SERVER_BUSY, runtimeContext.getVnfContext().getId()));
330                     Params params = new Params().addParam("errorMsg", e.getMessage());
331                     fillStatus(runtimeContext, LCMCommandStatus.LOCKING_FAILURE, params);
332                 }
333                 break;
334
335             case CheckLock:
336                 boolean isLocked = lockManager.isLocked(runtimeContext.getVnfContext().getId());
337                 fillStatus(runtimeContext,LCMCommandStatus.SUCCESS, null);
338                 runtimeContext.getResponseContext().addKeyValueToAdditionalContext("locked", String.valueOf(isLocked).toUpperCase());
339                 break;
340             default:
341                 try {
342                     boolean lockAcquired = acquireVNFLock(runtimeContext.getVnfContext().getId(), runtimeContext.getRequestContext().getCommonHeader().getRequestId(), 0);
343                     runtimeContext.setIsLockAcquired(lockAcquired);
344                     callWfOperation(runtimeContext);
345                 } catch (LockException e) {
346                     Params params = new Params().addParam("errorMsg", e.getMessage());
347                     fillStatus(runtimeContext, LCMCommandStatus.LOCKING_FAILURE, params);
348                 } finally {
349                     if (runtimeContext.isLockAcquired()) {
350                         final int statusCode = runtimeContext.getResponseContext().getStatus().getCode();
351                         if (statusCode % 100 == 2 || statusCode % 100 == 3) {
352                             try {
353                                 releaseVNFLock(runtimeContext.getVnfContext().getId(), runtimeContext.getRequestContext().getCommonHeader().getRequestId());
354                                 //TODO add logger call
355                             } catch (LockException e) {
356                                 //ignore
357                             }
358                         }
359                     }
360                 }
361         }
362
363     }
364
365     private void callWfOperation(RuntimeContext runtimeContext) {
366         int remainingTTL = calculateRemainingTTL(runtimeContext.getRequestContext().getCommonHeader());
367         if (remainingTTL > 0) {
368             if (logger.isDebugEnabled()) {
369                 logger.debug("Calling command Executor with remaining TTL value: " + remainingTTL);
370             }
371
372             RuntimeContext commandExecutorInput = cloneContext(runtimeContext);
373
374             try {
375                 commandExecutor.executeCommand(commandExecutorInput);
376                 if(logger.isTraceEnabled()) {
377                     logger.trace("Command was added to queue successfully for vnfID = " + ObjectUtils.toString(runtimeContext.getRequestContext().getActionIdentifiers().getVnfId()));
378                 }
379                 fillStatus(runtimeContext, LCMCommandStatus.ACCEPTED, null);
380                 if (isMetricEnabled) {
381                     ((DispatchingFuntionMetric) metricRegistry.metric("DISPATCH_FUNCTION")).incrementAcceptedRequest();
382                 }
383             } catch (APPCException e) {
384                 String errorMessage = e.getMessage() != null ? e.getMessage() : e.toString();
385                 Params params = new Params().addParam("errorMsg", errorMessage);
386                 fillStatus(runtimeContext, LCMCommandStatus.UNEXPECTED_ERROR, params);
387             }
388
389         } else {
390             fillStatus(runtimeContext, LCMCommandStatus.EXPIRED_REQUEST, null);
391             storeErrorMessageToLog(runtimeContext,
392                     LoggingConstants.TargetNames.APPC,
393                     LoggingConstants.TargetNames.REQUEST_HANDLER,
394                     EELFResourceManager.format(Msg.APPC_EXPIRED_REQUEST,
395                             runtimeContext.getRequestContext().getCommonHeader().getOriginatorId(),
396                             runtimeContext.getRequestContext().getActionIdentifiers().getVnfId(),
397                             String.valueOf(runtimeContext.getRequestContext().getCommonHeader().getFlags().getTtl())));
398         }
399     }
400
401     private void fillStatus(RuntimeContext runtimeContext, LCMCommandStatus lcmCommandStatus, Params params) {
402         runtimeContext.getResponseContext().setStatus(lcmCommandStatus.toStatus(params));
403     }
404
405     /*
406      * Workaround to clone context in order to prevent sharing of ResponseContext by two threads (one to set Accepted
407      * status code and other - depending on DG status). Other properties should not be a problem
408      */
409     private RuntimeContext cloneContext(RuntimeContext runtimeContext) {
410         RuntimeContext other = new RuntimeContext();
411         other.setRequestContext(runtimeContext.getRequestContext());
412         other.setResponseContext(new ResponseContext());
413         other.getResponseContext().setStatus(new Status(0, null));
414         other.getResponseContext().setCommonHeader(runtimeContext.getRequestContext().getCommonHeader());
415         other.setVnfContext(runtimeContext.getVnfContext());
416         other.setRpcName(runtimeContext.getRpcName());
417         other.setTimeStart(runtimeContext.getTimeStart());
418         other.setIsLockAcquired(runtimeContext.isLockAcquired());
419         return other;
420     }
421
422
423     private void clearRequestLogProperties() {
424         try {
425             MDC.remove(MDC_KEY_REQUEST_ID);
426             MDC.remove(MDC_SERVICE_INSTANCE_ID);
427             MDC.remove(MDC_SERVICE_NAME);
428             MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME);
429             MDC.remove(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY);
430         } catch (Exception e) {
431
432         }
433     }
434
435     private void removeRequestFromRegistry(CommonHeader commonHeader) {
436         if (logger.isTraceEnabled())
437             logger.trace("Entering to removeRequestFromRegistry with RequestHeader = " + ObjectUtils.toString(commonHeader));
438         requestRegistry.removeRequest(
439                 new UniqueRequestIdentifier(commonHeader.getOriginatorId(),
440                         commonHeader.getRequestId(),
441                         commonHeader.getSubRequestId()));
442     }
443
444     private boolean acquireVNFLock(String vnfID, String requestId, long timeout) throws LockException {
445         if (logger.isTraceEnabled())
446             logger.trace("Entering to acquireVNFLock with vnfID = " + vnfID);
447         boolean lockAcquired = lockManager.acquireLock(vnfID, requestId, timeout);
448         if (lockAcquired) {
449             logger.info("Lock acquired for vnfID = " + vnfID);
450         } else {
451             logger.info("vnfID = " + vnfID + " was already locked");
452         }
453         return lockAcquired;
454     }
455
456     private void lockWithTimeout(String vnfId, String requestId) throws LockException {
457         long timeout = configuration.getLongProperty(PROP_IDLE_TIMEOUT, Constants.DEFAULT_IDLE_TIMEOUT);
458         acquireVNFLock(vnfId, requestId, timeout);
459     }
460
461     private void resetLock(String vnfId, String requestId, boolean lockAcquired, boolean resetLockTimeout) {
462         if (lockAcquired) {
463             try {
464                 releaseVNFLock(vnfId, requestId);
465             } catch (LockException e) {
466                 logger.error("Unlock VNF [" + vnfId + "] failed. Request id: [" + requestId + "]", e);
467
468
469             }
470         } else if (resetLockTimeout) {
471             try {
472                 // reset timeout to previous value
473                 lockWithTimeout(vnfId, requestId);
474             } catch (LockException e) {
475                 logger.error("Reset lock idle timeout for VNF [" + vnfId + "] failed. Request id: [" + requestId + "]", e);
476             }
477         }
478     }
479
480     private void releaseVNFLock(String vnfId, String transactionId) throws LockException {
481         lockManager.releaseLock(vnfId, transactionId);
482         logger.info("Lock released for vnfID = " + vnfId);
483     }
484
485     private void setInitialLogProperties(RequestContext requestContext) {
486
487         try {
488             MDC.put(MDC_KEY_REQUEST_ID, requestContext.getCommonHeader().getRequestId());
489             if (requestContext.getActionIdentifiers().getServiceInstanceId() != null) {
490                 MDC.put(MDC_SERVICE_INSTANCE_ID, requestContext.getActionIdentifiers().getServiceInstanceId());
491             }
492             MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, requestContext.getCommonHeader().getOriginatorId());
493             MDC.put(MDC_INSTANCE_UUID, ""); // value should be created in the future
494             try {
495                 MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName()); //Don't change it to a .getHostName() again please. It's wrong!
496                 MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
497                 MDC.put(LoggingConstants.MDCKeys.SERVER_NAME, InetAddress.getLocalHost().getHostName());
498                 MDC.put(MDC_SERVICE_NAME, requestContext.getAction().name());
499                 MDC.put(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY, requestContext.getActionIdentifiers().getVnfId());
500
501             } catch (Exception e) {
502                 logger.debug(e.getMessage());
503             }
504         } catch (RuntimeException e) {
505             //ignore
506         }
507     }
508
509
510     private int calculateRemainingTTL(CommonHeader commonHeader) {
511         if (logger.isTraceEnabled()) {
512             logger.trace("Entering to calculateRemainingTTL with RequestHeader = " + ObjectUtils.toString(commonHeader));
513         }
514         long usedTimeInMillis = ChronoUnit.MILLIS.between(commonHeader.getTimeStamp(), Instant.now());
515         logger.debug("usedTimeInMillis = " + usedTimeInMillis);
516         int usedTimeInSeconds = Math.round(usedTimeInMillis / 1000);
517         logger.debug("usedTimeInSeconds = " + usedTimeInSeconds);
518         Integer inputTTL = this.getInputTTL(commonHeader);
519         logger.debug("inputTTL = " + inputTTL);
520         Integer remainingTTL = inputTTL - usedTimeInSeconds;
521         logger.debug("Remaining TTL = " + remainingTTL);
522         if (logger.isTraceEnabled())
523             logger.trace("Exiting from calculateRemainingTTL with (remainingTTL = " + ObjectUtils.toString(remainingTTL) + ")");
524         return remainingTTL;
525     }
526
527     private Integer getInputTTL(CommonHeader header) {
528         if (logger.isTraceEnabled())
529             logger.trace("Entering in getInputTTL with RequestHeader = " + ObjectUtils.toString(header));
530         if (!isValidTTL(String.valueOf(header.getFlags().getTtl()))) {
531             String defaultTTLStr = configuration.getProperty("org.openecomp.appc.workflow.default.ttl", String.valueOf(Constants.DEFAULT_TTL));
532             Integer defaultTTL = Integer.parseInt(defaultTTLStr);
533             if (logger.isTraceEnabled())
534                 logger.trace("Exiting from getInputTTL with (defaultTTL = " + ObjectUtils.toString(defaultTTL) + ")");
535             return defaultTTL;
536         }
537         if (logger.isTraceEnabled())
538             logger.trace("Exiting from getInputTTL with (inputTTL = " + ObjectUtils.toString(header.getFlags().getTtl()) + ")");
539
540         return header.getFlags().getTtl();
541     }
542
543     private boolean isValidTTL(String ttl) {
544         if (ttl == null || ttl.length() == 0) {
545             if (logger.isTraceEnabled())
546                 logger.trace("Exiting from getInputTTL with (result = false)");
547             return false;
548         }
549         try {
550             Integer i = Integer.parseInt(ttl);
551             return (i > 0);
552         } catch (NumberFormatException e) {
553             if (logger.isTraceEnabled())
554                 logger.trace("Exiting from getInputTTL with (result = false)");
555             return false;
556         }
557     }
558
559     private Boolean isLoggingEnabled() {
560         String defaultFlagStr = configuration.getProperty("org.openecomp.appc.localTransactionRecorder.enable", String.valueOf(Constants.DEFAULT_LOGGING_FLAG));
561         Boolean defaultFlag = Boolean.parseBoolean(defaultFlagStr);
562         return defaultFlag;
563     }
564
565     private static RequestHandlerOutput buildRequestHandlerOutput(LCMCommandStatus response, Params params) {
566         RequestHandlerOutput output = new RequestHandlerOutput();
567         ResponseContext responseContext = new ResponseContext();
568         responseContext.setStatus(response.toStatus(params));
569         output.setResponseContext(responseContext);
570         return output;
571     }
572
573     /**
574      * This method perform operations required before execution of workflow starts. It retrieves next state for current operation from Lifecycle manager and update it in AAI.
575      *
576      * @return true in case AAI updates are successful. false for any error or exception.
577      */
578     @Override
579     public void onRequestExecutionStart(String vnfId, boolean readOnlyActivity, String requestIdentifierString, boolean forceFlag) throws UnstableVNFException {
580         if (logger.isTraceEnabled()) {
581             logger.trace("Entering to onRequestExecutionStart with vnfId = " + vnfId + "and requestIdentifierString = " + requestIdentifierString);
582         }
583         try {
584             boolean updated = workingStateManager.setWorkingState(vnfId, VNFWorkingState.UNSTABLE, requestIdentifierString, forceFlag);
585             if (!updated) {
586                 throw new UnstableVNFException("VNF is not stable for vnfID = " + vnfId);
587             }
588         } catch (Exception e) {
589             logger.error("Error updating working state for vnf " + vnfId + e);
590             throw new RuntimeException(e);
591         }
592
593         if (logger.isTraceEnabled())
594             logger.trace("Exiting from onRequestExecutionStart ");
595     }
596
597     /**
598      * This method perform following operations required after execution of workflow.
599      * It posts asynchronous response to message bus (DMaaP).
600      * Unlock VNF Id
601      * Removes request from request registry.
602      * Generate audit logs.
603      * Adds transaction record to database id if transaction logging is enabled.
604      *
605      * @param isAAIUpdated boolean flag which indicate AAI upodate status after request completion.
606      */
607     @Override
608     public void onRequestExecutionEnd(RuntimeContext runtimeContext, boolean isAAIUpdated) {
609         if (logger.isTraceEnabled()) {
610             logger.trace("Entering to onRequestExecutionEnd with runtimeContext = " + ObjectUtils.toString(runtimeContext));
611         }
612
613         postMessageToDMaaP(runtimeContext.getRequestContext().getAction(), runtimeContext.getRpcName(), runtimeContext.getResponseContext());
614         requestRegistry.removeRequest(
615                 new UniqueRequestIdentifier(runtimeContext.getResponseContext().getCommonHeader().getOriginatorId(),
616                         runtimeContext.getResponseContext().getCommonHeader().getRequestId(),
617                         runtimeContext.getResponseContext().getCommonHeader().getSubRequestId()));
618         resetLock(runtimeContext.getVnfContext().getId(), runtimeContext.getResponseContext().getCommonHeader().getRequestId(), runtimeContext.isLockAcquired(), true);
619         Status status = runtimeContext.getResponseContext().getStatus();
620
621         VNFWorkingState workingState;
622         if (status.getCode() == LCMCommandStatus.SUCCESS.getResponseCode() || isReadOnlyAction(runtimeContext.getRequestContext().getAction())) {
623             workingState = VNFWorkingState.STABLE;
624         } else {
625             workingState = VNFWorkingState.UNKNOWN;
626         }
627
628         UniqueRequestIdentifier requestIdentifier = new UniqueRequestIdentifier(runtimeContext.getResponseContext().getCommonHeader().getOriginatorId(),
629                 runtimeContext.getResponseContext().getCommonHeader().getRequestId(),
630                 runtimeContext.getResponseContext().getCommonHeader().getSubRequestId());
631
632         String requestIdentifierString = requestIdentifier.toIdentifierString();
633         workingStateManager.setWorkingState(runtimeContext.getVnfContext().getId(), workingState, requestIdentifierString, false);
634
635
636         storeAuditLogRecord(runtimeContext);
637
638         if (isLoggingEnabled()) {
639             createTransactionRecord(runtimeContext);
640         }
641     }
642
643     private void storeAuditLogRecord(RuntimeContext runtimeContext) {
644         LoggingUtils.logAuditMessage(runtimeContext.getTimeStart(),
645                 Instant.now(),
646                 String.valueOf(runtimeContext.getResponseContext().getStatus().getCode()),
647                 runtimeContext.getResponseContext().getStatus().getMessage(),
648                 this.getClass().getCanonicalName());
649     }
650
651     private void storeMetricLogRecord(RuntimeContext runtimeContext) {
652         LoggingUtils.logMetricsMessage(runtimeContext.getTimeStart(),
653                 Instant.now(),
654                 LoggingConstants.TargetNames.APPC,
655                 runtimeContext.getRequestContext().getAction().name(),
656                 runtimeContext.getResponseContext().getStatus().getCode() == LCMCommandStatus.ACCEPTED.getResponseCode() ? LoggingConstants.StatusCodes.COMPLETE : LoggingConstants.StatusCodes.ERROR,
657                 String.valueOf(runtimeContext.getResponseContext().getStatus().getCode()),
658                 runtimeContext.getResponseContext().getStatus().getMessage(),
659                 this.getClass().getCanonicalName());
660     }
661
662     private boolean isReadOnlyAction(VNFOperation action) {
663         return VNFOperation.Sync == action
664                 || VNFOperation.Audit == action;
665     }
666
667
668     //returns null if asyncResponse was not modified otherwise reutrns the updated asyncResponse
669     private void postMessageToDMaaP(VNFOperation operation, String rpcName, ResponseContext responseContext/*, boolean isTTLEnd, boolean aaiUpdateSuccess*/) {
670         if (logger.isTraceEnabled()) {
671             logger.trace("Entering to postMessageToDMaaP with AsyncResponse = " + ObjectUtils.toString(responseContext));
672         }
673         /*boolean updated = updateAsyncResponseStatus(responseContext, isTTLEnd, aaiUpdateSuccess);
674          */
675         boolean callbackResponse = messageAdapter.post(operation, rpcName, responseContext);
676         if (!callbackResponse) {
677             logger.error("DMaaP posting status: " + callbackResponse, "dmaapMessage: " + responseContext);
678         }
679         if (logger.isTraceEnabled())
680             logger.trace("Exiting from postMessageToDMaaP with (callbackResponse = " + ObjectUtils.toString(callbackResponse) + ")");
681     }
682
683     //returns true if asyncResponse was modified
684     /*    private boolean updateAsyncResponseStatus(ResponseContext asyncResponse, boolean isTTLEnd, boolean aaiUpdateSuccess) {
685         boolean updated = false;
686         if (logger.isTraceEnabled())
687             logger.trace("Entering to updateAsyncResponseStatus with AsyncResponse = "+ObjectUtils.toString(asyncResponse)+ ", isTTLEnd = "+ ObjectUtils.toString(isTTLEnd)+ ", aaiUpdateSuccess = "+ ObjectUtils.toString(aaiUpdateSuccess));
688         if(!aaiUpdateSuccess){
689                 if (asyncResponse.getStatus().getCode() == 0 || asyncResponse.getStatus().getCode() == LCMCommandStatus.SUCCESS.getResponseCode()) {
690                     asyncResponse.getStatus().setCode(LCMCommandStatus.UPDATE_AAI_FAILURE.getResponseCode());
691                     asyncResponse.getStatus().setMessage(LCMCommandStatus.UPDATE_AAI_FAILURE.getResponseMessage());
692                 updated = true;
693             }
694         }else if(isTTLEnd){
695                 asyncResponse.getStatus().setCode(LCMCommandStatus.EXPIRED_REQUEST_FAILURE.getResponseCode());
696                 asyncResponse.getStatus().setMessage(LCMCommandStatus.EXPIRED_REQUEST_FAILURE.getResponseMessage());
697             updated = true;
698         }
699         if (logger.isTraceEnabled())
700             logger.trace("Exiting from updateAsyncResponseStatus with (asyncResponse = "+ ObjectUtils.toString(asyncResponse)+")");
701         return updated;
702     }*/
703
704
705     /**
706      * This method perform following operations required if TTL ends when request still waiting in execution queue .
707      * It posts asynchronous response to message bus (DMaaP).
708      * Unlock VNF Id
709      * Removes request from request registry.
710      *
711      * @param runtimeContext AsyncResponse object which contains VNF Id         , timestamp , apiVersion, responseId, executionSuccess, payload, isExpired, action, startTime, vnfType, originatorId, subResponseId;
712      * @param updateAAI      boolean flag which indicate AAI upodate status after request completion.
713      */
714     @Override
715     public void onRequestTTLEnd(RuntimeContext runtimeContext, boolean updateAAI) {
716         if (logger.isTraceEnabled()) {
717             logger.trace("Entering to onRequestTTLEnd with " +
718                     "AsyncResponse = " + ObjectUtils.toString(runtimeContext) +
719                     ", updateAAI = " + ObjectUtils.toString(updateAAI));
720         }
721         logger.error(LCMCommandStatus.EXPIRED_REQUEST_FAILURE.getResponseMessage());
722         fillStatus(runtimeContext, LCMCommandStatus.EXPIRED_REQUEST_FAILURE, null);
723         postMessageToDMaaP(runtimeContext.getRequestContext().getAction(), runtimeContext.getRpcName(), runtimeContext.getResponseContext());
724         resetLock(runtimeContext.getVnfContext().getId(), runtimeContext.getResponseContext().getCommonHeader().getRequestId(), runtimeContext.isLockAcquired(), true);
725         requestRegistry.removeRequest(
726                 new UniqueRequestIdentifier(runtimeContext.getResponseContext().getCommonHeader().getOriginatorId(),
727                         runtimeContext.getResponseContext().getCommonHeader().getRequestId(),
728                         runtimeContext.getResponseContext().getCommonHeader().getSubRequestId()));
729     }
730
731     private SvcLogicContext getVnfdata(String vnf_id, String prefix, SvcLogicContext ctx) throws VNFNotFoundException {
732         String key = "vnf-id = '" + vnf_id + "'";
733         if (logger.isTraceEnabled()) {
734             logger.trace("Entering to getVnfdata with " +
735                     "vnfId = " + vnf_id +
736                     ", prefix = " + prefix +
737                     ", SvcLogicContex = " + ObjectUtils.toString(ctx));
738         }
739         try {
740             QueryStatus response = aaiService.query("generic-vnf", false, null, key, prefix, null, ctx);
741             if (QueryStatus.NOT_FOUND.equals(response)) {
742                 throw new VNFNotFoundException("VNF not found for vnf_id = " + vnf_id);
743             } else if (QueryStatus.FAILURE.equals(response)) {
744                 throw new RuntimeException("Error Querying AAI with vnfID = " + vnf_id);
745             }
746             logger.info("AAIResponse: " + response.toString());
747         } catch (SvcLogicException e) {
748             logger.error("Error in getVnfdata " + e);
749             throw new RuntimeException(e);
750         }
751         if (logger.isTraceEnabled()) {
752             logger.trace("Exiting from getVnfdata with (SvcLogicContext = " + ObjectUtils.toString(ctx) + ")");
753         }
754         return ctx;
755     }
756
757     private boolean postVnfdata(String vnf_id, String status, String prefix, SvcLogicContext ctx) throws VNFNotFoundException {
758         if (logger.isTraceEnabled()) {
759             logger.trace("Entering to postVnfdata with " +
760                     "vnfId = " + vnf_id +
761                     ", status = " + status +
762                     ", prefix = " + prefix +
763                     ", SvcLogicContext = " + ObjectUtils.toString(ctx));
764         }
765         String key = "vnf-id = '" + vnf_id + "'";
766         Map<String, String> data = new HashMap<>();
767         data.put("orchestration-status", status);
768         try {
769             QueryStatus response = aaiService.update("generic-vnf", key, data, prefix, ctx);
770             if (QueryStatus.NOT_FOUND.equals(response)) {
771                 throw new VNFNotFoundException("VNF not found for vnf_id = " + vnf_id);
772             }
773             logger.info("AAIResponse: " + response.toString());
774             if (response.toString().equals("SUCCESS")) {
775                 if (logger.isTraceEnabled()) {
776                     logger.trace("Exiting from postVnfdata with (Result = " + ObjectUtils.toString(true) + ")");
777                 }
778                 return true;
779             }
780
781         } catch (SvcLogicException e) {
782             logger.error("Error in postVnfdata " + e);
783             throw new RuntimeException(e);
784         }
785         if (logger.isTraceEnabled()) {
786             logger.trace("Exiting from postVnfdata with (Result = " + ObjectUtils.toString(false) + ")");
787         }
788         return false;
789     }
790
791     private void initMetric() {
792         if (logger.isDebugEnabled())
793             logger.debug("Metric getting initialized");
794         MetricService metricService = getMetricservice();
795         metricRegistry = metricService.createRegistry("APPC");
796         DispatchingFuntionMetric dispatchingFuntionMetric = metricRegistry.metricBuilderFactory().
797                 dispatchingFunctionCounterBuilder().
798                 withName("DISPATCH_FUNCTION").withType(MetricType.COUNTER).
799                 withAcceptRequestValue(0)
800                 .withRejectRequestValue(0)
801                 .build();
802         if (metricRegistry.register(dispatchingFuntionMetric)) {
803             Metric[] metrics = new Metric[]{dispatchingFuntionMetric};
804             LogPublisher logPublisher = new LogPublisher(metricRegistry, metrics);
805             LogPublisher[] logPublishers = new LogPublisher[1];
806             logPublishers[0] = logPublisher;
807             PublishingPolicy manuallyScheduledPublishingPolicy = metricRegistry.policyBuilderFactory().
808                     scheduledPolicyBuilder().withPublishers(logPublishers).
809                     withMetrics(metrics).
810                     build();
811             if (logger.isDebugEnabled())
812                 logger.debug("Policy getting initialized");
813             manuallyScheduledPublishingPolicy.init();
814             if (logger.isDebugEnabled())
815                 logger.debug("Metric initialized");
816         }
817     }
818
819
820     private MetricService getMetricservice() {
821         BundleContext bctx = FrameworkUtil.getBundle(MetricService.class).getBundleContext();
822         ServiceReference sref = bctx.getServiceReference(MetricService.class.getName());
823         if (sref != null) {
824             logger.info("Metric Service from bundlecontext");
825             return (MetricService) bctx.getService(sref);
826         } else {
827             logger.info("Metric Service error from bundlecontext");
828             logger.warn("Cannot find service reference for org.openecomp.appc.metricservice.MetricService");
829             return null;
830         }
831     }
832 }