From 3579dcb7654971ecd859896e1bcabad50b0eebd1 Mon Sep 17 00:00:00 2001 From: Abiram070207 Date: Wed, 19 Aug 2026 15:37:57 +0530 Subject: [PATCH] added various fields inside the dropdown --- db/whatsappbot.mv.db | Bin 0 -> 20480 bytes db/whatsappbot.trace.db | 945 ++++++++++++++++++ .../controller/WebhookController.java | 19 +- .../whatsapp/handler/StudentMenuHandler.java | 216 +++- .../com/rit/whatsapp/model/UserState.java | 2 + .../rit/whatsapp/service/ImsApiService.java | 86 +- .../rit/whatsapp/service/SessionService.java | 11 + .../service/WhatsAppMessageService.java | 56 +- .../rit/whatsapp/util/MessageFormatter.java | 428 +++++++- src/main/resources/application.properties | 2 +- 10 files changed, 1685 insertions(+), 80 deletions(-) create mode 100644 db/whatsappbot.mv.db create mode 100644 db/whatsappbot.trace.db diff --git a/db/whatsappbot.mv.db b/db/whatsappbot.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..7a1211befa2f71caac49919635b5dbbef1944465 GIT binary patch literal 20480 zcmeHPPjBPK6(?nT!}b0t5+FVF5=Pn0?l!8*;c)m52(q#y$3kVo0vAyY*#Wk& z&Pw56xKBqeE*-Ps;qIUxwGVr2f;zyew9e(uq(ZANG z`>eculb?3`0Xr!haiKTxYIHC|TNLr>-4Ro#+}oLE3YPtzi#`=q_&-&-`qw&@e2`aO?+hXW6{Ywj>TUsb-D) z1N3++Mm?tKRy-=Utibb$7Au#4e|~3XZVq^AhWZRKMtzDv5iXWI=h4o{mJ{!^UZg4HK zqB4q4dVC`B$%{|^U*yCd)1(|cVV9)T+dXFM+(skYJaNGydEF{pC)TPb*6Q1lvBL8u zT4Jp>BeqpK>K`3K5)XxvqbH@xD0_`^=B#r&_K;Z``2NuW?fa)L3Nsy(gds>A%C8;h zjE=_nItG!7pd`&!lt{<$5<0?41ZxfUjhv1e`hAKcNs^lYx!n3@=5#bTjy&Nh0yhGZ zrVC#RWdKtEEki;8629=A1D-iv3kg?@5ih40*8Y|%W+sY(Dmle22wt+vCaW@k&QlmV zMuuU$M#oP*_ndR8nlXj}%BiX$8Qn}*e0V-O6gUdeKxSG%HVv{nI-)jB@8|~6z)qxx zlJw(t{3-ia_r-kD#3%v*fq+0jARrJB2nYmTY6PbEca}wOjkD-cXj!mvx2}#%k9%57 z#-H9FN8Ez%iMa#dS^MBjYZ5yE;!Qd1ea8bm?-lU>g zO{br>nqPH}&+bG9 z`IC!?tb+H7w+0XFNArJ{7ZxPBFbCH8uKNCFr`}bo?RuqK-(K2iG;6AEXhpSn>o;;- zt8R4aZMCtiw${38eY4T&cGP00QdB#YW>>uzBGWV-Q=_n2dmhp5sVkMvih3{bLlz(_ z&;pwh@FB9$F_|A);8A2@Kz$6WaS$2^dsgVdGHwQlnKm^;o0*~RqkC$lw%TaDr>eL9 zk!n({R9EUXwOd(g*45(r#!|CUEtZRsf}P_1#pnZ7Twhsh)wf$4t4sBEQLV02+LdY- zCh(}z-fFZyzONJVfKR2h(QKAtnR=_*-dgY0YuoFUPN%w7tDh&C2sBnZ+l|_JjTRr= zQQy6_mcX~(Zmh!C>d)$1Ih~W*ZK&Ngit1V`cQ2XGIdD*hadi2hc7F6miVrb&XGG&xlVXApjAdc)s`qDqtPn z#ou24?}Btai%+058Zi!3Tp}!yd96|6wbm!R)=-)XOORPEf9|y=X>=lXCPOSSjZT;v zwpr%2KF7hHi%uZ!wI-UA_gdpDI`Jw+P$r|V7YqU<-v1~v@f}1^xc5H}dq4y!^YLHO z`~Nw3{~t+`{7{m=_z%35|C9lg|E% z9t9>QrbV8YLeG*<`M*73&?Jj3a{8af|5^O10{tjOZ|Npz-|B)+0@c;VOx8eUM zuMGeH!=?GZ{BPx>c}dAQSC#>0U4m-;HBAsoGnXba!19?(aR%5#=F(IO*wgctAbpc> z-_E24S>qku%q*txkExQ@Gx;FmTgfPuG|jHUX?B&7W{W;OyYy-5WtpaV4yd2WT#7fY z33rJLN#;_rrHwO}l0uTX^!YQm3vihB`s+kh#9Rde0)Z<=AmRTh|IYY-?!V~invDo} My=U?F=dD}(Kc$9ULI3~& literal 0 HcmV?d00001 diff --git a/db/whatsappbot.trace.db b/db/whatsappbot.trace.db new file mode 100644 index 0000000..3d9c853 --- /dev/null +++ b/db/whatsappbot.trace.db @@ -0,0 +1,945 @@ +2026-08-19 12:34:41.941878+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.getWarnings(JdbcConnection.java:643) + at com.zaxxer.hikari.pool.HikariProxyConnection.getWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:309) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 12:34:41.947884+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.HikariProxyConnection.clearWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:318) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 12:34:41.948883+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:258) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.closeConnection(DataSourceConnectionProvider.java:162) + at org.hibernate.internal.NonContextualJdbcConnectionAccess.releaseConnection(NonContextualJdbcConnectionAccess.java:85) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:208) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 13:57:02.551061+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.getWarnings(JdbcConnection.java:643) + at com.zaxxer.hikari.pool.HikariProxyConnection.getWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:309) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 13:57:02.554165+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.HikariProxyConnection.clearWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:318) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 13:57:02.555183+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:258) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.closeConnection(DataSourceConnectionProvider.java:162) + at org.hibernate.internal.NonContextualJdbcConnectionAccess.releaseConnection(NonContextualJdbcConnectionAccess.java:85) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:208) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 14:19:01.753151+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.getWarnings(JdbcConnection.java:643) + at com.zaxxer.hikari.pool.HikariProxyConnection.getWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:309) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 14:19:01.757157+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.HikariProxyConnection.clearWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:318) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 14:19:01.758157+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:258) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.closeConnection(DataSourceConnectionProvider.java:162) + at org.hibernate.internal.NonContextualJdbcConnectionAccess.releaseConnection(NonContextualJdbcConnectionAccess.java:85) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:208) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 15:02:12.045641+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.getWarnings(JdbcConnection.java:643) + at com.zaxxer.hikari.pool.HikariProxyConnection.getWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:309) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 15:02:12.050243+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.HikariProxyConnection.clearWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:318) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 15:02:12.051239+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:258) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.closeConnection(DataSourceConnectionProvider.java:162) + at org.hibernate.internal.NonContextualJdbcConnectionAccess.releaseConnection(NonContextualJdbcConnectionAccess.java:85) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:208) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 15:32:55.645600+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.getWarnings(JdbcConnection.java:643) + at com.zaxxer.hikari.pool.HikariProxyConnection.getWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:309) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 15:32:55.648329+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.HikariProxyConnection.clearWarnings(HikariProxyConnection.java) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:318) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:291) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:203) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) +2026-08-19 15:32:55.651330+05:30 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:690) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.message.DbException.get(DbException.java:188) + at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1418) + at org.h2.jdbc.JdbcConnection.clearWarnings(JdbcConnection.java:657) + at com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:258) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.closeConnection(DataSourceConnectionProvider.java:162) + at org.hibernate.internal.NonContextualJdbcConnectionAccess.releaseConnection(NonContextualJdbcConnectionAccess.java:85) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.release(LogicalConnectionManagedImpl.java:208) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) + at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close(LogicalConnectionManagedImpl.java:264) + at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:160) + at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:576) + at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:392) + at org.hibernate.internal.SessionImpl.close(SessionImpl.java:374) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) + at jdk.proxy2/jdk.proxy2.$Proxy109.close(Unknown Source) + at org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:535) + at org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor.afterCompletion(OpenEntityManagerInViewInterceptor.java:112) + at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.afterCompletion(WebRequestHandlerInterceptorAdapter.java:73) + at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:175) + at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1060) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:946) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:480) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:57) + at java.base/java.lang.Thread.run(Thread.java:1447) diff --git a/src/main/java/com/rit/whatsapp/controller/WebhookController.java b/src/main/java/com/rit/whatsapp/controller/WebhookController.java index 11addae..c3bdd10 100644 --- a/src/main/java/com/rit/whatsapp/controller/WebhookController.java +++ b/src/main/java/com/rit/whatsapp/controller/WebhookController.java @@ -155,8 +155,25 @@ public class WebhookController { } private void handleInteractiveListSelection(String phoneNumber, String selectedListId, UserState currentState) { - if (currentState == UserState.MAIN_MENU) { + if (selectedListId.startsWith("student_")) { + // They clicked an option from the main menu studentMenuHandler.handleMenuSelection(phoneNumber, selectedListId); + } else if (selectedListId.startsWith("sem_")) { + // They clicked an option from the semester selection list + if (currentState == UserState.AWAITING_SEMESTER_SELECTION) { + studentMenuHandler.handleSemesterSelection(phoneNumber, selectedListId); + } else { + messageService.sendMessage(phoneNumber, "This menu selection is no longer active."); + studentMenuHandler.sendMainMenu(phoneNumber); + } + } else if (selectedListId.startsWith("receipt_")) { + // They clicked a receipt download option + if (currentState == UserState.AWAITING_RECEIPT_SELECTION) { + studentMenuHandler.handleReceiptSelection(phoneNumber, selectedListId); + } else { + messageService.sendMessage(phoneNumber, "This menu selection is no longer active."); + studentMenuHandler.sendMainMenu(phoneNumber); + } } else { studentMenuHandler.sendMainMenu(phoneNumber); } diff --git a/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java b/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java index d1e7a28..72f25ae 100644 --- a/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java +++ b/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java @@ -36,41 +36,23 @@ public class StudentMenuHandler { public void sendMainMenu(String phoneNumber) { sessionService.setUserState(phoneNumber, UserState.MAIN_MENU); - List> rows = new ArrayList<>(); - rows.add(createRow("student_attendance", "Attendance", "Overall % and Subject-wise")); - rows.add(createRow("student_timetable", "Timetable", "Today's classes and Weekly")); - rows.add(createRow("student_internal_marks", "Internal marks", "CAT 1, CAT 2, Overall")); - rows.add(createRow("student_semester_results", "Semester results", "Latest result and CGPA")); - rows.add(createRow("student_fee_details", "Fee details & receipt", "Fee paid, Pending, Due date")); - rows.add(createRow("student_academic_calendar", "Academic calendar", "Holidays and Important dates")); - rows.add(createRow("student_exam_schedule", "Exam schedule", "Upcoming exams and Hall details")); - rows.add(createRow("student_circulars", "Circulars & Notices", "Department circulars")); - rows.add(createRow("student_raise_grievance", "Raise a grievance \u2B50", "Submit an issue ticket")); - rows.add(createRow("student_contact_department", "Contact department", "Faculty mentor, HOD, etc.")); + String token = sessionService.getImsToken(phoneNumber); + String studentName = "Student"; + if (token != null) { + studentName = sessionService.getStudentName(phoneNumber, token); + } Map interactiveList = WhatsAppMessageBuilder.buildListMessage( "RIT Digital Assistant", - "Welcome to the RITz Student Portal! Please select an option from the menu below.", + "Welcome " + studentName + "! Please select an option from the menu below.", "Student Menu", - rows + getStudentMenuRows() ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); - - // Send a separate Logout button since the list is maxed out at 10 items - List> logoutBtn = new ArrayList<>(); - Map btn = new HashMap<>(); - btn.put("id", "student_logout"); - btn.put("title", "Logout"); - logoutBtn.add(btn); - - Map logoutMessage = WhatsAppMessageBuilder.buildButtonMessage( - "Need to switch accounts?", - logoutBtn - ); - messageService.sendInteractiveMessage(phoneNumber, logoutMessage); } + public void handleMenuSelection(String phoneNumber, String selectedOptionId) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { @@ -81,23 +63,67 @@ public class StudentMenuHandler { switch (selectedOptionId) { case "student_attendance": String rawAttendance = imsApiService.getAttendance(token); - messageService.sendMessage(phoneNumber, MessageFormatter.formatAttendance(rawAttendance)); + String rawLeaves = imsApiService.getLeaves(token); + sendResponseWithMenu(phoneNumber, MessageFormatter.formatAttendanceAndLeaves(rawAttendance, rawLeaves)); break; case "student_timetable": String rawTimetable = imsApiService.getTimetable(token); - messageService.sendMessage(phoneNumber, MessageFormatter.formatTimetable(rawTimetable)); + sendResponseWithMenu(phoneNumber, MessageFormatter.formatTimetable(rawTimetable)); + break; + + case "student_internal_marks": + String rawCatMarks = imsApiService.getCatMarks(token); + String rawAssignmentMarks = imsApiService.getAssignmentMarks(token); + sendResponseWithMenu(phoneNumber, MessageFormatter.formatInternalMarks(rawCatMarks, rawAssignmentMarks)); break; case "student_semester_results": - // Defaulting to semester 1 for now - String rawResults = imsApiService.getResults(token, 1); - messageService.sendMessage(phoneNumber, MessageFormatter.formatResults(rawResults, 1)); + sendSemesterSelection(phoneNumber, token); + break; + + case "student_fee_details": + String rawFees = imsApiService.getFees(token); + String rawExamFees = imsApiService.getExamFees(token); + String bodyText = MessageFormatter.formatFeesAndExamFees(rawFees, rawExamFees); + + List> receiptRows = MessageFormatter.extractReceiptRows(rawExamFees); + + if (!receiptRows.isEmpty()) { + // Max 10 items in a list. Limit to 10 if necessary. + if (receiptRows.size() > 10) receiptRows = receiptRows.subList(0, 10); + + sessionService.setUserState(phoneNumber, UserState.AWAITING_RECEIPT_SELECTION); + + // Meta API interactive list body limit is 1024 characters + if (bodyText.length() > 1024) bodyText = bodyText.substring(0, 1021) + "..."; + + Map listMessage = WhatsAppMessageBuilder.buildListMessage( + "Receipts", bodyText, "Download Receipt", receiptRows + ); + messageService.sendInteractiveMessage(phoneNumber, listMessage); + } else { + sendResponseWithMenu(phoneNumber, bodyText); + } break; case "student_raise_grievance": grievanceHandler.startGrievanceFlow(phoneNumber); break; + + case "student_help_menu": + sendHelpMenu(phoneNumber); + break; + + case "student_logout": + sessionService.logoutUser(phoneNumber); + messageService.sendMessage(phoneNumber, "You have been logged out successfully. Type 'Hi' to log in again."); + break; + + case "student_contact_department": + messageService.sendMessage(phoneNumber, "Contact Department is currently under development. Please check back later!"); + sendMainMenu(phoneNumber); + break; default: messageService.sendMessage(phoneNumber, "You selected an option that is currently under development. Please check back later!"); @@ -107,6 +133,134 @@ public class StudentMenuHandler { } } + public void sendSemesterSelection(String phoneNumber, String token) { + sessionService.setUserState(phoneNumber, UserState.AWAITING_SEMESTER_SELECTION); + + List> rows = new ArrayList<>(); + for (int i = 1; i <= 8; i++) { + rows.add(createRow("sem_" + i, "Semester " + i, "")); + } + + String rawDashboard = imsApiService.getDashboard(token); + String bodyText = MessageFormatter.formatDashboardCgpa(rawDashboard); + + Map interactiveList = WhatsAppMessageBuilder.buildListMessage( + "Semester Results", + bodyText, + "Select Semester", + rows + ); + + messageService.sendInteractiveMessage(phoneNumber, interactiveList); + } + + public void handleSemesterSelection(String phoneNumber, String selectedOptionId) { + String token = sessionService.getImsToken(phoneNumber); + if (token == null) { + messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); + return; + } + + try { + int semester = Integer.parseInt(selectedOptionId.replace("sem_", "")); + byte[] pdfBytes = imsApiService.getResultsPdf(token, semester); + + if (pdfBytes != null) { + String fileName = "Semester_" + semester + "_Results.pdf"; + String mediaId = messageService.uploadMedia(pdfBytes, fileName, "application/pdf"); + + if (mediaId != null) { + messageService.sendDocumentMessage(phoneNumber, mediaId, "Here are your Semester " + semester + " results!", fileName); + // Send menu afterwards + sendResponseWithMenu(phoneNumber, "Select an option from the menu below."); + } else { + sendResponseWithMenu(phoneNumber, "Failed to upload the results document to WhatsApp."); + } + } else { + sendResponseWithMenu(phoneNumber, "Failed to download your results. They may not be published yet."); + } + } catch (Exception e) { + sendResponseWithMenu(phoneNumber, "Invalid semester selected."); + } + + sessionService.resetState(phoneNumber); // Reset state after fetching results + } + + public void handleReceiptSelection(String phoneNumber, String selectedOptionId) { + String token = sessionService.getImsToken(phoneNumber); + if (token == null) { + messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); + return; + } + + try { + String historyId = selectedOptionId.replace("receipt_", ""); + byte[] pdfBytes = imsApiService.getExamFeeReceiptPdf(token, historyId); + + if (pdfBytes != null) { + String fileName = "Receipt_" + historyId + ".pdf"; + String mediaId = messageService.uploadMedia(pdfBytes, fileName, "application/pdf"); + + if (mediaId != null) { + messageService.sendDocumentMessage(phoneNumber, mediaId, "Here is your Exam Fee Receipt!", fileName); + sendResponseWithMenu(phoneNumber, "Select an option from the menu below."); + } else { + sendResponseWithMenu(phoneNumber, "Failed to upload the receipt document to WhatsApp."); + } + } else { + sendResponseWithMenu(phoneNumber, "Failed to download your receipt. It may not be available."); + } + } catch (Exception e) { + sendResponseWithMenu(phoneNumber, "Invalid receipt selected."); + } + + sessionService.resetState(phoneNumber); // Reset state after fetching receipt + } + + private void sendResponseWithMenu(String phoneNumber, String bodyText) { + // Meta API interactive list body limit is 1024 characters + if (bodyText.length() > 1024) { + bodyText = bodyText.substring(0, 1021) + "..."; + } + + Map interactiveList = WhatsAppMessageBuilder.buildListMessage( + null, + bodyText, + "Student Menu", + getStudentMenuRows() + ); + messageService.sendInteractiveMessage(phoneNumber, interactiveList); + } + + public void sendHelpMenu(String phoneNumber) { + List> rows = new ArrayList<>(); + rows.add(createRow("student_contact_department", "Contact department", "Faculty mentor, HOD, etc.")); + rows.add(createRow("student_logout", "Logout", "Sign out of your account")); + + Map interactiveList = WhatsAppMessageBuilder.buildListMessage( + "Help & Settings", + "Please select an option below:", + "Help Menu", + rows + ); + messageService.sendInteractiveMessage(phoneNumber, interactiveList); + } + + private List> getStudentMenuRows() { + List> rows = new ArrayList<>(); + rows.add(createRow("student_attendance", "Attendance", "Overall % and Subject-wise")); + rows.add(createRow("student_timetable", "Timetable", "Today's classes and Weekly")); + rows.add(createRow("student_internal_marks", "Internal marks", "CAT 1, CAT 2, Overall")); + rows.add(createRow("student_semester_results", "Semester results", "Latest result and CGPA")); + rows.add(createRow("student_fee_details", "Fee details & receipt", "Fee paid, Pending, Due date")); + rows.add(createRow("student_academic_calendar", "Academic calendar", "Holidays and Important dates")); + rows.add(createRow("student_exam_schedule", "Exam schedule", "Upcoming exams and Hall details")); + rows.add(createRow("student_circulars", "Circulars & Notices", "Department circulars")); + rows.add(createRow("student_raise_grievance", "Raise a grievance \u2B50", "Submit an issue ticket")); + rows.add(createRow("student_help_menu", "Help & Settings", "Logout, Contact dept, etc.")); + return rows; + } + private Map createRow(String id, String title, String description) { Map row = new HashMap<>(); row.put("id", id); diff --git a/src/main/java/com/rit/whatsapp/model/UserState.java b/src/main/java/com/rit/whatsapp/model/UserState.java index e126e8c..abaaede 100644 --- a/src/main/java/com/rit/whatsapp/model/UserState.java +++ b/src/main/java/com/rit/whatsapp/model/UserState.java @@ -4,6 +4,8 @@ public enum UserState { MAIN_MENU, AWAITING_LOGIN_ID, AWAITING_LOGIN_PASSCODE, + AWAITING_SEMESTER_SELECTION, + AWAITING_RECEIPT_SELECTION, AWAITING_GRIEVANCE_CATEGORY, AWAITING_GRIEVANCE_DESC } diff --git a/src/main/java/com/rit/whatsapp/service/ImsApiService.java b/src/main/java/com/rit/whatsapp/service/ImsApiService.java index 1f093b0..304d890 100644 --- a/src/main/java/com/rit/whatsapp/service/ImsApiService.java +++ b/src/main/java/com/rit/whatsapp/service/ImsApiService.java @@ -69,7 +69,9 @@ public class ImsApiService { try { ResponseEntity response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, request, String.class); if (response.getStatusCode().is2xxSuccessful()) { - return response.getBody(); + String rawJson = response.getBody(); + System.out.println("API Response for " + endpoint + ": " + rawJson); + return rawJson; } } catch (Exception e) { System.err.println("Failed to fetch from IMS API (" + endpoint + "): " + e.getMessage()); @@ -89,6 +91,66 @@ public class ImsApiService { return fetchFromIms("/api/student/results?semester=" + semester, token); } + public byte[] getResultsPdf(String token, int semester) { + String url = BASE_URL + "/api/student/results/download?semester=" + semester; + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(token); + + HttpEntity request = new HttpEntity<>(headers); + + try { + ResponseEntity response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, request, byte[].class); + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); + } + } catch (Exception e) { + System.err.println("Failed to download PDF: " + e.getMessage()); + } + return null; + } + + public String getDashboard(String token) { + return fetchFromIms("/api/student/dashboard", token); + } + + public String getCatMarks(String token) { + return fetchFromIms("/api/student/cat-marks", token); + } + + public String getAssignmentMarks(String token) { + return fetchFromIms("/api/student/assignment-marks", token); + } + + public String getLeaves(String token) { + return fetchFromIms("/api/student/leaves", token); + } + + public String getFees(String token) { + return fetchFromIms("/api/student/fees", token); + } + + public String getExamFees(String token) { + return fetchFromIms("/api/student/exam-fee", token); + } + + public byte[] getExamFeeReceiptPdf(String token, String historyId) { + String url = BASE_URL + "/api/student/exam-fee/receipt?history_id=" + historyId; + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(token); + + HttpEntity request = new HttpEntity<>(headers); + + try { + ResponseEntity response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, request, byte[].class); + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); + } + } catch (Exception e) { + System.err.println("Failed to download Exam Fee receipt PDF: " + e.getMessage()); + } + return null; + } + public void logout(String token) { String url = BASE_URL + "/api/auth/logout"; HttpHeaders headers = new HttpHeaders(); @@ -102,4 +164,26 @@ public class ImsApiService { System.err.println("Failed to logout from IMS API: " + e.getMessage()); } } + + public String getStudentName(String token) { + String rawJson = fetchFromIms("/api/student/profile", token); + if (rawJson == null) return "Student"; + + System.out.println("Profile JSON: " + rawJson); + + try { + JsonNode root = objectMapper.readTree(rawJson); + // Search common fields for the name + if (root.has("data")) { + JsonNode data = root.get("data"); + if (data.has("name")) return data.get("name").asText(); + if (data.has("student_name")) return data.get("student_name").asText(); + } + if (root.has("name")) return root.get("name").asText(); + if (root.has("student_name")) return root.get("student_name").asText(); + } catch (Exception e) { + System.err.println("Failed to parse profile JSON: " + e.getMessage()); + } + return "Student"; + } } diff --git a/src/main/java/com/rit/whatsapp/service/SessionService.java b/src/main/java/com/rit/whatsapp/service/SessionService.java index b0c17ee..4b37408 100644 --- a/src/main/java/com/rit/whatsapp/service/SessionService.java +++ b/src/main/java/com/rit/whatsapp/service/SessionService.java @@ -19,6 +19,7 @@ public class SessionService { // In-memory cache for API session tokens private final Map sessionTokens = new ConcurrentHashMap<>(); private final Map temporaryLoginIds = new ConcurrentHashMap<>(); + private final Map studentNames = new ConcurrentHashMap<>(); private final UserRepository userRepository; private final EncryptionUtils encryptionUtils; @@ -90,9 +91,19 @@ public class SessionService { imsApiService.logout(token); } userRepository.deleteById(phoneNumber); + studentNames.remove(phoneNumber); resetState(phoneNumber); } + public String getStudentName(String phoneNumber, String token) { + if (studentNames.containsKey(phoneNumber)) { + return studentNames.get(phoneNumber); + } + String name = imsApiService.getStudentName(token); + studentNames.put(phoneNumber, name); + return name; + } + public void setTempLoginId(String phoneNumber, String tempId) { temporaryLoginIds.put(phoneNumber, tempId); } diff --git a/src/main/java/com/rit/whatsapp/service/WhatsAppMessageService.java b/src/main/java/com/rit/whatsapp/service/WhatsAppMessageService.java index ae5ae5c..3116017 100644 --- a/src/main/java/com/rit/whatsapp/service/WhatsAppMessageService.java +++ b/src/main/java/com/rit/whatsapp/service/WhatsAppMessageService.java @@ -50,19 +50,69 @@ public class WhatsAppMessageService { } private void executePost(Map payload) { - String url = "https://graph.facebook.com/v19.0/" + phoneNumberId + "/messages"; + String cleanPhoneId = phoneNumberId != null ? phoneNumberId.trim() : ""; + String cleanToken = apiToken != null ? apiToken.trim() : ""; + + String url = "https://graph.facebook.com/v19.0/" + cleanPhoneId + "/messages"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - headers.setBearerAuth(apiToken); + headers.setBearerAuth(cleanToken); HttpEntity> request = new HttpEntity<>(payload, headers); try { ResponseEntity response = restTemplate.postForEntity(url, request, String.class); - System.out.println("Message sent successfully. Response: " + response.getBody()); + System.out.println("Message successfully delivered to WhatsApp."); } catch (Exception e) { System.err.println("Failed to send message: " + e.getMessage()); } } + + public String uploadMedia(byte[] fileData, String fileName, String mimeType) { + String cleanPhoneId = phoneNumberId != null ? phoneNumberId.trim() : ""; + String cleanToken = apiToken != null ? apiToken.trim() : ""; + String url = "https://graph.facebook.com/v19.0/" + cleanPhoneId + "/media"; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.setBearerAuth(cleanToken); + + org.springframework.util.MultiValueMap body = new org.springframework.util.LinkedMultiValueMap<>(); + body.add("messaging_product", "whatsapp"); + body.add("file", new org.springframework.core.io.ByteArrayResource(fileData) { + @Override + public String getFilename() { + return fileName; + } + }); + body.add("type", mimeType); + + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + try { + ResponseEntity response = restTemplate.postForEntity(url, requestEntity, String.class); + com.fasterxml.jackson.databind.JsonNode root = new com.fasterxml.jackson.databind.ObjectMapper().readTree(response.getBody()); + return root.get("id").asText(); + } catch (Exception e) { + System.err.println("Media upload failed: " + e.getMessage()); + return null; + } + } + + public void sendDocumentMessage(String toPhoneNumber, String mediaId, String caption, String filename) { + Map payload = new HashMap<>(); + payload.put("messaging_product", "whatsapp"); + payload.put("to", toPhoneNumber); + payload.put("type", "document"); + + Map doc = new HashMap<>(); + doc.put("id", mediaId); + if (caption != null && !caption.isEmpty()) doc.put("caption", caption); + if (filename != null && !filename.isEmpty()) doc.put("filename", filename); + + payload.put("document", doc); + + executePost(payload); + } } diff --git a/src/main/java/com/rit/whatsapp/util/MessageFormatter.java b/src/main/java/com/rit/whatsapp/util/MessageFormatter.java index 81fd67c..274dd3d 100644 --- a/src/main/java/com/rit/whatsapp/util/MessageFormatter.java +++ b/src/main/java/com/rit/whatsapp/util/MessageFormatter.java @@ -7,39 +7,92 @@ public class MessageFormatter { private static final ObjectMapper mapper = new ObjectMapper(); - public static String formatAttendance(String rawJson) { - if (rawJson == null) return "❌ Failed to retrieve attendance data."; + public static String formatAttendanceAndLeaves(String rawAttendance, String rawLeaves) { + StringBuilder sb = new StringBuilder(); - try { - JsonNode root = mapper.readTree(rawJson); - // Assuming the JSON has an array of subjects or an overall percentage - // Since we don't have the exact schema, this is a best-effort template. - - StringBuilder sb = new StringBuilder(); - sb.append("\ud83d\udcca *Your Attendance Report*\n\n"); - - if (root.has("overall_percentage")) { - sb.append("*Overall Attendance:* ").append(root.get("overall_percentage").asText()).append("% \ud83d\udfe2\n\n"); - } else { - sb.append("*Overall Attendance:* Data unavailable\n\n"); - } - - sb.append("*Subject-wise Breakdown:*\n"); - if (root.has("data") && root.get("data").isArray()) { - for (JsonNode subject : root.get("data")) { - String name = subject.has("course_name") ? subject.get("course_name").asText() : "Unknown"; - String percentage = subject.has("percentage") ? subject.get("percentage").asText() : "0"; - sb.append("- ").append(name).append(": ").append(percentage).append("%\n"); + // --- Parse Attendance --- + sb.append("\ud83d\udcca *Your Attendance Report*\n\n"); + if (rawAttendance == null) { + sb.append("❌ Failed to retrieve attendance data.\n"); + } else { + try { + JsonNode root = mapper.readTree(rawAttendance); + boolean foundData = false; + + if (root.has("data") && root.get("data").isObject() && root.get("data").has("subjects") && root.get("data").get("subjects").isArray()) { + JsonNode subjects = root.get("data").get("subjects"); + int totalConducted = 0; + int totalPresent = 0; + + StringBuilder subjectsBuilder = new StringBuilder(); + for (JsonNode subject : subjects) { + String name = subject.has("name") ? subject.get("name").asText() : "Unknown"; + int percentage = subject.has("percentage") ? subject.get("percentage").asInt() : 0; + + if (subject.has("conducted") && subject.has("present")) { + totalConducted += subject.get("conducted").asInt(); + totalPresent += subject.get("present").asInt(); + } + + String emoji = percentage >= 75 ? "\ud83d\udfe2" : (percentage >= 60 ? "\ud83d\udfe1" : "\ud83d\udd34"); + subjectsBuilder.append("- *").append(name).append("*: ").append(percentage).append("% ").append(emoji).append("\n"); + foundData = true; + } + + if (totalConducted > 0) { + int overallPercentage = (totalPresent * 100) / totalConducted; + String overallEmoji = overallPercentage >= 75 ? "\ud83d\udfe2" : (overallPercentage >= 60 ? "\ud83d\udfe1" : "\ud83d\udd34"); + sb.append("*Overall Attendance:* ").append(overallPercentage).append("% ").append(overallEmoji).append("\n\n"); + } + + sb.append("*Subject-wise Breakdown:*\n"); + sb.append(subjectsBuilder); } - } else { - sb.append("- Details not available in this format.\n"); + + if (!foundData) { + sb.append("Details not available in this format.\n"); + sb.append("\n*DEBUG RAW ATTENDANCE JSON:*\n").append(rawAttendance).append("\n"); + } + } catch (Exception e) { + sb.append("⚠️ Error formatting attendance data.\nRAW JSON: ").append(rawAttendance).append("\n"); } - - sb.append("\n_Keep up the good work!_"); - return sb.toString(); - } catch (Exception e) { - return "⚠️ Error formatting attendance data."; } + + sb.append("\n"); + + // --- Parse Leaves/OD --- + sb.append("🏖️ *Leave / OD History*\n"); + if (rawLeaves == null) { + sb.append("❌ Failed to retrieve leaves data.\n"); + } else { + try { + JsonNode root = mapper.readTree(rawLeaves); + boolean foundData = false; + + // Assuming typical array of objects for leaves + if (root.has("data") && root.get("data").isArray() && root.get("data").size() > 0) { + for (JsonNode leave : root.get("data")) { + String date = leave.has("date") ? leave.get("date").asText() : + (leave.has("from_date") ? leave.get("from_date").asText() : "Unknown"); + String type = leave.has("type") ? leave.get("type").asText() : + (leave.has("leave_type") ? leave.get("leave_type").asText() : "Leave"); + String status = leave.has("status") ? leave.get("status").asText() : "Pending"; + + sb.append("- *").append(date).append("*: ").append(type).append(" (").append(status).append(")\n"); + foundData = true; + } + } + + if (!foundData) { + sb.append("Details not available in this format.\n"); + sb.append("\n*DEBUG RAW LEAVES JSON:*\n").append(rawLeaves).append("\n"); + } + } catch (Exception e) { + sb.append("⚠️ Error formatting leaves data.\nRAW JSON: ").append(rawLeaves).append("\n"); + } + } + + return sb.toString(); } public static String formatTimetable(String rawJson) { @@ -50,21 +103,63 @@ public class MessageFormatter { StringBuilder sb = new StringBuilder(); sb.append("\ud83d\uddd3\ufe0f *Today's Classes*\n\n"); - if (root.has("data") && root.get("data").isArray()) { - for (JsonNode classNode : root.get("data")) { - String time = classNode.has("time") ? classNode.get("time").asText() : "TBA"; - String course = classNode.has("course_name") ? classNode.get("course_name").asText() : "Unknown"; - String room = classNode.has("room") ? classNode.get("room").asText() : "Unknown"; + boolean validFormat = false; + boolean hasClassesToday = false; + + if (root.has("data") && root.get("data").isObject() && root.get("data").has("schedule")) { + validFormat = true; + JsonNode schedule = root.get("data").get("schedule"); + + String today = java.time.LocalDate.now().getDayOfWeek().toString().toLowerCase(); + + if (schedule.has(today)) { + JsonNode todaySchedule = schedule.get(today); - sb.append("*").append(time).append(":* ").append(course).append(" (Room ").append(room).append(")\n"); + if (todaySchedule.isObject() && todaySchedule.size() > 0) { + java.util.Iterator> fields = todaySchedule.fields(); + while (fields.hasNext()) { + java.util.Map.Entry field = fields.next(); + String timeOrPeriod = field.getKey(); + JsonNode details = field.getValue(); + + if (details.isObject()) { + String course = details.has("course_name") ? details.get("course_name").asText() : + (details.has("name") ? details.get("name").asText() : "Unknown"); + String room = details.has("room") ? details.get("room").asText() : ""; + + sb.append("*").append(timeOrPeriod).append(":* ").append(course); + if (!room.isEmpty()) sb.append(" (Room ").append(room).append(")"); + sb.append("\n"); + } else { + sb.append("*").append(timeOrPeriod).append(":* ").append(details.asText()).append("\n"); + } + hasClassesToday = true; + } + } else if (todaySchedule.isArray() && todaySchedule.size() > 0) { + for (JsonNode details : todaySchedule) { + String time = details.has("time") ? details.get("time").asText() : "TBA"; + String course = details.has("course_name") ? details.get("course_name").asText() : "Unknown"; + String room = details.has("room") ? details.get("room").asText() : ""; + + sb.append("*").append(time).append(":* ").append(course); + if (!room.isEmpty()) sb.append(" (Room ").append(room).append(")"); + sb.append("\n"); + hasClassesToday = true; + } + } } - } else { - sb.append("No classes scheduled for today.\n"); } + if (validFormat && !hasClassesToday) { + sb.append("No classes scheduled for today.\n"); + } else if (!validFormat) { + sb.append("Details not available in this format.\n"); + sb.append("\n\n*DEBUG RAW JSON:*\n").append(rawJson); + } + return sb.toString(); } catch (Exception e) { - return "⚠️ Error formatting timetable data."; + return "⚠️ Error formatting timetable data.\nRAW JSON: " + rawJson; } } @@ -77,11 +172,12 @@ public class MessageFormatter { sb.append("\ud83c\udf93 *Semester ").append(semester).append(" Results*\n\n"); boolean passedAll = true; + boolean hasData = false; - if (root.has("data") && root.get("data").isArray()) { + if (root.has("data") && root.get("data").isArray() && root.get("data").size() > 0) { + hasData = true; for (JsonNode courseNode : root.get("data")) { String name = courseNode.has("course_name") ? courseNode.get("course_name").asText() : "Unknown"; - String total = courseNode.has("total_mark") ? courseNode.get("total_mark").asText() : "0"; String grade = courseNode.has("grade") ? courseNode.get("grade").asText() : "N/A"; String result = courseNode.has("result") ? courseNode.get("result").asText() : "N/A"; @@ -89,10 +185,12 @@ public class MessageFormatter { passedAll = false; } - sb.append("*").append(name).append(":* ").append(total).append("/100 (Grade: ").append(grade).append(")\n"); + sb.append("*").append(name).append(":* Grade ").append(grade).append("\n"); } - } else { - sb.append("No results found for this semester.\n"); + } + + if (!hasData) { + return "\ud83c\udf93 *Semester " + semester + " Results*\n\nNil or not yet updated."; } sb.append("\n*Result:* ").append(passedAll ? "PASS \ud83c\udf89" : "Arrears \u26a0\ufe0f"); @@ -101,4 +199,248 @@ public class MessageFormatter { return "⚠️ Error formatting results data."; } } + + public static String formatDashboardCgpa(String rawJson) { + String defaultMsg = "Please select the semester to download your detailed PDF results:"; + if (rawJson == null) return defaultMsg; + + try { + JsonNode root = mapper.readTree(rawJson); + if (root.has("data") && root.get("data").isObject()) { + JsonNode data = root.get("data"); + String cgpa = data.has("cgpa") ? data.get("cgpa").asText() : "N/A"; + String arrears = data.has("arrears") ? data.get("arrears").asText() : "0"; + + StringBuilder sb = new StringBuilder(); + sb.append("\ud83c\udf93 *Your Current CGPA:* ").append(cgpa).append("\n"); + if (!"0".equals(arrears) && !"N/A".equals(arrears)) { + sb.append("\ud83d\udd34 *Active Arrears:* ").append(arrears).append("\n"); + } + sb.append("\n").append(defaultMsg); + return sb.toString(); + } + } catch (Exception e) { + // Ignore parse errors and return default message + } + return defaultMsg; + } + + public static String formatInternalMarks(String rawCatJson, String rawAssignmentJson) { + StringBuilder sb = new StringBuilder(); + sb.append("\ud83d\udcc8 *Internal Marks*\n\n"); + + // --- Parse CAT Marks --- + sb.append("*CAT MARKS:*\n"); + if (rawCatJson == null) { + sb.append("❌ Failed to retrieve CAT marks.\n\n"); + } else { + try { + JsonNode root = mapper.readTree(rawCatJson); + boolean foundData = false; + + JsonNode targetArray = null; + if (root.has("data")) { + if (root.get("data").isArray()) { + targetArray = root.get("data"); + } else if (root.get("data").isObject() && root.get("data").has("subjects") && root.get("data").get("subjects").isArray()) { + targetArray = root.get("data").get("subjects"); + } + } + + if (targetArray != null && targetArray.size() > 0) { + for (JsonNode subject : targetArray) { + String name = subject.has("name") ? subject.get("name").asText() : + (subject.has("course_name") ? subject.get("course_name").asText() : "Unknown"); + + String marks = ""; + if (subject.has("total") && !subject.get("total").asText().isEmpty()) { + marks = subject.get("total").asText(); + if (subject.has("weightage") && !subject.get("weightage").asText().isEmpty()) { + marks += " (" + subject.get("weightage").asText() + " wt)"; + } + } else if (subject.has("marks")) { + marks = subject.get("marks").asText(); + } else { + marks = "N/A"; + } + + sb.append("- *").append(name).append("*: ").append(marks).append("\n"); + foundData = true; + } + } + + if (!foundData) { + sb.append("Details not available in this format.\n"); + sb.append("\n*DEBUG RAW CAT JSON:*\n").append(rawCatJson).append("\n"); + } + } catch (Exception e) { + sb.append("⚠️ Error formatting CAT marks.\nRAW JSON: ").append(rawCatJson).append("\n"); + } + } + + sb.append("\n"); + + // --- Parse Assignment Marks --- + sb.append("*ASSIGNMENT MARKS:*\n"); + if (rawAssignmentJson == null) { + sb.append("❌ Failed to retrieve Assignment marks.\n"); + } else { + try { + JsonNode root = mapper.readTree(rawAssignmentJson); + boolean foundData = false; + + JsonNode targetArray = null; + if (root.has("data")) { + if (root.get("data").isArray()) { + targetArray = root.get("data"); + } else if (root.get("data").isObject() && root.get("data").has("subjects") && root.get("data").get("subjects").isArray()) { + targetArray = root.get("data").get("subjects"); + } + } + + if (targetArray != null && targetArray.size() > 0) { + for (JsonNode subject : targetArray) { + String name = subject.has("name") ? subject.get("name").asText() : + (subject.has("course_name") ? subject.get("course_name").asText() : "Unknown"); + + String marks = ""; + if (subject.has("total") && !subject.get("total").asText().isEmpty()) { + marks = subject.get("total").asText(); + if (subject.has("weightage") && !subject.get("weightage").asText().isEmpty()) { + marks += " (" + subject.get("weightage").asText() + " wt)"; + } + } else if (subject.has("marks")) { + marks = subject.get("marks").asText(); + } else { + marks = "N/A"; + } + + sb.append("- *").append(name).append("*: ").append(marks).append("\n"); + foundData = true; + } + } + + if (!foundData) { + sb.append("Details not available in this format.\n"); + sb.append("\n*DEBUG RAW ASSIGNMENT JSON:*\n").append(rawAssignmentJson).append("\n"); + } + } catch (Exception e) { + sb.append("⚠️ Error formatting Assignment marks.\nRAW JSON: ").append(rawAssignmentJson).append("\n"); + } + } + + return sb.toString(); + } + + public static String formatFeesAndExamFees(String rawFees, String rawExamFees) { + StringBuilder sb = new StringBuilder(); + + // --- Parse Academic Fees --- + sb.append("\ud83d\udcb0 *Academic Dues / Fees*\n\n"); + if (rawFees == null) { + sb.append("❌ Failed to retrieve academic fee details.\n"); + } else { + try { + JsonNode root = mapper.readTree(rawFees); + boolean foundData = false; + + if (root.has("data")) { + JsonNode data = root.get("data"); + if (data.isArray() && data.size() > 0) { + for (JsonNode fee : data) { + String type = fee.has("type") ? fee.get("type").asText() : + (fee.has("description") ? fee.get("description").asText() : "Fee"); + String amount = fee.has("amount") ? fee.get("amount").asText() : "0"; + String status = fee.has("status") ? fee.get("status").asText() : "N/A"; + + sb.append("- *").append(type).append("*: ₹").append(amount).append(" (").append(status).append(")\n"); + foundData = true; + } + } else if (data.isObject()) { + java.util.Iterator> fields = data.fields(); + while (fields.hasNext()) { + java.util.Map.Entry field = fields.next(); + sb.append("- *").append(field.getKey().replace("_", " ")).append("*: ").append(field.getValue().asText()).append("\n"); + foundData = true; + } + } + } + + if (!foundData) { + sb.append("Details not available in this format.\n"); + sb.append("\n*DEBUG RAW FEES JSON:*\n").append(rawFees).append("\n"); + } + } catch (Exception e) { + sb.append("⚠️ Error formatting academic fee data.\nRAW JSON: ").append(rawFees).append("\n"); + } + } + + sb.append("\n"); + + // --- Parse Exam Fees --- + sb.append("📝 *Exam Fees & Payment History*\n"); + if (rawExamFees == null) { + sb.append("❌ Failed to retrieve exam fee details.\n"); + } else { + try { + JsonNode root = mapper.readTree(rawExamFees); + boolean foundData = false; + + if (root.has("data")) { + JsonNode data = root.get("data"); + if (data.isArray() && data.size() > 0) { + for (JsonNode fee : data) { + String semester = fee.has("semester") ? fee.get("semester").asText() : "Unknown Sem"; + String amount = fee.has("amount") ? fee.get("amount").asText() : "0"; + String status = fee.has("status") ? fee.get("status").asText() : "N/A"; + String date = fee.has("date") ? " on " + fee.get("date").asText() : ""; + + sb.append("- *Sem ").append(semester).append("*: ₹").append(amount).append(" (").append(status).append(date).append(")\n"); + foundData = true; + } + } else if (data.isObject()) { + java.util.Iterator> fields = data.fields(); + while (fields.hasNext()) { + java.util.Map.Entry field = fields.next(); + sb.append("- *").append(field.getKey().replace("_", " ")).append("*: ").append(field.getValue().asText()).append("\n"); + foundData = true; + } + } + } + + if (!foundData) { + sb.append("Details not available in this format.\n"); + sb.append("\n*DEBUG RAW EXAM FEES JSON:*\n").append(rawExamFees).append("\n"); + } + } catch (Exception e) { + sb.append("⚠️ Error formatting exam fee data.\nRAW JSON: ").append(rawExamFees).append("\n"); + } + } + + return sb.toString(); + } + + public static java.util.List> extractReceiptRows(String rawExamFees) { + java.util.List> rows = new java.util.ArrayList<>(); + if (rawExamFees == null) return rows; + try { + JsonNode root = mapper.readTree(rawExamFees); + if (root.has("data") && root.get("data").isArray()) { + for (JsonNode fee : root.get("data")) { + if (fee.has("history_id") || fee.has("id")) { + String id = fee.has("history_id") ? fee.get("history_id").asText() : fee.get("id").asText(); + String amount = fee.has("amount") ? fee.get("amount").asText() : ""; + String date = fee.has("date") ? fee.get("date").asText() : ""; + + java.util.Map row = new java.util.HashMap<>(); + row.put("id", "receipt_" + id); + row.put("title", "Receipt " + id); + row.put("description", "₹" + amount + (date.isEmpty() ? "" : " on " + date)); + rows.add(row); + } + } + } + } catch (Exception e) {} + return rows; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f0cc8fd..1de28b1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,7 +5,7 @@ server.port=8080 whatsapp.verify-token=rit_bot_secret_token_123 # WhatsApp Graph API Token (You get this from the Meta developer console) -whatsapp.api-token=EAAc3Wjql00oBSZAZAWjbSjOOoX3dZBPZAb4VHcQqg1oZAYqPQXvd9fpoNb3bOoPeHtR6irmZB5zQtBApBctcS72eMRgIMa0TOqbP9huKHFoeKq3RJVgcLEtMRJGus4yDrSM23YJpkEbolrT2HDIxahm75fI3oetVZC27jmtoqkdTnVEAOO5wbhZAF7ZAg05nMqFWwMBvpd6cf4Regtfljj0ZBCZBfDaUkOSAf4ZC6D7VFU7djl6RY0qfbRRMRuf0F2D9gV7JzF8WZBZBcvepFixU7PAd6SUsCrxQZDZD +whatsapp.api-token=EAAc3Wjql00oBSarFHyUZCOvu1VRj9BZCs5lfZAEAloWHiqCvSFqZAbnQiPZBshUN56ccGFt5iZBcC9g0kZBgmeBjCYs7PXk00QSDwo1fDyZAqHWhYO6ZBdwU8GnwEldCyrwGnGTTSgBLFNEHLtCdbmSeGvCYHgYbXYQDGE7OjFus0XZAz3sVLZAJqdxgUZAh7qHHomuq27VZASuvuUHnZAX5V8EoDv6VZBZBb6LARAGnh3f2shlM4BvkAyr8h5nlTY50ZBs6dINSxHl2bjVRlDUmpsA5SfAG3ctWQ9AZDZD # WhatsApp Phone Number ID (You get this from the Meta developer console) whatsapp.phone-number-id=1236658909534007