Hi Sajith, Thanks for the suggestions.
Catching Throwable means that you are catching Error as well, and that is > not recommended [1]. The rule of thumb that need to follow when catching > Error is whether we can fully recover from an Error. If the answer is yes, > then its fine to catch Error (catch Throwable), otherwise catching > Exception will be enough. Yes, I am aware of it. My intention was to correct the push notification status at all cost when whatever throwable occurs since we mark it as *COMPLETED* prior to calling notification send method. AFAIU, only notificationStrategy.execute(new NotificationContext(deviceId, > operation)); line is the concern here. Seems like operationMappingDAO. > updateOperationMapping is a DB operation. If so, then my suggestion is to > have 2 try-catch blocks. One for the operationMappingDAO.update > OperationMapping line with catching appropriate DB operation exception > (SQLException). Another one for the notificationStrategy.execute(new > NotificationContext(deviceId, > operation)); catching Throwable. Agree. We'll consider adding two try-catch blocks. Best Regards, ~Rasika On Wed, Jan 24, 2018 at 7:36 AM, SajithAR Ariyarathna <sajit...@wso2.com> wrote: > Hi Rasika, > > Regarding your code snippet: > >> try { >> operationMappingDAO.updateOperationMapping(operationId, enrolmentId, >> org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.COMPLETED); >> notificationStrategy.execute(new NotificationContext(deviceId, >> operation)); >> } catch (Throwable e) { >> log.error("Error occurred while sending push notifications to " + >> deviceId.getType() + " device carrying id '" + >> deviceId + "'", e); >> // Reschedule if push notification failed. >> operationMappingDAO.updateOperationMapping(operationId, enrolmentId, >> org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.SCHEDULED); >> } >> >> Catching Throwable means that you are catching Error as well, and that is > not recommended [1]. The rule of thumb that need to follow when catching > Error is whether we can fully recover from an Error. If the answer is yes, > then its fine to catch Error (catch Throwable), otherwise catching > Exception will be enough. > > AFAIU, only notificationStrategy.execute(new NotificationContext(deviceId, > operation)); line is the concern here. Seems like operationMappingDAO. > updateOperationMapping is a DB operation. If so, then my suggestion is to > have 2 try-catch blocks. One for the operationMappingDAO.update > OperationMapping line with catching appropriate DB operation exception > (SQLException). Another one for the notificationStrategy.execute(new > NotificationContext(deviceId, > operation)); catching Throwable. > > [1] https://stackoverflow.com/a/11018879/1577286 > > Thanks. > > On Tue, Jan 23, 2018 at 8:23 PM, Geeth Munasinghe <ge...@wso2.com> wrote: > >> Hi Charitha/Rasika >> >> >> On Tue, Jan 23, 2018 at 8:17 PM, Rasika Perera <rasi...@wso2.com> wrote: >> >>> Good catch Charitha! As you explained this code might raise unforeseen >>> issues. >>> >>> However; if we are bringing the update operation mapping before the FCM >>> notification; as per [1] status of the push notification will be marked as >>> *COMPLETED* even before executing the notification sending process. And >>> this will cause another issue of an inconsistent state. >>> >>> Most of the time, these notification providers involves calling external >>> 3rd party libraries(eg. MQTT, FCM...etc). Suppose there's a >>> RuntimeException thrown while sending the push notification. Notification >>> status still will be marked as COMPLETED and will not try ever again since >>> it is not tracked with the current try-catch block(it only catches >>> PushNotificationExecutionFailedException). >>> >>> Thus, If we are changing the order as suggested please consider adding a >>> Throwable catch block(since notificationStrategy.execute() calls 3rd party >>> or untrusted libraries); >>> >>> try { >>> operationMappingDAO.updateOperationMapping(operationId, enrolmentId, >>> org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.COMPLETED); >>> notificationStrategy.execute(new NotificationContext(deviceId, >>> operation)); >>> } catch (Throwable e) { >>> log.error("Error occurred while sending push notifications to " + >>> deviceId.getType() + " device carrying id '" + >>> deviceId + "'", e); >>> // Reschedule if push notification failed. >>> operationMappingDAO.updateOperationMapping(operationId, enrolmentId, >>> org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.SCHEDULED); >>> } >>> >>> >> +1 for this approach. >> >>> >>> [1] https://github.com/wso2/carbon-device-mgt/blob/e56fb5f4d >>> e5d8f08af879a39a412ff501cba35fc/components/device-mgt/org.ws >>> o2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/devi >>> ce/mgt/core/operation/mgt/OperationManagerImpl.java#L196 >>> >>> On Tue, Jan 23, 2018 at 7:16 PM, Charitha Goonetilleke < >>> charit...@wso2.com> wrote: >>> >>>> Hi All, >>>> >>>> I have implemented state life cycle to prevent concurrent API call from >>>> agent to pending operations endpoint. However issue is still appearing. I >>>> have tested the same scenario with Update 10 and was able to reproduce the >>>> issue with Update 10 pack also. >>>> >>>> However as I figured out, we are sending FCM notification before >>>> updating operation mapping table[1]. Due to that device received FCM >>>> notification in realtime as same as it is being added to the Operations DB >>>> in the server. So there is chance to a raise condition and as a result, we >>>> are observing above exception. So we might need to send FCM notification >>>> after updating Operation Mapping in order to prevent that. WDYT? >>>> >>>> [1] https://github.com/wso2/carbon-device-mgt/blob/master/co >>>> mponents/device-mgt/org.wso2.carbon.device.mgt.core/src/main >>>> /java/org/wso2/carbon/device/mgt/core/operation/mgt/Operatio >>>> nManagerImpl.java#L195 >>>> >>>> Thanks & Regards, >>>> /charithag >>>> >>>> On Tue, Jan 23, 2018 at 2:34 PM, Charitha Goonetilleke < >>>> charit...@wso2.com> wrote: >>>> >>>>> Hi All, >>>>> >>>>> I was able to figure out the root cause for the issue. As Geeth and >>>>> Rasika pointed out this is happening due to concurrent insert and update >>>>> query executions. The root cause for this is calling pending operations >>>>> endpoint more than once from a single android device at a given time. Due >>>>> to that concurrent insert and update happen in the DB level. Ideally a >>>>> device should not call pending operations endpoint simultaneously. But as >>>>> device may receive multiple FCM notifications within fractions of seconds, >>>>> it is triggering pending operation calls per notification. >>>>> >>>>> So I'm now implementing a state machine to avoid that raise condition. >>>>> >>>>> Thanks & Regards, >>>>> /charithag >>>>> >>>>> On Tue, Jan 23, 2018 at 2:14 PM, Rasika Perera <rasi...@wso2.com> >>>>> wrote: >>>>> >>>>>> Hi All, >>>>>> >>>>>> This error has raised since two threads trying to update the DB with >>>>>> following requirements; >>>>>> >>>>>> Thread #1 >>>>>> waiting to lock PUBLIC.*DM_ENROLMENT_OP_MAPPING* while >>>>>> locking PUBLIC.*DM_OPERATION* (exclusive), PUBLIC. >>>>>> *DM_COMMAND_OPERATION* (exclusive). >>>>>> >>>>>> Thread #2 >>>>>> waiting to lock PUBLIC.DM_OPERATION while >>>>>> locking PUBLIC.*DM_ENROLMENT_OP_MAPPING* (exclusive), PUBLIC. >>>>>> *DM_DEVICE_OPERATION_RESPONSE* (exclusive)."; >>>>>> >>>>>> I noticed we are already using ";LOCK_TIMEOUT=60000" (60sec) H2 DB >>>>>> parameter which would allow sometime to continue the thread and do the DB >>>>>> update. >>>>>> >>>>>> Hence, this might happen when you are holding the debug pointer in >>>>>> updateOperation() method or in a state where device responses burst >>>>>> occurs. >>>>>> However the latter case is very rare on other DBs(other than embedded >>>>>> H2). >>>>>> We can even minimize the chance for a such issue implementing a LOCK for >>>>>> calling updateOperation method(might affect the performance). WDYT? >>>>>> >>>>>> Best Regards, >>>>>> ~Rasika >>>>>> >>>>>> On Tue, Jan 23, 2018 at 12:39 PM, Charitha Goonetilleke < >>>>>> charit...@wso2.com> wrote: >>>>>> >>>>>>> Hi All, >>>>>>> >>>>>>> I have encountered following exception intermittently on IoTS Update >>>>>>> 11, when testing with Android device. >>>>>>> >>>>>>> [2018-01-23 12:19:51,077] [IoT-Core] ERROR - >>>>>>> {org.wso2.carbon.mdm.services.android.services.impl.DeviceManagementServiceImpl} >>>>>>> Issue in retrieving operation management service instance >>>>>>> org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException: >>>>>>> Error occurred while updating the operation: 90 status:COMPLETED >>>>>>> at org.wso2.carbon.device.mgt.core.operation.mgt.OperationManag >>>>>>> erImpl.updateOperation(OperationManagerImpl.java:551) >>>>>>> at org.wso2.carbon.device.mgt.core.service.DeviceManagementProv >>>>>>> iderServiceImpl.updateOperation(DeviceManagementProviderServ >>>>>>> iceImpl.java:1426) >>>>>>> at org.wso2.carbon.mdm.services.android.util.AndroidDeviceUtils >>>>>>> .updateOperation(AndroidDeviceUtils.java:211) >>>>>>> at org.wso2.carbon.mdm.services.android.services.impl.DeviceMan >>>>>>> agementServiceImpl.updateOperations(DeviceManagementServiceI >>>>>>> mpl.java:184) >>>>>>> at org.wso2.carbon.mdm.services.android.services.impl.DeviceMan >>>>>>> agementServiceImpl.getPendingOperations(DeviceManagementServ >>>>>>> iceImpl.java:139) >>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcce >>>>>>> ssorImpl.java:62) >>>>>>> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMe >>>>>>> thodAccessorImpl.java:43) >>>>>>> at java.lang.reflect.Method.invoke(Method.java:498) >>>>>>> at org.apache.cxf.service.invoker.AbstractInvoker.performInvoca >>>>>>> tion(AbstractInvoker.java:188) >>>>>>> at org.apache.cxf.service.invoker.AbstractInvoker.invoke(Abstra >>>>>>> ctInvoker.java:104) >>>>>>> at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:204) >>>>>>> at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:101) >>>>>>> at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(S >>>>>>> erviceInvokerInterceptor.java:58) >>>>>>> at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleM >>>>>>> essage(ServiceInvokerInterceptor.java:94) >>>>>>> at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(Phase >>>>>>> InterceptorChain.java:272) >>>>>>> at org.apache.cxf.transport.ChainInitiationObserver.onMessage(C >>>>>>> hainInitiationObserver.java:121) >>>>>>> at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke >>>>>>> (AbstractHTTPDestination.java:249) >>>>>>> at org.apache.cxf.transport.servlet.ServletController.invokeDes >>>>>>> tination(ServletController.java:248) >>>>>>> at org.apache.cxf.transport.servlet.ServletController.invoke(Se >>>>>>> rvletController.java:222) >>>>>>> at org.apache.cxf.transport.servlet.ServletController.invoke(Se >>>>>>> rvletController.java:153) >>>>>>> at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke( >>>>>>> CXFNonSpringServlet.java:171) >>>>>>> at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleR >>>>>>> equest(AbstractHTTPServlet.java:289) >>>>>>> at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPut(A >>>>>>> bstractHTTPServlet.java:226) >>>>>>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:653) >>>>>>> at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service >>>>>>> (AbstractHTTPServlet.java:265) >>>>>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi >>>>>>> lter(ApplicationFilterChain.java:303) >>>>>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App >>>>>>> licationFilterChain.java:208) >>>>>>> at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilte >>>>>>> r.java:52) >>>>>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi >>>>>>> lter(ApplicationFilterChain.java:241) >>>>>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App >>>>>>> licationFilterChain.java:208) >>>>>>> at org.wso2.carbon.mdm.services.android.util.ApiOriginFilter.do >>>>>>> Filter(ApiOriginFilter.java:33) >>>>>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi >>>>>>> lter(ApplicationFilterChain.java:241) >>>>>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App >>>>>>> licationFilterChain.java:208) >>>>>>> at org.apache.catalina.core.StandardWrapperValve.invoke(Standar >>>>>>> dWrapperValve.java:218) >>>>>>> at org.apache.catalina.core.StandardContextValve.invoke(Standar >>>>>>> dContextValve.java:110) >>>>>>> at org.apache.catalina.authenticator.AuthenticatorBase.invoke(A >>>>>>> uthenticatorBase.java:506) >>>>>>> at org.apache.catalina.core.StandardHostValve.invoke(StandardHo >>>>>>> stValve.java:169) >>>>>>> at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorRepo >>>>>>> rtValve.java:103) >>>>>>> at org.wso2.carbon.tomcat.ext.valves.CompositeValve.continueInv >>>>>>> ocation(CompositeValve.java:99) >>>>>>> at org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve$1.invoke >>>>>>> (CarbonTomcatValve.java:47) >>>>>>> at org.wso2.carbon.webapp.mgt.TenantLazyLoaderValve.invoke(Tena >>>>>>> ntLazyLoaderValve.java:57) >>>>>>> at org.wso2.carbon.webapp.authenticator.framework.WebappAuthent >>>>>>> icationValve.processRequest(WebappAuthenticationValve.java:151) >>>>>>> at org.wso2.carbon.webapp.authenticator.framework.WebappAuthent >>>>>>> icationValve.invoke(WebappAuthenticationValve.java:69) >>>>>>> at org.wso2.carbon.tomcat.ext.valves.TomcatValveContainer.invok >>>>>>> eValves(TomcatValveContainer.java:47) >>>>>>> at org.wso2.carbon.tomcat.ext.valves.CompositeValve.invoke(Comp >>>>>>> ositeValve.java:62) >>>>>>> at org.wso2.carbon.tomcat.ext.valves.CarbonStuckThreadDetection >>>>>>> Valve.invoke(CarbonStuckThreadDetectionValve.java:159) >>>>>>> at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogVa >>>>>>> lve.java:962) >>>>>>> at org.wso2.carbon.tomcat.ext.valves.CarbonContextCreatorValve. >>>>>>> invoke(CarbonContextCreatorValve.java:57) >>>>>>> at org.apache.catalina.core.StandardEngineValve.invoke(Standard >>>>>>> EngineValve.java:116) >>>>>>> at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAd >>>>>>> apter.java:445) >>>>>>> at org.apache.coyote.http11.AbstractHttp11Processor.process(Abs >>>>>>> tractHttp11Processor.java:1115) >>>>>>> at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler >>>>>>> .process(AbstractProtocol.java:637) >>>>>>> at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun >>>>>>> (NioEndpoint.java:1770) >>>>>>> at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(N >>>>>>> ioEndpoint.java:1729) >>>>>>> at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPool >>>>>>> Executor.java:1142) >>>>>>> at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoo >>>>>>> lExecutor.java:617) >>>>>>> at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.r >>>>>>> un(TaskThread.java:61) >>>>>>> at java.lang.Thread.run(Thread.java:745) >>>>>>> Caused by: org.wso2.carbon.device.mgt.cor >>>>>>> e.operation.mgt.dao.OperationManagementDAOException: Error occurred >>>>>>> while inserting operation response >>>>>>> at org.wso2.carbon.device.mgt.core.operation.mgt.dao.impl.Gener >>>>>>> icOperationDAOImpl.addOperationResponse(GenericOperationDAOI >>>>>>> mpl.java:213) >>>>>>> at org.wso2.carbon.device.mgt.core.operation.mgt.OperationManag >>>>>>> erImpl.updateOperation(OperationManagerImpl.java:544) >>>>>>> ... 58 more >>>>>>> Caused by: org.h2.jdbc.JdbcSQLException: Deadlock detected. The >>>>>>> current transaction was rolled back. Details: " >>>>>>> Session #49 (user: WSO2CARBON) on thread pool-54-thread-1 is waiting >>>>>>> to lock PUBLIC.DM_ENROLMENT_OP_MAPPING while locking PUBLIC.DM_OPERATION >>>>>>> (exclusive), PUBLIC.DM_COMMAND_OPERATION (exclusive). >>>>>>> Session #59 (user: WSO2CARBON) on thread http-nio-9443-exec-27 is >>>>>>> waiting to lock PUBLIC.DM_OPERATION while locking >>>>>>> PUBLIC.DM_ENROLMENT_OP_MAPPING (exclusive), >>>>>>> PUBLIC.DM_DEVICE_OPERATION_RESPONSE >>>>>>> (exclusive)."; SQL statement: >>>>>>> INSERT INTO DM_DEVICE_OPERATION_RESPONSE(OPERATION_ID, >>>>>>> ENROLMENT_ID, EN_OP_MAP_ID, OPERATION_RESPONSE, RECEIVED_TIMESTAMP) >>>>>>> VALUES(?, ?, ?, ?, ?) [40001-175] >>>>>>> at org.h2.message.DbException.getJdbcSQLException(DbException.j >>>>>>> ava:332) >>>>>>> at org.h2.message.DbException.get(DbException.java:172) >>>>>>> at org.h2.message.DbException.get(DbException.java:149) >>>>>>> at org.h2.table.RegularTable.doLock(RegularTable.java:504) >>>>>>> at org.h2.table.RegularTable.lock(RegularTable.java:450) >>>>>>> at org.h2.constraint.ConstraintReferential.existsRow(Constraint >>>>>>> Referential.java:375) >>>>>>> at org.h2.constraint.ConstraintReferential.checkRowOwnTable(Con >>>>>>> straintReferential.java:367) >>>>>>> at org.h2.constraint.ConstraintReferential.checkRow(ConstraintR >>>>>>> eferential.java:310) >>>>>>> at org.h2.table.Table.fireConstraints(Table.java:894) >>>>>>> at org.h2.table.Table.fireAfterRow(Table.java:911) >>>>>>> at org.h2.command.dml.Insert.insertRows(Insert.java:162) >>>>>>> at org.h2.command.dml.Insert.update(Insert.java:115) >>>>>>> at org.h2.command.CommandContainer.update(CommandContainer.java:79) >>>>>>> at org.h2.command.Command.executeUpdate(Command.java:253) >>>>>>> at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(Jdbc >>>>>>> PreparedStatement.java:154) >>>>>>> at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPrepared >>>>>>> Statement.java:140) >>>>>>> at org.wso2.carbon.device.mgt.core.operation.mgt.dao.impl.Gener >>>>>>> icOperationDAOImpl.addOperationResponse(GenericOperationDAOI >>>>>>> mpl.java:211) >>>>>>> ... 59 more >>>>>>> >>>>>>> >>>>>>> Thanks & regards, >>>>>>> /charithag >>>>>>> -- >>>>>>> *Charitha Goonetilleke* >>>>>>> Senior Software Engineer >>>>>>> WSO2 Inc.; http://wso2.com >>>>>>> lean.enterprise.middleware >>>>>>> >>>>>>> mobile: +94 77 751 3669 <%2B94777513669> >>>>>>> Twitter:@CharithaWs <https://twitter.com/CharithaWs>, fb: charithag >>>>>>> <https://www.facebook.com/charithag>, linkedin: charithag >>>>>>> <http://www.linkedin.com/in/charithag> >>>>>>> >>>>>>> <http://wso2.com/signature> >>>>>>> >>>>>>> -- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "WSO2 IoT Team Group" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>> send an email to iot-group+unsubscr...@wso2.com. >>>>>>> For more options, visit https://groups.google.com/a/ws >>>>>>> o2.com/d/optout. >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> With Regards, >>>>>> >>>>>> *Rasika Perera* >>>>>> Senior Software Engineer >>>>>> LinkedIn: http://lk.linkedin.com/in/rasika90 >>>>>> >>>>>> <http://wso2.com/signature> >>>>>> >>>>>> WSO2 Inc. www.wso2.com >>>>>> lean.enterprise.middleware >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> *Charitha Goonetilleke* >>>>> Senior Software Engineer >>>>> WSO2 Inc.; http://wso2.com >>>>> lean.enterprise.middleware >>>>> >>>>> mobile: +94 77 751 3669 <%2B94777513669> >>>>> Twitter:@CharithaWs <https://twitter.com/CharithaWs>, fb: charithag >>>>> <https://www.facebook.com/charithag>, linkedin: charithag >>>>> <http://www.linkedin.com/in/charithag> >>>>> >>>>> <http://wso2.com/signature> >>>>> >>>> >>>> >>>> >>>> -- >>>> *Charitha Goonetilleke* >>>> Senior Software Engineer >>>> WSO2 Inc.; http://wso2.com >>>> lean.enterprise.middleware >>>> >>>> mobile: +94 77 751 3669 <%2B94777513669> >>>> Twitter:@CharithaWs <https://twitter.com/CharithaWs>, fb: charithag >>>> <https://www.facebook.com/charithag>, linkedin: charithag >>>> <http://www.linkedin.com/in/charithag> >>>> >>>> <http://wso2.com/signature> >>>> >>> >>> >>> >>> -- >>> With Regards, >>> >>> *Rasika Perera* >>> Senior Software Engineer >>> LinkedIn: http://lk.linkedin.com/in/rasika90 >>> >>> <http://wso2.com/signature> >>> >>> WSO2 Inc. www.wso2.com >>> lean.enterprise.middleware >>> >> >> >> >> -- >> *Geeth Munasinghe* >> *WSO2, Inc. http://wso2.com <http://wso2.com/> * >> *lean.enterprise.middleware.* >> >> email: ge...@wso2.com >> phone:(+94) 777911226 <+94%2077%20791%201226> >> >> <http://wso2.com/signature> >> >> _______________________________________________ >> Dev mailing list >> Dev@wso2.org >> http://wso2.org/cgi-bin/mailman/listinfo/dev >> >> > > > -- > Sajith Janaprasad Ariyarathna > Senior Software Engineer; WSO2, Inc.; http://wso2.com/ > <https://wso2.com/signature> > -- With Regards, *Rasika Perera* Senior Software Engineer LinkedIn: http://lk.linkedin.com/in/rasika90 <http://wso2.com/signature> WSO2 Inc. www.wso2.com lean.enterprise.middleware
_______________________________________________ Dev mailing list Dev@wso2.org http://wso2.org/cgi-bin/mailman/listinfo/dev