Spawning threads from UI

Hi,
when I began to use Push with Vaadin, I followed this tutorial: https://vaadin.com/book/-/page/advanced.push.html

In the complete example there is a new Thread spawned directly by the UI, but this is discouraged by J2EE standard and it also causes issues with Vaadin methods.
In fact, following this example I made a real worker thread that calls EJB methods (not Thread.sleep(3000) or Math.random() or any other useless stuff) for speeding up UI loading and I’m getting these problems:

  • UI.getCurrent()
    always
    returns null

  • Neither HttpSession and VaadinSession are thread safe
    , so they can be null when invoking methods on them inside threads

  • EJB marked with @RolesAllowed always throw security exceptions
    , because threads are out of any context, so login informations (principal propagation and so on) are completely lost

  • EJB context
    , where I’ve stored some useful information for my application,
    is always empty
    for the same reason described above

I’m getting exceptions everywhere using this approach, because any servlet is NOT thread safe, so I’m asking why an example of the official Vaadin guide suggests this solution?

Vaadin runs in a servlet, so anyone should be warned, not incouraged, about spawning threads inside it.

So , is there any other way to parallelize work without spawning threads inside the UI?
I’m very disappointed of using this approach.

It’s very simple. It doesn’t matter whether you spawn threads your self, use an Executor, or any other mechanism of doing asynchronous work, the same rules apply: it is your responsibility to lock the relevant VaadinSession instance before accessing it. 99.9% of the time this means using the one of the helper methods
UI.access
and
VaadinSession.access
, just like the book examples show. The examples are simple, but totally generalizable to real-world use cases as long as you do it properly.

If you use threadlocals, you must understand how threadlocals work. Vaadin guarantees that the various getCurrent() methods return correct values when 1) handling a client request 2) inside an
access
Runnable. Some of the threadlocals are inheritable and thus available automatically when you spawn a new thread from a thread that already has them set; I’d discourage this usage and strongly recommend always explicitly passing the instances you need to any asynchronous workers.

Regarding EJB, well, Vaadin can’t help you there, you must set up any non-request contexts yourself. I don’t know much about EJB so I’m afraid I can’t give any pointers.

Antlia,

regarding vaadinSession and UI just to point out that once a componente is attached you can go throw aComponent.getUI() to obtain an UI reference. Once you have a UI reference you go through ui.getSession() to get a VaadinSession.

Hi Joannes,

I’ve found this on Servlet 3.0 specs (used by Vaadin for supporting push)
http://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html

Using AsyncContext there is a start method, which
“Causes the container to dispatch a thread, possibly from a managed thread pool, to run the specified Runnable.
The container may propagate appropriate contextual information to the Runnable
.”

So, sorry, but I don’t agree with your assertion: It doesn't matter whether you spawn threads your self, use an Executor, or any other mechanism of doing asynchronous work I’m trying to use AsyncContext approach for calling protected EJBs, i’ll post updates if I’ll manage it to work correctly.

Regards,
Antlia

Hi Omar,

thanks for the suggestion, I’ll try it!

Finally I’ve managed Thread calls to work with EJB marked with security annotations (@RolesAllowed and so on…)

Unfortunately I’ve tried with AsyncContext, but, on Vaadin Servlet there might be some issue, because calling .start method on this object, never actually runs the Runnable.

So, I’ve managed with this solution (It works only for JBoss, because it uses a class of a JBoss package).

  • Created a custom Runnable:

[code]
public abstract class SecurityContextRunnable implements Runnable{

private SecurityContext securityContext;
private Principal currentPrincipal;
private Object credential;

public SecurityContextRunnable(SecurityContext securityContext, Principal principal, Object credential){
this.securityContext = securityContext;
this.currentPrincipal = principal;
this.credential = credential;
}

@Override
public void run(){
//This class is a JBoss class
SecurityContextAssociation.setSecurityContext(securityContext);
SecurityContextAssociation.setPrincipal(currentPrincipal);
SecurityContextAssociation.setCredential(credential);

  //Do work with EJBs protected with security annotations
  doInBackground();

}

//This method must be implemented in all classes inheriting from this runnable
protected abstract void doInBackground();

}
[/code]- When need to call an EJB-secured method asynchronously simply create a new object extending previous class

public class EJBCaller extends SecurityContextRunnable{

  public EJBCaller(SecurityContext securityContext, Principal principal, Object credential){
     super(securityContext, principal, credendial);
  }

  @Override
  protected void doInBackground(){
     //Dirty job here
  }
}
[/code]- And instantiate it with the populated params:[code]
button.addClickListener(new Button.ClickListener() {
    public void buttonClick(ClickEvent event) {
        //Retrieve all values here and pass them to the Runnable
        SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
        Principal principal = SecurityContextAssociation.getPrincipal();
        Object credential = SecurityContextAssociation.getCredential();

        EJBCaller ejbCaller = new EJBCaller(securityContext,principal,credential);
        new Thread(ejbCaller).start();  
    }
});