HttpServletRequestListener.onRequestStart and Application.start replacement

Hi,

We are migrating our Vaadin application from Vaadin 6.8.8 to Vaadin 7.0.3. We finally got it to compile (using plenty of
Legacy*
component classes) and now are trying to make it start. One of the problems in getting the application to start is that Vaadin 7 no longer includes
HttpServletRequestListener
. Our implementation of
onRequestStart
method handles quite essential stuff, such as user management.

However, we have not found any good instructions what should be done to get rid of the HttpServletRequestListener, except some year old forum posts which mention Vaadin 7 alpha classes that no longer exist.

Also, old
Application
start method was overridden in our application, and LegacyApplication proves useless in this case since it doesn’t contain this method at all. We need a similar functionality from Vaadin 7.

What are the ways of handling these in Vaadin 7? Has anyone migrated them successfully? We are not yet willing to migrate the application into using UI class etc. since using the Legacy* classes should have had us back in business quickly - although now we already have spent days trying to get it working. :slight_smile:

I also need the feature of HttpServletRequestListener. Does anybody knows how to get the onRequestStart callback with Vaadin 7?

Thanks.

Hi,

Vaadin 7 is embracing the fact that it is a web framework used in a servlet (or portlet) environment. Along the way, we had to remove some abstractions that were needed to get around the limitations in Vaadin 6 that were caused by trying to abstract away the web technologies.

HttpServletRequestListener is generally not needed because you can usually just use a Servlet Filter or override VaadinServlet.service for handling the beginning and end of requests with more flexibility than what HttpServletRequestListener permitted. If you only need to access the request or response objects from inside your UI logic, things can now be made even simpler by using the static helper methods VaadinService.getCurrentRequest() and VaadinService.getCurrentResponse(). We are aware that there might be some very specific use cases where the new stuff is not enough, but we have not yet gathered enough feedback to be sure we know enough to design an API that addresses those needs - feedback is welcome!

Although there are some subtle semantical differences, Application.start() can almost always be replaced with LegacyApplication.init().

The problem is that if you override VaadinServlet.service() you are one your own when it comes to all of the Vaadin UI infrastructure (all the getCurrent() methods for threadlocals on VaadinRequest/VaadinSession/VaadinUI) because you cannot get a callback for a new HTTP request that’s at least had the Vaadin threadlocals setup.

It can be done, but it would be nice to have a hook after the VaadinServlet has had time to setup its core environment.

For what it’s worth, our current subclass of VaadinServlet looks like this as we tried to block access if the user is not yet logged in, as well as setting up our customized messages:


package com.esignforms.open.vaadin;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.esignforms.open.admin.SessionTracker;
import com.esignforms.open.user.User;
import com.esignforms.open.util.ServletUtil;
import com.esignforms.open.vaadin.main.MainView;
import com.vaadin.server.CustomizedSystemMessages;
import com.vaadin.server.SystemMessages;
import com.vaadin.server.SystemMessagesInfo;
import com.vaadin.server.VaadinService;
import com.vaadin.server.SystemMessagesProvider;

/**
 * EsfVaadinServlet is our extension of the standard VaadinServlet so we can intercept HTTP requests.
 * 
 * @author Yozons Inc.
 */
public class EsfVaadinServlet extends com.vaadin.server.VaadinServlet {
	private static final long serialVersionUID = -7870529962822567124L;
	
	@Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession sess = request.getSession(false);
		String localRequestUrl = ServletUtil.getLocalRequestUrl(request);
		
		if ( ! localRequestUrl.contains("/VAADIN/") ) { // allow for themes/widgetset downloads without requiring the user be logged in
			User loggedInUser = sess == null ? null : (User)sess.getAttribute(SessionTracker.USER_SESSION_ATTRIBUTE_NAME);

			if ( loggedInUser == null ) {
				try {
					String redirectUrl = ServletUtil.getExternalUrlContextPath(request)+"/"; // go to main page where login can take place
					response.sendRedirect(redirectUrl);
					return;
				}
				catch(java.io.IOException e) {
					//ignore
				}
			}
		}
		
		if ( sess != null ) { // hack hook so we can call our UI before super.service() sets us up
			EsfVaadinUI vaadinUi = (EsfVaadinUI)sess.getAttribute("EsfVaadinUI");
			if ( vaadinUi != null ) {
				MainView mainView = vaadinUi.getMainView();
				if ( mainView != null ) {
					mainView.updateLastServerCommunications(vaadinUi);
				}
			}
		}

		super.service(request, response);
    }
	
    @Override
    protected void servletInitialized() throws ServletException {
        super.servletInitialized();
        // At least in this method, we have the Vaadin threadlocals set up so we can use
        EsfVaadinUI ui = EsfVaadinUI.getInstance();
		if ( ui != null ) {
			ui.setHttpRequest(VaadinService.getCurrentRequest());
		}

		getService().setSystemMessagesProvider(
        	    new SystemMessagesProvider() {
					private static final long serialVersionUID = 5776072298071825406L;

				@Override 
        	    public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
        	        EsfVaadinUI ui = EsfVaadinUI.getInstance();
        	        return ui == null ? new CustomizedSystemMessages() : ui.getCustomizedSystemMessages();
        	    }
        	   });
    }
	
}

Vaadin 7.1 will provide new way of doing generic request handling with the basic thread local values set up by adding a RequestHandler to VaadinService (during VaadinService init). These request handlers are run with all the standard thread locals except the current UI set up.

Handling a request with the current UI defined requires answering some further questions:

  1. What about requests that are not “UIDL” requests, but still tightly related to a specific UI instance, e.g. file uploads or ConnectorResource serving?
  2. What about using server push and receiving a WebSocket message? This is technically not a HTTP request, although it is basically the same from a semantic point of view.
  3. What about accessing one UI from a HTTP request originally directed to another UI, e.g. when updating the contents of the main UI from a UI opened in a popup window or when broadcasting something between independent UIs?

The answers to these questions generally depend on what you want to achieve.

Finally some comments about your example code:

  • It seems that the login redirect is not directly related to this discussion as it does not really need anything set up by Vaadin?
  • I can’t comment on the part that calls MainView.updateLastServerCommunications as I don’t know the purpose of that method.
  • VaadinService.getCurrentRequest() in servletInitialized seems kind of pointless as the current request will be null at that point since servletInitialized is run before the first request to the servlet is processed.
  • The SystemMessagesProvider code does not seem to be related to this issue?

I presume this is the createServletService() method we can override to create our own VaadinServletService with requestStart() and requestEnd(). I do have that code commented out in our EsfVaadinServlet to give it a try once it’s ready.

Very true. I think we were not entirely sure about all of the Vaadin-specific requests you mentioned, but in our testing we found that since we map Vaadin to the a “/ui/" path from our login page (so we can handle all of our own JSP/servlets/files without going through the VaadinServlet), we were able to allow all "/VAADIN/” requests to just pass through without the login verification and just ensure they are logged in otherwise. It seems this is working.

Well, the login redirect now is using only servlet code because we couldn’t get it to work using just Vaadin APIs.

The MainView.updateLastServerCommunications is a hook we have that shows/monitors the last server communications – and we also happen to show the last communications time in our app’s footer. We’d like this to occur on each HTTP request with Vaadin objects setup, so this code will probably live in the new 7.1 onRequestStart() once it’s ready, and then our login check will probably take place there, too.

You are right that when we found out how to make the SystemMessages override work in Vaadin 7, we slipped in the code to see about the VaadinRequest, but it’s actually test code that we failed to remove as we tried out various options trying to beat it all into submission. We still use it to override SystemMessages, but we’ve removed that dead code thanks to your review pointing out it was still in there!

I was mainly thinking of overriding VaadinServletService.createRequestHandlers() to add your own RequestHandler that would be run before any of the built-in handlers. The problem with overriding requestStart() is that you have no nice way of telling the framework that it should not continue handling the request e.g. if you have already written a redirect to a login page.

All the requests I mention would go through the "/ui/" mapping. There are however also requests going to /ui/ that are not related to any specific UI instance, e.g. heartbeat requests and the request that fetches the bootstrap HTML page.

What would you need Vaadin APIs for in this case? I guess a service-level RequestHandler could be used with Vaadin 7.1, so this should soon be OK as long as you don’t need to find the UI to which the request is directed (if there is one). Another problem is that it would not catch the WebSocket messages that are used when push is enabled.

Once again there’s the problem of locating the right UI if there are multiple UIs in the same session as well as completely missing WebSocket messages. It’s also unclear what to do with e.g. file upload requests - no UI update is included in the response but they are nevertheless requests targeted to a specific UI instance.

The overall challenge how to design a “UI request handling” API when the concept of a request to a UI instance is unambiguous because of e.g. file uploads, WebSocket messages or updates pushed to the browser even thought there isn’t any request. One “solution” that I’m considering is to ignore “requests” and instead fire events when the UI is “accessed” (using the newly introduced UI.access() or UI.accessSynchronously() methods) or when changes might be about to get sent to the browser (i.e. right before starting to write a response or when UI.push is called). Would either concept make sense for you use case?

Thanks, Leif. Once the request handler is ready, we’ll give it a test as you are right that I need to be able to redirect. It sounds like it may solve our needs, though we are more or less solved now by subclassing VaadinServlet.

I believe I’ll have subclass VaadinServlet anyway to install our custom messages (SystemMessagesProvider) at servlet initialization. This does bring up a a question about the right place/time to set system messages begin at servlet initialization, though, should we ever need per-user (localization) versions of those messages. Right now, we just set up URLs, so no per-user localization is required.

I’m not sure about the UI request handling API. I guess I don’t really need anything else, but if it could be used to replace my updating of the UI based on the last server communications, that would be useful, but only if I could get all the UI instances from the session using VaadinSession.getCurrent().getUIs(). I believe I only ever have one UI per session, but I’m not entirely sure if that’s the case.

The RequestHandler changes are already “ready” in the sense that they have been included in Vaadin 7.1.0 beta1 that was released some weeks a go and there are no plans of doing any changes to those parts of the code base before 7.1.0.

Servlet initialization is indeed the right place for setting up a custom SystemMessagesProvider. If you need to provide different messages for different users, that logic can be in your implementation of SystemMessagesProvider.getSystemMessages(SystemMessagesInfo) as that method gets called every time a message is needed.

Iterating VaadinSession.getCurrent().getUIs() should be OK, although you would also need to the same in your UI.init() method as the newly initialized UI is not present in the session’s UI list during the beginning of that request. You can generally not be sure that there will never be more than one UI instance per session as the user might open the same URL in a new browser tab, causing a new UI to be created.

Handling HTTP requests just for adding details about the request in a footer might not be the typical use case so I wouldn’t design a framework API just based on what is needed for that case, although it’s still worth taking into consideration. I assume the exact semantics in border cases are not that important in your case, which means that there shouldn’t be so much difference between using a RequestHandler or any of the other approaches I suggested.

Thanks, Leif. Yes, the latter may not be a typical use case, but I think the information is pretty typically interesting in that session timeouts occur based on your last activity with the server. We actually use some of this via our standard session listening, but you are right that once you have all of this extra data going back and forth unrelated to a user request, we’ll want a way to know about the last “access” that Vaadin will treat as keeping the session alive. As I understand it, the hearbeat essentially will keep a Servlet session open forever as long as the browser is open because it will continue to receive requests, but that Vaadin has it’s own tracking to still end the session if no user activity occurs within the web.xml’s standard session-timeout setting.

Anyway, we are looking at tracking that user activity side since it shows a user their last activity and estimated time before their session will end on them if they don’t keep on working. That’s what we’re trying to do there.

In my case I was using in Vaadin 6 the following code to get LIferay portlet info:

[code]
public void onRequestStart(PortletRequest request, PortletResponse response) {

      if (getUser() == null) {

            try {

                User user = PortalUtil.getUser(request);

                setUser(user);

                ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);

                setScopeGroupId((int) themeDisplay.getScopeGroupId());    

                setUrlPortal(themeDisplay.getPortalURL());

                System.err.println("URL de PORTAL" +themeDisplay.getPortalURL());

                

            }

[/code]As in Vaadin 7.1 onRequestStart(…) is gone , after looking for a alternative, I didn’t find it, but testing I got the following code that works fine in Vaadin 7 to get the same Info, then I post here to show How you can very easy info form Portlet response.
here is the code:

    @Override

    protected void init(VaadinRequest request) {

        

        ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);

.....................
        if (themeDisplay != null) // then you can test also as standalone / no portlet

            {

            setIdLogin(themeDisplay.getUserId());

            setIdEntidad(themeDisplay.getCompanyId());

            setScopeGroupId((int) themeDisplay.getScopeGroupId());

            }

In other words, “init(VaadinRequest request)…” is equivalent to “onRequestStart(PortletRequest request,” and more simple to implement