Jmix 2.0 SessionListener missing imports

Hi,

I had created below class in jmix 2.0 but getting package error for WebSessionInitializedEvent and WebSessionDestroyedEvent this is working in jmix 1.5 to manually invalidate HttpSession every time VaadinSession is expired. To do this, you need to create a Spring bean and add WebSessionDestroyedEvent EventListener

jmix.ui.httpSessionExpirationTimeoutSec=120
vaadin.servlet.heartbeatInterval=-1
vaadin.servlet.close-idle-sessions=true
main.datasource.hikari.connection-timeout=900000

Added above configuration still session not getting destroyed


import com.vaadin.flow.server.VaadinRequest;
import com.vaadin.flow.server.WrappedHttpSession;
import com.vaadin.flow.server.WrappedSession;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class SessionListener {

    private static final Logger log = org.slf4j.LoggerFactory.getLogger(SessionListener.class);


    @EventListener
    public void onWebSessionInitialized(WebSessionInitializedEvent event) {
        WrappedSession wrappedSession = VaadinRequest.getCurrent().getWrappedSession();
        String sessionId = wrappedSession != null ? wrappedSession.getId() : "";
        log.info("WebSessionInitializedEvent. Session Id: " + sessionId);
    }

    @EventListener
    public void onWebSessionDestroyed(WebSessionDestroyedEvent event) {
        WrappedSession wrappedSession = VaadinRequest.getCurrent().getWrappedSession();
        if (wrappedSession instanceof WrappedHttpSession) {
            HttpSession httpSession = ((WrappedHttpSession) wrappedSession).getHttpSession();
            httpSession.invalidate();
            log.info("Invalidate HttpSession: " + httpSession.getId());
        }

        String sessionId = wrappedSession != null ? wrappedSession.getId() : "";
        log.info("WebSessionInitializedEvent. Session Id: " + sessionId);
    }
}

Hi,

Any Changes need to be done as this is working on jmix 1.5 but the same is not handled again in 2.0

Hi,

In Jmix 2.x it should be something like below:

import com.vaadin.flow.server.*;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ServiceListener implements VaadinServiceInitListener {

    private static final Logger log = LoggerFactory.getLogger(ServiceListener.class);

    @Override
    public void serviceInit(ServiceInitEvent serviceInitEvent) {
        VaadinService vaadinService = serviceInitEvent.getSource();
        vaadinService.addSessionInitListener(this::sessionInit);
        vaadinService.addSessionDestroyListener(this::sessionDestroy);
    }

    private void sessionInit(SessionInitEvent sessionInitEvent) {
        WrappedSession wrappedSession = sessionInitEvent.getSession().getSession();
        String sessionId = wrappedSession != null ? wrappedSession.getId() : "";
        log.info("SessionInitEvent. Session Id: " + sessionId);
    }

    private void sessionDestroy(SessionDestroyEvent sessionDestroyEvent) {
        WrappedSession wrappedSession = sessionDestroyEvent.getSession().getSession();
        if (wrappedSession instanceof WrappedHttpSession) {
            HttpSession httpSession = ((WrappedHttpSession) wrappedSession).getHttpSession();
            httpSession.invalidate();
            log.info("Invalidate HttpSession: " + httpSession.getId());
        }

        String sessionId = wrappedSession != null ? wrappedSession.getId() : "";
        log.info("SessionDestroyEvent. Session Id: " + sessionId);
    }
}

Hi,

I had imports but in jmix 2.0 session getting invalidated but still not getting any communication error popup and session also not getting expired.


java.lang.IllegalStateException: invalidate: Session already invalidated
	at org.apache.catalina.session.StandardSession.invalidate(StandardSession.java:912)
	at org.apache.catalina.session.StandardSessionFacade.invalidate(StandardSessionFacade.java:115)
	at com.company.glosnew.security.SessionListener.sessionDestroy(SessionListener.java:31)
	at com.vaadin.flow.server.VaadinService.lambda$fireSessionDestroy$9c853e43$1(VaadinService.java:624)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at com.vaadin.flow.server.VaadinService.runPendingAccessTasks(VaadinService.java:2024)
	at com.vaadin.flow.server.VaadinSession.unlock(VaadinSession.java:708)
	at com.vaadin.flow.server.VaadinService.ensureAccessQueuePurged(VaadinService.java:1990)
	at com.vaadin.flow.server.VaadinService.accessSession(VaadinService.java:1957)
	at com.vaadin.flow.server.VaadinSession.access(VaadinSession.java:1012)
	at com.vaadin.flow.server.VaadinService.fireSessionDestroy(VaadinService.java:598)
	at com.vaadin.flow.server.VaadinSession.valueUnbound(VaadinSession.java:204)
	at org.apache.catalina.session.StandardSession.removeAttributeInternal(StandardSession.java:1432)
	at org.apache.catalina.session.StandardSession.expire(StandardSession.java:679)
	at org.apache.catalina.session.StandardSession.expire(StandardSession.java:571)
	at org.apache.catalina.session.StandardSession.invalidate(StandardSession.java:916)
	at org.apache.catalina.session.StandardSessionFacade.invalidate(StandardSessionFacade.java:115)
	at org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler.logout(SecurityContextLogoutHandler.java:72)
	at org.springframework.security.web.authentication.logout.CompositeLogoutHandler.logout(CompositeLogoutHandler.java:54)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:117)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:225)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	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.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	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.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:124)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
	at java.base/java.lang.Thread.run(Thread.java:842)

Hi,

As an option, you can try to set the vaadin.servlet.heartbeat-interval to be a little bit higher than the session timeout, for example, 1 minute higher.

Pay attention that setting heartbeat-interval to -1 disabled it, so Vaadin won’t test if session is expired.

Hi @gorelov

I tried this changes but this is not working on production environment on Tomcat but this works on local instance and also on jmix 1.5.

Can you help me sharing some demo project with session configuration so that same we can deploy and check.

Hi @gorelov,

Can you help on this.

Hi,

Same as you I’ve tested on local instance without any errors. If you provide a demo project that reproduces the problem, I’ll try to investigate the issue.

Hi,

below link to download test project with Session configuration.

https://tinyurl.com/444m5sm7

Hi,

Could you please attach project here? My browser ways that the link is insecure

Screenshot 2025-02-10 at 14.44.21

Hi @gorelov

Unable to upload file getting upload error file size is 129 MB.
Kindly click on Keep options to download file as we also get the same option while downloading.

Use the zipProject gradle task that makes archive without the build directory which makes it small.

TestProject.zip (1.1 MB)

You incorrectly set Vaadin properties

Instead of

vaadin.servlet.heartbeat-interval=<value>
vaadin.servlet.close-idle-sessions=true

it should be

vaadin.heartbeat-interval=<value>
vaadin.close-idle-sessions=true

In this case, vaadin.heartbeat-interval=-1 works as expected.

1 Like

Hi @gorelov

Thank you for help, Issue is resolved post modifying Vaadin properties. :grinning: