how to intercept every call

Hi all.

In Vaadin 6, my Application class used to implement HttpServletRequestListener, then I would override:
public void onRequestStart(HttpServletRequest request, HttpServletResponse response)
in order to intercept every call made by the client to the server and execute some checks before letting the server take care of the request.

How can I do the same in Vaadin 7?

I see I can make UI implement RequestHandler, but that’s for non-UIDL calls only.

I also tried to make UI implement Component.Listener, then I added
this.setListener(this)
and overrode the componentEvent() method.
But not all events are intercepted (event if the components are set as Immediate).

Is there a safe way to catch every call (both internal and URL ones) before they are processed?

Thanks for your help,
Marco

I
read
that [quote]
TransactionListener, ServletRequestListener and PortletRequestListener have been removed, a tutorial is under work on migration
[/quote].
However, I see no tutorials on the matter
on the linked page
.

Am I missing anything?

Thanks,
Marco

I’m not sure if this is the recommended way (some of the methods are deprecated, for instance), but here is a partial possible answer:

-UIDL calls (Inside your main servlet that extends extends VaadinServlet):


    @Override
    protected VaadinServletService createServletService(DeploymentConfiguration deploymentConfiguration) {
        return new VaadinServletService(this, deploymentConfiguration){
            @Override
            protected AbstractCommunicationManager createCommunicationManager(VaadinSession session) {
                return new CommunicationManager(session){
                    @Override
                    public void handleUidlRequest(VaadinRequest request, VaadinResponse response, Callback callback, UI uI) throws IOException, InvalidUIDLSecurityKeyException, JSONException {
                        //do request init here
                        super.handleUidlRequest(request, response, callback, uI);

-Initial page request:
We only need to do some initialization on each request, not true request interception, so we just use the UI.Init method to handle the request init.

Another approach for getting at the initial page request might be to override handleOtherRequest() (in the same place as handleUidlRequest() above). The “other” request seems to be the initial page request. We haven’t tried that out yet, however.

Thanks Tom, that made the trick!
Actually I forgot I could extend the default VaadinServlet…

Thanks again,

Marco

Hi everybody.

As Tom properly warned, some of the above classes (AbstractCommunicationManager and CommunicationManager, for example) have been removed from 7.1.x. So the above trick does not work anymore.

Is there a new way to circumvent the problem?
I basically need to intercept every call (UIDL and non-UIDL ones) before they are executed, in order to perform some specific security checks.

Thanks very much for your help,
Marco

If you want to intercept every call on a low level, you could also consider using a servlet filter rather than doing this in Vaadin.

The downside of that approach (although it also applies to doing this on a low level in Vaadin) is that you don’t have much Vaadin application specific info available there nor necessarily a very clean way to notify the client that the operation was forbidden.

In Vaadin 7.1, you can override VaadinServletService.createRequestHandlers() instead and append your own RequestHandler to the list returned by super.createRequestHandlers() - the handlers are run in reverse order so your handler is always run first, and can decide whether to let the others run. Note that in 7.1, you must call init() for the created VaadinServletService when you override createServletService().

Hi Henri and thanks for your prompt answer.

Notifying the client is not a priority to me - if anything fails, I may just throw an exception and stop everything.

The point is, I need to check some “external” parameters (i.e.: the remote ip address, the user id, etc.) against some Vaadin ones. So I suppose I need to stay on the Vaadin side, instead of using external tools like a servlet filter.

I’m studying VaadinServletService to see if anything may help me: maybe createRequestHandlers()?

Thanks,
Marco

Johannes, thank you very much for your help, too!

I was able to fix the problem just as you described:


public class AApplicationServlet extends VaadinServlet {

    /* Events */

    protected VaadinServletService createServletService(DeploymentConfiguration deploymentConfiguration) throws ServiceException {
        VaadinServletService vaadinServletService = new VaadinServletService(this, deploymentConfiguration) {

            protected List<RequestHandler> createRequestHandlers() throws ServiceException {
                List<RequestHandler> requestHandlerList = super.createRequestHandlers();
                //
                requestHandlerList.add(new RequestHandler() {

                    public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException {
                        Iterator<UI> uis = session.getUIs().iterator();
                        if (uis.hasNext()) {
                            // YOUR_LOGIC_HERE - throw an exception if any security check fails
                        }
                        //
                        return false;
                    }

                });
                //
                return requestHandlerList;
            }

        };
        //
        vaadinServletService.init();
        //
        return vaadinServletService;
    }

Thank you very much, both of you.
Marco

When using that createServletService scheme:

  1. Can our code use the VaadinResponse object to sendRedirect(), such as to a login page or the like? Will the caller stop further processing if we redirect on the response?

  2. When doing iterating over the session.getUIs(), does the current session need to be locked, or is it already locked when the callbacks occur? I’d hate to lock the session, process the getUIs(), then unlock the session if that then messed up the caller.

We are are looking to use a similar scheme, though we were using the requestStart() and requestEnd() methods to override in our VaadinServletService.

Hi David,

  1. I never tried redirecting, but returning “true” instead of false should stop further processing. In my specific code I didn’t do that, as I was throwing an exception and obviously I didn’t any return value.

  2. Actually, the only reason for me to do that was to get one UI object, which in turn allows me to access the logging mechanism and other stuff. So I don’t know whether you lock it or not.

Sorry for not being more helpful…

Bye,
Marco

Yes, as Marco said, just return true to indicate that you got it, no more handlers should be run.

With plain RequestHandler, you have to do locking yourself. This way, you can keep the lock contention at minimum if you want to do lots of processing in the handler but know you only need to actually hold the lock for a short time. There’s also an abstract helper, SynchronizedRequestHander, that you can extend; it automatically acquires and releases the lock for you.

Not sure what plain RequestHandler is, but what if we’re overriding the method:


public void requestEnd(VaadinRequest request, VaadinResponse response, VaadinSession session)

In our processing of requestEnd, if we get all of the UIs from the session, is the session already locked or do I need to lock it first. I have tried both ways and cannot tell the difference (both seem to work), but don’t know if I must lock/unlock it, or whether it’s a bad idea to lock/unlock it (like maybe I am unlocking but since it’s in requestEnd it just so happens nothing else attempts to update the session).

Ah, sorry, I missed that you were overriding RequestEnd. I meant that if you add custom RequestHandler instances in createRequestHandler(), you have the option of implementing RequestHandler (and handling locking yourself) or extending SynchronizedRequestHandler (and getting locking for free).

The session (if any!) is not locked in requestEnd so you must lock it yourself. Also note that, as I implied, the session parameter passed to requestEnd may be null - this occurs if the session has expired and the request is not supposed to create a new one.