91dacb323628d2e3d1121424ffe2b42fc22c50fe
[oam/tr069-adapter.git] / acs / requestprocessor / src / main / java / org / commscope / tr069adapter / acs / requestprocessor / impl / TR069RequestProcessEngine.java
1 /*\r
2  * ============LICENSE_START========================================================================\r
3  * ONAP : tr-069-adapter\r
4  * =================================================================================================\r
5  * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
6  * =================================================================================================\r
7  * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
8  * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
9  * may obtain a copy of the License at\r
10  *\r
11  * http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
14  * either express or implied. See the License for the specific language governing permissions and\r
15  * limitations under the License.\r
16  * ===============LICENSE_END=======================================================================\r
17  */\r
18 \r
19 package org.commscope.tr069adapter.acs.requestprocessor.impl;\r
20 \r
21 import static org.commscope.tr069adapter.acs.common.utils.AcsConstants.SESSION_ID;\r
22 \r
23 import java.util.List;\r
24 \r
25 import org.commscope.tr069adapter.acs.common.DeviceDetails;\r
26 import org.commscope.tr069adapter.acs.common.DeviceInform;\r
27 import org.commscope.tr069adapter.acs.common.DeviceRPCRequest;\r
28 import org.commscope.tr069adapter.acs.common.DeviceRPCResponse;\r
29 import org.commscope.tr069adapter.acs.common.OperationCode;\r
30 import org.commscope.tr069adapter.acs.common.OperationDetails;\r
31 import org.commscope.tr069adapter.acs.common.OperationResponse;\r
32 import org.commscope.tr069adapter.acs.common.dto.CustomOperationCode;\r
33 import org.commscope.tr069adapter.acs.common.dto.DeviceOperationRequestDetails;\r
34 import org.commscope.tr069adapter.acs.common.dto.TR069DeviceDetails;\r
35 import org.commscope.tr069adapter.acs.common.dto.TR069InformType;\r
36 import org.commscope.tr069adapter.acs.common.dto.TR069OperationCode;\r
37 import org.commscope.tr069adapter.acs.common.dto.TR069OperationDetails;\r
38 import org.commscope.tr069adapter.acs.common.exception.DeviceOperationException;\r
39 import org.commscope.tr069adapter.acs.common.exception.SessionConcurrentAccessException;\r
40 import org.commscope.tr069adapter.acs.common.exception.SessionManagerException;\r
41 import org.commscope.tr069adapter.acs.common.exception.TR069EventProcessingException;\r
42 import org.commscope.tr069adapter.acs.common.faults.AcsFaultCode;\r
43 import org.commscope.tr069adapter.acs.common.inform.BootInform;\r
44 import org.commscope.tr069adapter.acs.common.inform.BootstrapInform;\r
45 import org.commscope.tr069adapter.acs.common.response.DeviceInformResponse;\r
46 import org.commscope.tr069adapter.acs.common.utils.ErrorCode;\r
47 import org.commscope.tr069adapter.acs.requestprocessor.DeviceOperationInterface;\r
48 import org.commscope.tr069adapter.acs.requestprocessor.dao.DeviceRPCRequestRepositoryHelper;\r
49 import org.commscope.tr069adapter.acs.requestprocessor.dto.CustomOperationData;\r
50 import org.commscope.tr069adapter.acs.requestprocessor.dto.SessionDTO;\r
51 import org.commscope.tr069adapter.acs.requestprocessor.dto.SessionState;\r
52 import org.commscope.tr069adapter.acs.requestprocessor.dto.TR069RequestProcessorData;\r
53 import org.commscope.tr069adapter.acs.requestprocessor.entity.TR069DeviceRPCRequestEntity;\r
54 import org.commscope.tr069adapter.acs.requestprocessor.helper.TR069RequestProcessEngineHelper;\r
55 import org.commscope.tr069adapter.acs.requestprocessor.util.TR069RequestProcessorUtility;\r
56 import org.slf4j.Logger;\r
57 import org.slf4j.LoggerFactory;\r
58 import org.springframework.beans.factory.annotation.Autowired;\r
59 import org.springframework.stereotype.Component;\r
60 \r
61 @Component\r
62 public class TR069RequestProcessEngine extends TR069RequestProcessEngineHelper {\r
63 \r
64   private static final String PENDING_RPC_CHECK =\r
65       "Checking if any pending Device RPC requests exists for the device";\r
66 \r
67   private static final Logger logger = LoggerFactory.getLogger(TR069RequestProcessEngine.class);\r
68 \r
69   @Autowired\r
70   TR069EventNotificationService tr069EventNotificationService;\r
71 \r
72   @Autowired\r
73   DeviceOperationInterface deviceOperationInterface;\r
74 \r
75   @Autowired\r
76   protected DeviceRPCRequestRepositoryHelper deviceRPCRequestRepositoryHelper;\r
77 \r
78   /**\r
79    * @param deviceRPCRequest\r
80    * @throws TR069EventProcessingException\r
81    * @throws SessionConcurrentAccessException\r
82    */\r
83   public void processDeviceRPCRequest(DeviceRPCRequest deviceRPCRequest)\r
84       throws TR069EventProcessingException, SessionConcurrentAccessException {\r
85 \r
86     DeviceRPCResponse deviceRPCResponse = null;\r
87     String deviceId = null;\r
88 \r
89     try {\r
90       if (deviceRPCRequest == null) {\r
91         TR069EventProcessingException ex =\r
92             new TR069EventProcessingException(ErrorCode.INVALID_NBI_REQUEST);\r
93         logger.error(ex.getMessage());\r
94         throw ex;\r
95       }\r
96 \r
97       Long operationId = deviceRPCRequest.getOperationId();\r
98       logger.info("A Mapper request is received with operationID: {}", operationId);\r
99       TR069DeviceDetails tr069DeviceDetails = null;\r
100       deviceId = deviceRPCRequest.getDeviceDetails().getDeviceId();\r
101       try {\r
102         tr069DeviceDetails = deviceOperationInterface.getDeviceDetails(deviceId);\r
103         deviceRPCResponse = checkForDeviceAvailabilityRequest(deviceRPCRequest, tr069DeviceDetails);\r
104         if (null != deviceRPCResponse) {\r
105           return;\r
106         }\r
107       } catch (DeviceOperationException | SessionManagerException deo) {\r
108         logger.error(deo.getMessage());\r
109         deviceRPCResponse = tr069RequestProcessEngineUtility.buildAbortedOperationresult(\r
110             tr069DeviceDetails, deviceRPCRequest, AcsFaultCode.FAULT_CODE_8000);\r
111         return;\r
112       }\r
113 \r
114       try {\r
115         SessionDTO sessionDTO = acquireSessionLockWithRetryOnFailure(deviceId, operationId);\r
116 \r
117         logger.debug("Persisting the Device RPC request, with operation ID: {}", operationId);\r
118         List<TR069DeviceRPCRequestEntity> tr069DeviceRPCRequestEntities =\r
119             TR069RequestProcessorUtility.convertToEntity(deviceRPCRequest);\r
120         deviceRPCRequestRepositoryHelper.saveAll(tr069DeviceRPCRequestEntities);\r
121         logger.info("Successfully persisted the Device RPC request");\r
122 \r
123         if (sessionDTO != null) {\r
124           if (SessionState.TERMINATED.equals(sessionDTO.getSessionState())) {\r
125             logger.debug("No active session exists, hence requesting for Connection request");\r
126             requestForConnectionRequestInform(tr069DeviceDetails);\r
127 \r
128             // Start Request Timer\r
129             startDeviceRPCRequestTimer(deviceId, deviceRPCRequest.getOperationId(),\r
130                 deviceRPCRequest.getOptions().getExecutionTimeout());\r
131           } else {\r
132             logger.debug(\r
133                 "Session is in processing state, Will be notified to session manager to pick the request on session availability");\r
134           }\r
135         } else {\r
136           logger.warn(\r
137               "The device is not activated yet, hence the NBI Operation result cannot be processed!");\r
138           deviceRPCResponse = tr069RequestProcessEngineUtility.buildAbortedOperationresult(\r
139               tr069DeviceDetails, deviceRPCRequest, AcsFaultCode.FAULT_CODE_8001);\r
140         }\r
141       } catch (SessionConcurrentAccessException scae) {\r
142         throw scae;\r
143       } catch (Exception e) {\r
144         logger.error("An unknown exception occurred while processing the NBI request, Reason: {}",\r
145             e.getMessage());\r
146         deviceRPCResponse = tr069RequestProcessEngineUtility.buildAbortedOperationresult(\r
147             tr069DeviceDetails, deviceRPCRequest, AcsFaultCode.FAULT_CODE_8004);\r
148       }\r
149     } finally {\r
150       if (deviceRPCResponse != null) {\r
151         logger.debug("Sending failed operation result for this NBI request");\r
152         tr069EventNotificationService.sendOperationResultToNBI(deviceRPCResponse);\r
153         // Marking the NBI Request as processed\r
154         deviceRPCRequestRepositoryHelper.markDeviceRPCRequestAsProcessed(deviceId,\r
155             deviceRPCRequest.getOperationId());\r
156       }\r
157     }\r
158   }\r
159 \r
160   private DeviceRPCResponse checkForDeviceAvailabilityRequest(DeviceRPCRequest deviceRPCRequest,\r
161       TR069DeviceDetails tr069DeviceDetails) throws SessionManagerException {\r
162     DeviceRPCResponse deviceRPCResponse = null;\r
163 \r
164     if (!deviceRPCRequest.getOpDetails().getOpCode().equals(CustomOperationCode.CONNECT)) {\r
165       return deviceRPCResponse;\r
166     }\r
167 \r
168     SessionDTO sessionDTO = getSession(tr069DeviceDetails.getDeviceId());\r
169 \r
170     if (null != sessionDTO && !SessionState.TERMINATED.equals(sessionDTO.getSessionState())) {\r
171       logger.debug("Device is reachable as device tr069 session is in {} state.",\r
172           sessionDTO.getSessionState());\r
173 \r
174       deviceRPCResponse = new DeviceRPCResponse();\r
175       deviceRPCResponse.setDeviceDetails(tr069DeviceDetails);\r
176       deviceRPCResponse.setOperationId(deviceRPCRequest.getOperationId());\r
177 \r
178       OperationResponse operationResponse = new OperationResponse();\r
179       // device reachable...change value 1 to some constant or enum\r
180       operationResponse.setStatus(TR069RequestProcessorUtility.DEVICE_REACHABLE_STATUS_CODE);\r
181       operationResponse.setOperationCode(deviceRPCRequest.getOpDetails().getOpCode());\r
182 \r
183       deviceRPCResponse.setOperationResponse(operationResponse);\r
184     }\r
185 \r
186     return deviceRPCResponse;\r
187   }\r
188 \r
189   /**\r
190    * Common Step 1. Since there can exist only one Inform from any device, which will be the\r
191    * initiator of the session, following steps to be followed a. Stop the session timer for this\r
192    * device if any running. b. Get the lock by reading the session record for this device from DB\r
193    * and load the session object in Thread Local Cache c. Create a new session id from\r
194    * SessionManager, and update the session object with new Session id and change the state to\r
195    * PROCESSING. 2. Read the Device record from the DB, and load the device DTO also in the\r
196    * ThreadLocalCache\r
197    * \r
198    * Common Notification Specific Step 1. Take the connection request URL from the\r
199    * deviceNotification object 2. Update the Device DTO object with connection request URL,\r
200    * swVersion, hwVersion if there is a difference. Update the last updated time if updated 3. Send\r
201    * this Inform to the NBI, by calling the ProcessDeviceInform method on TR069NBIService module. 4.\r
202    * Create the Inform response Object and update the sessionID used for this transaction in the\r
203    * response which will be used in the cookie of the HTTP response 5. Post the message into\r
204    * Response Queue 6. Change the session state to LOCKED 7. Save the Session and device records\r
205    * with the values in ThreadLocalCache 8. Start the session timer and default request timer (As\r
206    * configured for all the requests from device) 8. All the above steps to be executed in a single\r
207    * transaction.\r
208    * \r
209    * @param deviceNotification\r
210    * @return\r
211    * @throws SessionConcurrentAccessException\r
212    */\r
213   public DeviceInformResponse processDeviceInform(DeviceInform deviceNotification)\r
214       throws SessionConcurrentAccessException {\r
215 \r
216     String deviceId = deviceNotification.getDeviceDetails().getDeviceId();\r
217     TR069InformType notificationType = (TR069InformType) deviceNotification.getInformType();\r
218     logger.info("Processing the Device Inform Event: '{}'", notificationType.getNotificationCode());\r
219     String newSessionId = null;\r
220     SessionDTO session = null;\r
221     TR069DeviceDetails deviceDetails = null;\r
222     DeviceInformResponse informResponse = null;\r
223 \r
224     try {\r
225 \r
226       SessionDTO sessionDTO = getSession(deviceId);\r
227       if (sessionDTO != null && !SessionState.TERMINATED.equals(sessionDTO.getSessionState())) {\r
228         String sessionId = sessionDTO.getSessionId();\r
229         logger.debug(\r
230             "The session with session id {} is not terminated, hence stopping the associated timer",\r
231             sessionId);\r
232         stopSessionTimer(sessionDTO.getSessionId());\r
233       }\r
234 \r
235       // To stop the request timer if any running for this device, and send failed operation\r
236       // result for any such pending cases. Requests pending in DB should not be cleared\r
237 \r
238       /*\r
239        * Read any pending records in TR069_NBI_REQUEST table for this device. Send abort operation\r
240        * result for all the pending requests Delete the records from the TR069_NBI_Request table for\r
241        * this device.\r
242        */\r
243       if (deviceNotification instanceof BootstrapInform\r
244           || deviceNotification instanceof BootInform) {\r
245         sendAbortedOperationResultForPendingRPCRequests(deviceNotification.getDeviceDetails(),\r
246             notificationType);\r
247       }\r
248 \r
249       session = acquireSessionLock(deviceId, notificationType, true);\r
250       deviceDetails = getPersistedDeviceDetails(deviceId, deviceNotification);\r
251 \r
252       newSessionId = session.getSessionId();\r
253       logger.debug("The session id generated to process the device notification request is: {} ",\r
254           newSessionId);\r
255 \r
256       initThreadLocalCache(deviceDetails, session);\r
257       TR069RequestProcessorData tr069RequestProcessorData = getTR069RequestProcessorData();\r
258       updateSessionOnDeviceNotification(tr069RequestProcessorData, newSessionId);\r
259 \r
260       logger.debug("Sending the Device Inform Event to the Mapper");\r
261       tr069EventNotificationService.sendDeviceInformToNBI(deviceNotification);\r
262 \r
263       updateDeviceDetailsFromInform(tr069RequestProcessorData, deviceNotification);\r
264 \r
265       logger.debug("Updating the session for the device with newly generated session id");\r
266       changeSessionState(tr069RequestProcessorData, SessionState.LOCKED);\r
267       updateSession(session);\r
268 \r
269       // Start session timer - Get a default timeout for session.\r
270       startSessionTimer(session.getSessionId());\r
271 \r
272       informResponse =\r
273           new DeviceInformResponse(newSessionId, deviceNotification.getDeviceDetails());\r
274     } catch (\r
275 \r
276     DeviceOperationException doe) {\r
277       logger.error(doe.getMessage());\r
278     } catch (SessionConcurrentAccessException scae) {\r
279       throw scae;\r
280     } catch (Exception e) {\r
281       throw new SessionConcurrentAccessException(ErrorCode.UNKNOWN_ERROR, e.getMessage());\r
282     }\r
283     return informResponse;\r
284   }\r
285 \r
286   /**\r
287    * \r
288    * 1. Stop the request timer for this device using the session ID received in the cookie of the\r
289    * request 2. Read the session record from the session table into ThreadLocalCache 3. Move the\r
290    * session state to PROCESSING and update the OPERATION_ID as null. 4a. Session Manager to check\r
291    * if any pending request being notified for the device using in memory cache - Not planned for\r
292    * this Drop 4. As an interim solution for drop1, Check the TR069_NBI_REQUEST table if any request\r
293    * is pending.\r
294    * \r
295    * if (anyPendingRequestExists) { 1. Pick the request with the least created_time 2. Create the\r
296    * response object and update the sessionID used for this transaction in the response which will\r
297    * be used in the cookie of the HTTP response 3. Post the response object into Response Queue 4.\r
298    * Change the session state to LOCKED and update the OPERATION_ID in the session table with the\r
299    * NBI requests OPERATION_ID. 5. Save the Session record with the values in ThreadLocalCache 6.\r
300    * Start the session timer and request timer (available in the request) } else { 1. Move the\r
301    * session state to PROCESSING and update the OPERATION_ID as null. 2. Save the Session record\r
302    * with the values in ThreadLocalCache. 3. Start the session timer. }\r
303    * \r
304    * 6. All the above steps to be executed in a single transaction\r
305    * \r
306    * @param deviceRPCResponse\r
307    * @return\r
308    * @throws SessionConcurrentAccessException\r
309    */\r
310   public DeviceRPCRequest processDeviceRPCResponse(DeviceRPCResponse deviceRPCResponse)\r
311       throws SessionConcurrentAccessException {\r
312     TR069DeviceDetails deviceDetails = (TR069DeviceDetails) deviceRPCResponse.getDeviceDetails();\r
313     String deviceId = deviceDetails.getDeviceId();\r
314     logger.info("Processing the operation response from device");\r
315 \r
316     SessionDTO session;\r
317     DeviceRPCRequest deviceRPCRequest = null;\r
318     try {\r
319       session = acquireSessionLock(deviceId, null, false);\r
320       String newSessionId = session.getSessionId();\r
321       logger.debug("The session id used to process the device RPC response is: {}", newSessionId);\r
322 \r
323       initThreadLocalCache(deviceDetails, session);\r
324       TR069RequestProcessorData tr069RequestProcessorData = getTR069RequestProcessorData();\r
325       updateSessionOnDeviceNotification(tr069RequestProcessorData, newSessionId);\r
326 \r
327       Long operationId = deviceRPCResponse.getOperationId();\r
328 \r
329       deviceRPCRequest = getNextRPCRequest(deviceId, operationId);\r
330 \r
331       if (deviceRPCRequest != null) {\r
332         OperationDetails opDetails = deviceRPCRequest.getOpDetails();\r
333         if (opDetails != null) {\r
334           OperationCode opCode = opDetails.getOpCode();\r
335           if (opCode instanceof CustomOperationCode) {\r
336             CustomOperationCode customOperationCode = (CustomOperationCode) opCode;\r
337             String customOperationCodeName = customOperationCode.name();\r
338             logger.info(\r
339                 "The Device RPC request is of custom type, the custom operation to be performed is: {}",\r
340                 customOperationCodeName);\r
341             String jndiName = customOperationCode.getJndiName();\r
342             CustomOperationData customOperationData =\r
343                 new CustomOperationData(deviceDetails, deviceRPCResponse, deviceRPCRequest);\r
344             customOperationData = executeCustomOperation(jndiName, customOperationData);\r
345 \r
346             DeviceRPCRequest operationRequest = customOperationData.getDeviceRPCRequest();\r
347             deviceRPCResponse = customOperationData.getDeviceRPCResponse();\r
348             if (operationRequest != null) {\r
349               return handleOperationRequest(deviceRPCResponse, session, deviceRPCRequest,\r
350                   newSessionId, tr069RequestProcessorData, operationRequest);\r
351             } else {\r
352               logger.debug(PENDING_RPC_CHECK);\r
353               deviceRPCRequest =\r
354                   deviceRPCRequestRepositoryHelper.findOldestDeviceRPCRequest(deviceId);\r
355             }\r
356           }\r
357         }\r
358       }\r
359 \r
360       if (deviceRPCRequest != null) {\r
361         logger.info("A pending Device RPC request exists for the device with operation ID: {}",\r
362             deviceRPCRequest.getOperationId());\r
363         updateSessionCurOpId(tr069RequestProcessorData, deviceRPCRequest.getOperationId());\r
364         changeSessionState(tr069RequestProcessorData, SessionState.LOCKED);\r
365 \r
366         deviceRPCRequest.addContextParam(SESSION_ID, newSessionId);\r
367 \r
368       } else {\r
369         logger.info(\r
370             "No pending Device RPC request exists for the device, hence empty response will be sent to the device");\r
371         logger.debug("Updating the session to terminated state");\r
372         // To stop the session timer if any running for this device.\r
373         stopSessionTimer(newSessionId);\r
374         changeSessionState(tr069RequestProcessorData, SessionState.TERMINATED);\r
375       }\r
376 \r
377       // To stop the request timer if any running for this operation.\r
378       stopDeviceRPCRequestTimer(deviceId, deviceRPCResponse.getOperationId());\r
379 \r
380       // Sending the operation response to NBI\r
381       logger.debug("Sending the Device RPC Response to the Mapper");\r
382       tr069EventNotificationService.sendOperationResultToNBI(deviceRPCResponse);\r
383 \r
384       updateSession(session);\r
385     } catch (DeviceOperationException doe) {\r
386       logger.error(doe.getMessage());\r
387     } catch (SessionConcurrentAccessException scae) {\r
388       throw scae;\r
389     }\r
390 \r
391     return deviceRPCRequest;\r
392   }\r
393 \r
394   private DeviceRPCRequest handleOperationRequest(DeviceRPCResponse deviceRPCResponse,\r
395       SessionDTO session, DeviceRPCRequest deviceRPCRequest, String newSessionId,\r
396       TR069RequestProcessorData tr069RequestProcessorData, DeviceRPCRequest operationRequest) {\r
397     operationRequest.addContextParam(SESSION_ID, newSessionId);\r
398     updateSessionCurOpId(tr069RequestProcessorData, deviceRPCRequest.getOperationId());\r
399     changeSessionState(tr069RequestProcessorData, SessionState.LOCKED);\r
400     updateSession(session);\r
401     if (deviceRPCResponse != null && operationRequest.getOperationId() != null\r
402         && !operationRequest.getOperationId().equals(deviceRPCResponse.getOperationId())) {\r
403       logger\r
404           .debug("Sending the Device RPC response for a configure Multiple object prior operation");\r
405       // Sending the operation response to NBI\r
406       tr069EventNotificationService.sendOperationResultToNBI(deviceRPCResponse);\r
407     }\r
408     return operationRequest;\r
409   }\r
410 \r
411   /**\r
412    * \r
413    * 1. Stop the request timer for this device using the session ID received in the cookie of the\r
414    * request 2. Read the session record from the session table into ThreadLocalCache 3. Move the\r
415    * session state to PROCESSING and update the OPERATION_ID as null. 4a. Session Manager to check\r
416    * if any pending request being notified for the device using in memory cache - Not planned for\r
417    * this Drop 4. As an interim solution for drop1, Check the TR069_NBI_REQUEST table if any request\r
418    * is pending.\r
419    * \r
420    * if (anyPendingRequestExists) { 1. Pick the request with the least created_time 2. Create the\r
421    * response object and update the sessionID used for this transaction in the response which will\r
422    * be used in the cookie of the HTTP response 3. Post the response object into Response Queue 4.\r
423    * Change the session state to LOCKED and update the OPERATION_ID in the session table with the\r
424    * NBI requests OPERATION_ID. 5. Save the Session record with the values in ThreadLocalCache 6.\r
425    * Start the session timer and request timer (available in the request) } else { 1. Move the\r
426    * session state to PROCESSING and update the OPERATION_ID as null. 2. Save the Session record\r
427    * with the values in ThreadLocalCache. 3. Start the session timer. }\r
428    * \r
429    * 6. All the above steps to be executed in a single transaction\r
430    * \r
431    * @param deviceDetails\r
432    * @return\r
433    * @throws SessionConcurrentAccessException\r
434    */\r
435   public DeviceRPCRequest processEmptyDeviceRequest(TR069DeviceDetails deviceDetails)\r
436       throws SessionConcurrentAccessException {\r
437     String deviceId = deviceDetails.getDeviceId();\r
438     logger.info("Processing the empty request from device");\r
439 \r
440     SessionDTO session;\r
441     DeviceRPCRequest nbiDeviceOperationRequest = null;\r
442     try {\r
443       session = acquireSessionLock(deviceId, null, false);\r
444       String newSessionId = session.getSessionId();\r
445       logger.debug("The session id used to process the empty device request is: {}", newSessionId);\r
446 \r
447       initThreadLocalCache(deviceDetails, session);\r
448       TR069RequestProcessorData tr069RequestProcessorData = getTR069RequestProcessorData();\r
449       updateSessionOnDeviceNotification(tr069RequestProcessorData, newSessionId);\r
450 \r
451       logger.debug(PENDING_RPC_CHECK);\r
452       nbiDeviceOperationRequest =\r
453           deviceRPCRequestRepositoryHelper.findOldestDeviceRPCRequest(deviceId);\r
454       if (nbiDeviceOperationRequest != null) {\r
455         Long operationId = nbiDeviceOperationRequest.getOperationId();\r
456         OperationDetails opDetails = nbiDeviceOperationRequest.getOpDetails();\r
457         if (opDetails != null) {\r
458           OperationCode opCode = opDetails.getOpCode();\r
459           if (opCode instanceof CustomOperationCode) {\r
460             CustomOperationCode customOperationCode = (CustomOperationCode) opCode;\r
461             String customOperationCodeName = customOperationCode.name();\r
462             logger.info(\r
463                 "The Device RPC operation request is of custom type, the custom operation to be performed is: {}",\r
464                 customOperationCodeName);\r
465             String jndiName = customOperationCode.getJndiName();\r
466             CustomOperationData customOperationData =\r
467                 new CustomOperationData(deviceDetails, null, nbiDeviceOperationRequest);\r
468             customOperationData = executeCustomOperation(jndiName, customOperationData);\r
469 \r
470             DeviceRPCRequest operationRequest = customOperationData.getDeviceRPCRequest();\r
471             if (operationRequest != null) {\r
472               operationRequest.addContextParam(SESSION_ID, newSessionId);\r
473               updateSessionCurOpId(tr069RequestProcessorData, operationId);\r
474               changeSessionState(tr069RequestProcessorData, SessionState.LOCKED);\r
475               updateSession(session);\r
476               return operationRequest;\r
477             } else {\r
478               logger.debug(PENDING_RPC_CHECK);\r
479               nbiDeviceOperationRequest =\r
480                   deviceRPCRequestRepositoryHelper.findOldestDeviceRPCRequest(deviceId);\r
481             }\r
482           }\r
483         }\r
484       }\r
485 \r
486       if (nbiDeviceOperationRequest != null) {\r
487         Long operationId = nbiDeviceOperationRequest.getOperationId();\r
488         logger.info("A pending Device RPC request exists for the device with operation ID: {}",\r
489             operationId);\r
490         updateSessionCurOpId(tr069RequestProcessorData, operationId);\r
491         changeSessionState(tr069RequestProcessorData, SessionState.LOCKED);\r
492 \r
493         nbiDeviceOperationRequest.addContextParam(SESSION_ID, newSessionId);\r
494 \r
495       } else {\r
496         logger.info(\r
497             "No pending Device RPC request exists for the device, hence empty device response will be sent to the device");\r
498         logger.debug("Updating the session to terminated state");\r
499         // To stop the session timer if any running for this device.\r
500         stopSessionTimer(newSessionId);\r
501         changeSessionState(tr069RequestProcessorData, SessionState.TERMINATED);\r
502       }\r
503 \r
504       updateSession(session);\r
505     } catch (DeviceOperationException doe) {\r
506       logger.error(doe.getMessage());\r
507     } catch (SessionConcurrentAccessException scae) {\r
508       throw scae;\r
509     }\r
510 \r
511     return nbiDeviceOperationRequest;\r
512   }\r
513 \r
514   /**\r
515    * @param sessionId\r
516    * @return\r
517    * @throws SessionManagerException\r
518    */\r
519   public DeviceOperationRequestDetails getOpRequestDetailsBySessionId(String sessionId)\r
520       throws SessionManagerException {\r
521     DeviceOperationRequestDetails deviceOperationRequestDetails =\r
522         new DeviceOperationRequestDetails();\r
523 \r
524     logger.debug("Fetching Operation request details for session: {}", sessionId);\r
525     SessionDTO session = getSessionBySessionId(sessionId);\r
526     String deviceId = session.getDeviceId();\r
527     TR069DeviceDetails deviceDetails = null;\r
528     try {\r
529       deviceDetails = deviceOperationInterface.getDeviceDetails(deviceId);\r
530       if (session.getCurrentOperationId() == null) {\r
531         logger.debug("There exists no pending operation request for the session: {}", sessionId);\r
532       } else {\r
533         logger.debug("There exists pending operation request for the session: {}", sessionId);\r
534         List<TR069DeviceRPCRequestEntity> tr069DeviceRPCRequestEntityList =\r
535             deviceRPCRequestRepositoryHelper.findByDeviceIdAndOperationId(deviceId,\r
536                 session.getCurrentOperationId());\r
537         if (tr069DeviceRPCRequestEntityList == null) {\r
538           SessionManagerException ex =\r
539               new SessionManagerException(ErrorCode.SESSION_EXPIRED, sessionId);\r
540           logger.error(ex.getMessage());\r
541           throw ex;\r
542         }\r
543         DeviceRPCRequest deviceRPCRequest =\r
544             TR069RequestProcessorUtility.convertToDTO(tr069DeviceRPCRequestEntityList);\r
545         OperationCode opCode = deviceRPCRequest.getOpDetails().getOpCode();\r
546 \r
547         String operationName = null;\r
548 \r
549         if (opCode instanceof TR069OperationCode) {\r
550           operationName = ((TR069OperationCode) opCode).name();\r
551         } else {\r
552           operationName = ((CustomOperationCode) opCode).name();\r
553           TR069OperationDetails tr069OperationDetails =\r
554               (TR069OperationDetails) deviceRPCRequest.getOpDetails();\r
555           opCode = getCustomOperationCode(tr069OperationDetails);\r
556         }\r
557         logger.info("The pending operation request for the session is of operation {}",\r
558             operationName);\r
559         deviceOperationRequestDetails.setOpCode(opCode);\r
560         deviceOperationRequestDetails.setOperationId(deviceRPCRequest.getOperationId());\r
561       }\r
562       deviceOperationRequestDetails.setDeviceDetails(deviceDetails);\r
563     } catch (DeviceOperationException e) {\r
564       SessionManagerException ex =\r
565           new SessionManagerException(ErrorCode.DEVICE_NOT_EXISTS, deviceId);\r
566       logger.error(ex.getMessage());\r
567       throw ex;\r
568     } catch (Exception e) {\r
569       logger.error(e.getMessage());\r
570       SessionManagerException ex =\r
571           new SessionManagerException(ErrorCode.SESSION_EXPIRED, sessionId);\r
572       logger.error(ex.getMessage());\r
573       throw ex;\r
574     }\r
575     return deviceOperationRequestDetails;\r
576   }\r
577 \r
578   /**\r
579    * @param deviceId\r
580    * @return\r
581    * @throws DeviceOperationException\r
582    */\r
583   public TR069DeviceDetails getDeviceDetails(String deviceId) throws DeviceOperationException {\r
584     return deviceOperationInterface.getDeviceDetails(deviceId);\r
585   }\r
586 \r
587   /**\r
588    * @param deviceId\r
589    * @param operationId\r
590    * @return\r
591    * @throws DeviceOperationException\r
592    * @throws SessionConcurrentAccessException\r
593    * @throws InterruptedException\r
594    */\r
595   private SessionDTO acquireSessionLockWithRetryOnFailure(String deviceId, Long operationId)\r
596       throws DeviceOperationException, SessionConcurrentAccessException, InterruptedException {\r
597     int sessionLockAcquireRetryCount = 0;\r
598     SessionDTO sessionDTO = null;\r
599     do {\r
600       try {\r
601         sessionDTO = acquireSessionLock(deviceId, null, false);\r
602         logger.info(\r
603             "Successfully acquired the session lock for processing NBI request with operation ID: {}",\r
604             operationId);\r
605         break;\r
606       } catch (SessionConcurrentAccessException ex) {\r
607         sessionLockAcquireRetryCount++;\r
608         if (sessionLockAcquireRetryCount == 3) {\r
609           logger.error("Failed acquiring the lock after retry, rolling back the transaction");\r
610           throw ex;\r
611         }\r
612         logger.warn(\r
613             "Session lock acquiring failed with SessionConcurrentAccessException, hence retrying");\r
614         Thread.sleep(1000L);\r
615       }\r
616     } while (sessionLockAcquireRetryCount < 3);\r
617 \r
618     return sessionDTO;\r
619   }\r
620 \r
621   /**\r
622    * @param deviceId\r
623    * @param deviceNotification\r
624    * @return\r
625    * @throws DeviceOperationException\r
626    */\r
627   private TR069DeviceDetails getPersistedDeviceDetails(String deviceId,\r
628       DeviceInform deviceNotification) throws DeviceOperationException {\r
629     TR069DeviceDetails deviceDetails = null;\r
630     try {\r
631       deviceDetails = deviceOperationInterface.getDeviceDetails(deviceId);\r
632     } catch (DeviceOperationException doe) {\r
633       if (ErrorCode.DEVICE_NOT_EXISTS.equals(doe.getErrorCode())) {\r
634         logger.info(\r
635             "Creating the device record in TR069_DEVICE_ table, as the device is authenticated successfully.");\r
636         createDevice(deviceNotification.getDeviceDetails());\r
637         deviceDetails = deviceOperationInterface.getDeviceDetails(deviceId);\r
638       }\r
639     }\r
640 \r
641     return deviceDetails;\r
642   }\r
643 \r
644   /**\r
645    * @param deviceDetails\r
646    * @param notificationType\r
647    * @throws TR069EventProcessingException\r
648    */\r
649   private void sendAbortedOperationResultForPendingRPCRequests(DeviceDetails deviceDetails,\r
650       TR069InformType notificationType) throws TR069EventProcessingException {\r
651     String deviceId = deviceDetails.getDeviceId();\r
652     String notificationName = notificationType.name();\r
653     logger.debug(\r
654         "Device Inform event received is {}, hence aborting all the pending operations if any exists",\r
655         notificationName);\r
656 \r
657     List<DeviceRPCRequest> deviceRPCRequestList =\r
658         deviceRPCRequestRepositoryHelper.findAllDeviceRPCRequests(deviceId);\r
659 \r
660     for (DeviceRPCRequest pendingDeviceRPCRequest : deviceRPCRequestList) {\r
661       DeviceRPCResponse deviceOpResult =\r
662           tr069RequestProcessEngineUtility.buildAbortedOperationresult(deviceDetails,\r
663               pendingDeviceRPCRequest, AcsFaultCode.FAULT_CODE_8002);\r
664       String operationName = null;\r
665       if (pendingDeviceRPCRequest.getOpDetails().getOpCode() instanceof CustomOperationCode) {\r
666         CustomOperationCode operationCode =\r
667             (CustomOperationCode) pendingDeviceRPCRequest.getOpDetails().getOpCode();\r
668         operationName = operationCode.name();\r
669       } else {\r
670         TR069OperationCode operationCode =\r
671             (TR069OperationCode) pendingDeviceRPCRequest.getOpDetails().getOpCode();\r
672         operationName = operationCode.name();\r
673       }\r
674       Long operationId = pendingDeviceRPCRequest.getOperationId();\r
675       logger.debug("Aborting the NBI Operation request with operation Id : {} for operation: {}",\r
676           operationId, operationName);\r
677       tr069EventNotificationService.sendOperationResultToNBI(deviceOpResult);\r
678       // Marking the NBI Request as processed\r
679       deviceRPCRequestRepositoryHelper.markDeviceRPCRequestAsProcessed(deviceId, operationId);\r
680       stopDeviceRPCRequestTimer(deviceId, operationId);\r
681     }\r
682   }\r
683 \r
684   /**\r
685    * @param tr069RequestProcessorData\r
686    * @param deviceNotification\r
687    */\r
688   private void updateDeviceDetailsFromInform(TR069RequestProcessorData tr069RequestProcessorData,\r
689       DeviceInform deviceNotification) {\r
690     Boolean isDeviceDataChanged =\r
691         isDeviceUpdateExists(tr069RequestProcessorData, deviceNotification);\r
692     if (isDeviceDataChanged.booleanValue()) {\r
693       updateDeviceDetails(tr069RequestProcessorData, deviceNotification);\r
694       try {\r
695         logger.info(\r
696             "The device data like connection request URL/ Device SW/HW version has changed, hence updating the device details");\r
697         deviceOperationInterface\r
698             .updateDeviceDetails(tr069RequestProcessorData.getTr069DeviceDetails());\r
699       } catch (DeviceOperationException e) {\r
700         logger.error("Updating the device details with the notification details failed, Reason: {}",\r
701             e.getMessage());\r
702         logger.error(e.getMessage());\r
703       }\r
704     }\r
705   }\r
706 \r
707   /**\r
708    * @param deviceId\r
709    * @param operationId\r
710    * @return\r
711    */\r
712   private DeviceRPCRequest getNextRPCRequest(String deviceId, Long operationId) {\r
713     DeviceRPCRequest deviceRPCRequest = null;\r
714     try {\r
715       List<TR069DeviceRPCRequestEntity> entityList =\r
716           deviceRPCRequestRepositoryHelper.findByDeviceIdAndOperationId(deviceId, operationId);\r
717       Integer operationCode = entityList.get(0).getOpCode();\r
718       if (CustomOperationCode.getByOperationCode(operationCode) == null) {\r
719         logger.info("Marking the Device RPC request with operation id - {} as processed.",\r
720             operationId);\r
721         deviceRPCRequestRepositoryHelper.markDeviceRPCRequestAsProcessed(deviceId, operationId);\r
722       }\r
723       logger.debug(PENDING_RPC_CHECK);\r
724       deviceRPCRequest = deviceRPCRequestRepositoryHelper.findOldestDeviceRPCRequest(deviceId);\r
725     } catch (TR069EventProcessingException e) {\r
726       logger.error("An unknown exception occurred while fetching the NBI request, Reason: {}",\r
727           e.getMessage());\r
728     }\r
729 \r
730     return deviceRPCRequest;\r
731   }\r
732 \r
733   /**\r
734    * Creates the device in the DM module if factory imported already\r
735    * \r
736    * @param deviceDetails\r
737    * @throws DeviceOperationException\r
738    */\r
739   private void createDevice(DeviceDetails deviceDetails) throws DeviceOperationException {\r
740     deviceOperationInterface.updateDeviceDetails(deviceDetails);\r
741   }\r
742 }\r