--- /dev/null
+/*\r
+ * ============LICENSE_START========================================================================\r
+ * ONAP : tr-069-adapter\r
+ * =================================================================================================\r
+ * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
+ * =================================================================================================\r
+ * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
+ * may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
+ * either express or implied. See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ===============LICENSE_END=======================================================================\r
+ */\r
+\r
+package org.commscope.tr069adapter.acs.requestprocessor.impl;\r
+\r
+import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.CONNECTION_REQUEST;\r
+import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.DEVICE_RESPONSE_TIMEOUT;\r
+import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.SEPERATOR;\r
+import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.SESSION_TIMEOUT_CALLBACK_JNDI;\r
+import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.WAITING_FOR_DEVICE_RESPONSE;\r
+import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.WAITING_FOR_NBI_RESPONSE;\r
+\r
+import java.io.Serializable;\r
+import java.util.List;\r
+\r
+import org.commscope.tr069adapter.acs.common.DeviceRPCRequest;\r
+import org.commscope.tr069adapter.acs.common.DeviceRPCResponse;\r
+import org.commscope.tr069adapter.acs.common.dto.TR069DeviceDetails;\r
+import org.commscope.tr069adapter.acs.common.exception.DeviceOperationException;\r
+import org.commscope.tr069adapter.acs.common.exception.SessionManagerException;\r
+import org.commscope.tr069adapter.acs.common.utils.ErrorCode;\r
+import org.commscope.tr069adapter.acs.requestprocessor.DeviceOperationInterface;\r
+import org.commscope.tr069adapter.acs.requestprocessor.dao.DeviceRPCRequestRepositoryHelper;\r
+import org.commscope.tr069adapter.acs.requestprocessor.dto.SessionDTO;\r
+import org.commscope.tr069adapter.acs.requestprocessor.dto.SessionState;\r
+import org.commscope.tr069adapter.acs.requestprocessor.entity.TR069DeviceRPCRequestEntity;\r
+import org.commscope.tr069adapter.acs.requestprocessor.helper.TR069RequestProcessEngineUtility;\r
+import org.commscope.tr069adapter.acs.requestprocessor.util.TR069RequestProcessorUtility;\r
+import org.commscope.tr069adapter.common.timer.TimerException;\r
+import org.commscope.tr069adapter.common.timer.TimerListener;\r
+import org.commscope.tr069adapter.common.timer.TimerServiceManagerAPI;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.slf4j.MDC;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.stereotype.Component;\r
+import org.springframework.transaction.annotation.Isolation;\r
+import org.springframework.transaction.annotation.Propagation;\r
+import org.springframework.transaction.annotation.Transactional;\r
+\r
+@Component(SESSION_TIMEOUT_CALLBACK_JNDI)\r
+public class SessionTimeoutHandler implements TimerListener {\r
+\r
+\r
+\r
+ private static final Logger logger = LoggerFactory.getLogger(SessionTimeoutHandler.class);\r
+\r
+ private static final String CLIENT_STR = "client";\r
+\r
+ @Autowired\r
+ private SessionManager sessionManager;\r
+\r
+ @Autowired\r
+ TR069EventNotificationService eventNotificationService;\r
+\r
+ @Autowired\r
+ DeviceOperationInterface deviceOperationInterface;\r
+\r
+ @Autowired\r
+ private TimerServiceManagerAPI timerServiceManagerAPI;\r
+\r
+ @Autowired\r
+ private DeviceRPCRequestRepositoryHelper deviceRPCRequestRepositoryHelper;\r
+\r
+ @Autowired\r
+ private TR069RequestProcessEngineUtility tr069ProcessEngineUtility;\r
+\r
+ @Transactional(isolation = Isolation.DEFAULT, timeout = 300,\r
+ propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})\r
+ @Override\r
+ public void notifyTimeout(String timerId, Serializable data) {\r
+\r
+ String timeoutType = (String) data;\r
+\r
+ logger.info("Timeout notification received for the type: {}", timeoutType);\r
+ if (WAITING_FOR_NBI_RESPONSE.equals(timeoutType)) {\r
+ handleNBIResponseTimeout(timerId);\r
+ } else if (WAITING_FOR_DEVICE_RESPONSE.equals(timeoutType)) {\r
+ handleDeviceResponseTimeout(timerId);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Handling the NBI response timeout\r
+ * \r
+ * @param timerId\r
+ */\r
+ private void handleNBIResponseTimeout(String timerId) {\r
+ String[] splitTimerId = timerId.split(SEPERATOR);\r
+ String deviceId = splitTimerId[0];\r
+ String operationId = splitTimerId[1];\r
+ try {\r
+ MDC.put(CLIENT_STR, deviceId);\r
+ // Only session must be moved to terminated state in such case\r
+ logger.debug("The NBI operation request {} has timeout", operationId);\r
+\r
+ TR069DeviceDetails deviceDetails = deviceOperationInterface.getDeviceDetails(deviceId);\r
+ List<TR069DeviceRPCRequestEntity> deviceRPCRequestEntityList =\r
+ deviceRPCRequestRepositoryHelper.findByDeviceIdAndOperationId(deviceId,\r
+ Long.valueOf(operationId));\r
+\r
+ if (deviceRPCRequestEntityList != null) {\r
+ logger.debug(\r
+ "Device details and the NBI Operation request are successfully fetched for operationId: {}",\r
+ operationId);\r
+ DeviceRPCRequest nbiDeviceOperationrequest =\r
+ TR069RequestProcessorUtility.convertToDTO(deviceRPCRequestEntityList);\r
+ DeviceRPCResponse deviceRPCResponse = tr069ProcessEngineUtility\r
+ .buildTimedOutOperationResult(deviceDetails, nbiDeviceOperationrequest);\r
+\r
+ eventNotificationService.sendOperationResultToNBI(deviceRPCResponse);\r
+ logger.debug("Successfully notified timed out operation result to NBI");\r
+\r
+ // Marking the NBI Request as processed\r
+ for (TR069DeviceRPCRequestEntity deviceRPCRequestEntity : deviceRPCRequestEntityList) {\r
+ deviceRPCRequestEntity.setIsProcessed(Integer.valueOf(1));\r
+ }\r
+ deviceRPCRequestRepositoryHelper.saveAll(deviceRPCRequestEntityList);\r
+\r
+ logger.debug("Stopping the connection request timer if any running");\r
+ String connectionRequestTimerId = deviceId + SEPERATOR + CONNECTION_REQUEST;\r
+ timerServiceManagerAPI.stopTimer(connectionRequestTimerId);\r
+ }\r
+ } catch (DeviceOperationException e) {\r
+ logger.error(\r
+ "Fetching device details failed for timed out operation processing for operation id: {} Reason: {}",\r
+ operationId, e.getMessage());\r
+ } catch (TimerException e) {\r
+ logger.debug(\r
+ "Failed stopping the timer job for connection request retry timer for operation id: {} Reason: {}",\r
+ operationId, e.getMessage());\r
+ } catch (Exception e) {\r
+ logger.error(\r
+ "An unknown exception occurred while timed out operation processing for operation id: {} Reason: {}",\r
+ operationId, e.getMessage());\r
+ } finally {\r
+ MDC.remove(CLIENT_STR);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Handling the device inform response timeout\r
+ * \r
+ * @param sessionId\r
+ */\r
+ private void handleDeviceResponseTimeout(String sessionId) {\r
+ SessionDTO session = null;\r
+ try {\r
+ session = sessionManager.getSessionBySessionId(sessionId);\r
+ } catch (SessionManagerException e) {\r
+ if (ErrorCode.SESSION_EXPIRED.equals(e.getErrorCode())) {\r
+ logger.info(\r
+ "The session {} does not exist or already in TERMINATED state, hence ignoring the timeout notification",\r
+ sessionId);\r
+ return;\r
+ }\r
+\r
+ logger.debug("Session fetching failed, Reason: {} ", e.getMessage());\r
+ }\r
+\r
+ try {\r
+ // Only session must be moved to terminated state in such case\r
+ if (session != null) {\r
+ MDC.put(CLIENT_STR, session.getDeviceId());\r
+ boolean isSessionReset = false;\r
+\r
+ String deviceId = session.getDeviceId();\r
+ Long operationId = session.getCurrentOperationId();\r
+ if (operationId != null && operationId != 0l\r
+ && !SessionState.TERMINATED.equals(session.getSessionState())) {\r
+ List<TR069DeviceRPCRequestEntity> deviceRPCRequestEntityList =\r
+ deviceRPCRequestRepositoryHelper.findByDeviceIdAndOperationId(deviceId, operationId);\r
+ Integer isProcessed = deviceRPCRequestEntityList.get(0).getIsProcessed();\r
+ if (isProcessed != null && isProcessed == 0) {\r
+ logger.debug(\r
+ "The Device RPC request is still in processing state, hence resetting the session timer");\r
+ timerServiceManagerAPI.modifyTimer(sessionId, DEVICE_RESPONSE_TIMEOUT,\r
+ WAITING_FOR_DEVICE_RESPONSE);\r
+ logger.debug("Successfully restarted the session timer for session: {} ", sessionId);\r
+ isSessionReset = true;\r
+ }\r
+ }\r
+\r
+ if (!isSessionReset) {\r
+ logger.debug("Updating the session state to terminated");\r
+ session.setSessionState(SessionState.TERMINATED);\r
+ sessionManager.updateSession(session);\r
+ logger.debug("Successfully handled timeout notification of Device Response");\r
+ }\r
+ }\r
+ } catch (Exception e) {\r
+ logger.error(\r
+ "An error occurred while checking the NBI state to reset the session timer, Reason: {}",\r
+ e.getMessage());\r
+ logger.debug("Updating the session to TERMINATED failed during timeout, Reason: {}",\r
+ e.getMessage());\r
+ } finally {\r
+ MDC.remove(CLIENT_STR);\r
+ }\r
+ }\r
+}\r