TransactionListener in Vaadin7

Hi,

in Vaadin 6 I was using a TransactionListener to use a ThreadLocal to hold user specific data. Something like:

public class AppCxt implements TransactionListener, Serializable {
	private Application application;
	private static ThreadLocal<AppCxt> instance = new ThreadLocal<>();

	// user data....

	public ApplicationContext(Application app) {
		this.application = app;
		instance.set(this);
	}

	@Override
	public void transactionStart(Application application, Object transactionData) {
		if (this.application == application) {
			instance.set(this);
		}
	}

	@Override
	public void transactionEnd(Application application, Object transactionData) {
		if (this.application == application) {
			instance.set(null);
		}
	}
}

I tried this with Vaadin 7, but it seems to me that I have to find the correct Root in transactionStart, otherwise the user data is overwritten by another Root (e.g. multi-tab usage).

How would I do this in Vaadin 7?

The can probably use Application.getRootForRequest to find the Root to which the request is targeted.

Another approach is to instead use the ThreadLocal instance of Root that is already provided by Vaadin 7 using Root.getCurrentRoot(). You could then maybe skip the transaction listener altogether. Please observe that Root.getCurrentRoot() will not work from within the transaction listener, as it has not yet been initialized when transactionStart in invoked.

Thanks for your answer.

I already tried these approaches, sorry for not mentioning this in the post.

Concerning Application.getRootForRequest(): how do I get the wrappedRequest Parameter in transactionStart? Is it possible to get it from the transactionData parameter, which seems to be a RequestFacade? I could not find a possibility, if you could show me a way, this would resolve my problems.

Root.getCurrentRoot() would of course be great but it is not initialized yet in the moment I need it. Maybe there is something wrong with my architecture:
I extend the Vaadin LoginForm to set a LoginButtonClickListener which sends a user to authentication and if successful to the main layout. There I would like to use Root.getCurrentRoot() to add all necessary components and this gives me a NPE.
Can this be done in a more appropriate way?

The transactionData parameter should be a WrappedRequest (WrappedHttpServletRequest, WrappedPortletRequest or CombinedRequest depending on the deployment), which is just a facade for the original request.

It seems you are using the TransactionListener just to initialize and clear your own ThreadLocal. This pattern with own ThreadLocal instances is usually not required any more as Vaadin 7 alpha 1 already maintains ThreadLocal instances of both the current Application (Application.getCurrentApplciation()) and the current Root (Root.getCurrentRoot()).

Depending on exactly how you use the ThreadLocal, it might therefore be possible to stop using the TransactionListener and your own ThreadLocal altogether and instead put your custom data in your own subclass of Root, which can then be accessed from “anywhere” (except TransactionListeners and some other special cases) using Root.getCurrentRoot() + a cast to your own Root type.

Thank you for your help.

I made it work using Root.setCurrentRoot() in my subclass of Root and in the login form login handler.
However, multitab works for me only in FF. In IE and Opera I get invalid security key notifications.

And I now realized that I could cast transactionData to HttpServletRequest and get the Root by using application.getRootForRequest(new WrappedHttpServletRequest(HttpServletRequest, DeploymentConfiguration)).
But I would not know how to get DeploymentConfiguration.

Please submit a ticket with details on how to reproduce the issue in our bug tracker at
dev.vaadin.com
.

Why not simply cast transactionData to WrappedRequest in your transactionStart method? I.e. application.getRootForRequest((WrappedRequest) transactionData)

I created ticket #8466 (new defect) - MultiTab usage gives invalid security key error.

Casting transactionData to WrappedRequest gives me a ClassCastException. I work with Tomcat 7.0.25 and jdk 1.7.0_02 (Vaadin 7.0.0.alpha1).

java.lang.ClassCastException: org.apache.catalina.connector.RequestFacade cannot be cast to com.vaadin.terminal.WrappedRequest
at com.teles.vaadin.MyRoot.transactionStart(MyRoot.java:132)
at com.vaadin.terminal.gwt.server.AbstractWebApplicationContext.startTransaction(AbstractWebApplicationContext.java:83)
at com.vaadin.terminal.gwt.server.WebApplicationContext.startTransaction(WebApplicationContext.java:63)
at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:481)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

My bad. I was looking at the current version of the code, which has been slightly refactored since alhpa1 was released. I would suggest trying with the nightly build from
21.01.2012
. It’s the last nightly build before any major changes targeted for alpha2 were included in the master branch. Any nightly build newer than 7.1.2012 should contain the change relevant for your case.

Thank you!