How to create Servlet?

Hi, I am trying to create a servlet, from that i can regist my sessionDestroy and sessionInit listeners.
I followed the guide in https://vaadin.com/docs/v10/flow/advanced/tutorial-application-lifecycle.html but look like my CustomServlet never called when application start.

Here is my code:

@WebServlet(urlPatterns = "/*", loadOnStartup = 1, name = "myservlet", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false)
public class CustomServlet extends VaadinServlet implements SessionInitListener, SessionDestroyListener {
    static Logger logger = Logger.getLogger(CustomServlet.class.getName());

    @Override
    protected void servletInitialized() throws ServletException {
        super.servletInitialized();
        getService().addSessionInitListener(this);
        getService().addSessionDestroyListener(this);
        
        // don't think the code below will work, i need to set timeout of session.
        // VaadinSession.getCurrent().getSession().setMaxInactiveInterval(5);
    }

    @Override
    public void sessionDestroy(SessionDestroyEvent sessionDestroyEvent) {
        // destroy stuff...
    }

    @Override
    public void sessionInit(SessionInitEvent sessionInitEvent) throws ServiceException {
        // destroy stuff...
    }
}

Also, I am running in Spring boot project. Can you give me an idea to how to fix this?

Thanks.

Hi,

I know this is not answering your question about servlet registration, but an easier way to install session listener is to implement a VaadinServiceInitListener. By default it should be registered through a META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener file, but since you are using running spring you just need to expose your implementation as a bean

    @Component
    private static final class MySessionListener implements SessionInitListener, SessionDestroyListener {

        @Override
        public void sessionDestroy(SessionDestroyEvent sessionDestroyEvent) {
            // destroy stuff...
        }

        @Override
        public void sessionInit(SessionInitEvent sessionInitEvent) throws ServiceException {
            // destroy stuff...
        }

    }

    @Component
    private static class MyVaadinServiceInitListener implements VaadinServiceInitListener {

        private final MySessionListener sessionListener;

        private MyVaadinServiceInitListener(MySessionListener sessionListener) {
            this.sessionListener = sessionListener;
        }

        @Override
        public void serviceInit(ServiceInitEvent event) {
            event.getSource().addSessionInitListener(sessionListener);
            event.getSource().addSessionDestroyListener(sessionListener);
        }
    }

HTH

Marco

Marco Collovati:
Hi,

I know this is not answering your question about servlet registration, but an easier way to install session listener is to implement a VaadinServiceInitListener. By default it should be registered through a META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener file, but since you are using running spring you just need to expose your implementation as a bean

    @Component
    private static final class MySessionListener implements SessionInitListener, SessionDestroyListener {

        @Override
        public void sessionDestroy(SessionDestroyEvent sessionDestroyEvent) {
            // destroy stuff...
        }

        @Override
        public void sessionInit(SessionInitEvent sessionInitEvent) throws ServiceException {
            // destroy stuff...
        }

    }

    @Component
    private static class MyVaadinServiceInitListener implements VaadinServiceInitListener {

        private final MySessionListener sessionListener;

        private MyVaadinServiceInitListener(MySessionListener sessionListener) {
            this.sessionListener = sessionListener;
        }

        @Override
        public void serviceInit(ServiceInitEvent event) {
            event.getSource().addSessionInitListener(sessionListener);
            event.getSource().addSessionDestroyListener(sessionListener);
        }
    }

HTH

Marco

It works as what i needed! I only need to regist these listeners and nothing else, this must be best way to approach!
Thank you Marco!

Hi @Marco Collovati,

Can I ask you for 1 more question? About how to get current UI in sessionDestroy, i want when the user session expire, it will navigate to specific route or show up a notification to let user know that they need to re-login.

Thank you.

Hi,

when the SessionDestroy listener is invoked all UIs are removed already from session, so this seems not the correct place for your use case.

Since you are willing to redirect all UIs on session expiration (correct me if I’m wrong) I would try customizing SystemMessages.sessionExpiredURL; this can be done in the VaadinServiceInitListener.

        @Override
        public void serviceInit(ServiceInitEvent event) {
            event.getSource().addSessionInitListener(sessionListener);
            event.getSource().addSessionDestroyListener(sessionListener);
            event.getSource().setSystemMessagesProvider(systemMessagesInfo -> {
                CustomizedSystemMessages messages = new CustomizedSystemMessages();
                messages.setSessionExpiredURL("logout");
                return messages;
            });

        }

With CustomizedSystemMessages you can also set custom notification messages instead of redirect the user.
Also remember that redirection will happen automatically only if you have @Push enabled,
otherwise a user interaction on the UI may be needed.

I don’t know if this is the best (or correct) way; maybe some Vaadin expert can give some advice.

HTH

Marco

Marco Collovati:
Hi,

when the SessionDestroy listener is invoked all UIs are removed already from session, so this seems not the correct place for your use case.

Since you are willing to redirect all UIs on session expiration (correct me if I’m wrong) I would try customizing SystemMessages.sessionExpiredURL; this can be done in the VaadinServiceInitListener.

        @Override
        public void serviceInit(ServiceInitEvent event) {
            event.getSource().addSessionInitListener(sessionListener);
            event.getSource().addSessionDestroyListener(sessionListener);
            event.getSource().setSystemMessagesProvider(systemMessagesInfo -> {
                CustomizedSystemMessages messages = new CustomizedSystemMessages();
                messages.setSessionExpiredURL("logout");
                return messages;
            });

        }

With CustomizedSystemMessages you can also set custom notification messages instead of redirect the user.
Also remember that redirection will happen automatically only if you have @Push enabled,
otherwise a user interaction on the UI may be needed.

I don’t know if this is the best (or correct) way; maybe some Vaadin expert can give some advice.

HTH

Marco

Yes, i just find out that UI will be remove before my sessionDestroyListener, i made some trick to make it redirect and maybe it’s good for now, thank you for your useful solution!

Thank you,

Phong

There are something kinda weird on sessionInit() or serviceInit(), when my application start up, the sessionInit get called multiple times (around 2 ~ 4 times)

I tried to rewrite code to simple like this:

    @Override
        public void sessionInit(SessionInitEvent sessionInitEvent) throws ServiceException {
            sessionInitEvent.getSession().getSession().setMaxInactiveInterval(15);
            sessionInitEvent.getSession().getSession().setAttribute(Session.LATEST_NOTIFY_COUNT, 0);
            System.out.println("Session Init: ");
            System.out.println(sessionInitEvent.getSession().toString());
        }

and terminal show like this:

Session Init: 
com.vaadin.flow.server.VaadinSession@78666dd7
Session Init: 
com.vaadin.flow.server.VaadinSession@725554ef

This only happen on first time when server start my application, and later (after session destroy) it back to normal, 1 session init at time, but randomly called 2 times at once.

Please, try to check the request path on session init listener ( sessionInitEvent.getRequest().getPathInfo() ).

I did some tests and noticed the listener was called also for a /sw.js request, that is related to PWA.

After clearing site data from Chrome tools, the second call to the listener has gone.

I don’t know if session creation is expected for /sw.js or if it is a bug.

HTH

Marco

Marco Collovati:
Please, try to check the request path on session init listener ( sessionInitEvent.getRequest().getPathInfo() ).

I did some tests and noticed the listener was called also for a /sw.js request, that is related to PWA.

After clearing site data from Chrome tools, the second call to the listener has gone.

I don’t know if session creation is expected for /sw.js or if it is a bug.

HTH

Marco

You are right, there is a request to /sw.js. I don’t know that it does.

Now i add some condition to check request path before set some default values to sessionInit. Evevrything still fine, maybe i need more time to see this behaviour.

Thank you for your help Marco.

Phong