I’m new to Vaadin, my application uses MySQL & Hibernate and I’m writing a data maintenance UI for it using Vaadin 7.
This tutorial :
https://vaadin.com/wiki/-/wiki/Main/Using%20Hibernate%20with%20Vaadin tells me how to implement the session-per-request pattern using addTransactionListener() method to correctly close and open hibernate sessions when a vaadin transaction (ie request) happens.
I’ve downloaded the example mentioned and can get it to work using vaadin 6.
Things have changed a bit in Vaadin 7, and there’s now no addTransactionListener() that I can find.
So the question is: how to implement a session-per-request pattern in Vaadin 7?
I don’t find an equivalent question here (or in StackOverflow), the questions and examples all seem to be Vaadin 6.
To reiterate: MySQL, Hibernate, Vaadin 7, I’m developing in Eclipse Kepler.
In my opinion you shouldn’t call the persistency provider from the UI class anyway (or the application). I would just create a session when I needed one in my business logic.
In Vaadin 7, certain abstractions have been removed and the underlying machinery exposed more than in Vaadin 6; this is by design. Thus, to implement a “request listener”, you can simply write your own VaadinServlet subclass, overriding the service method like this:
public class MyVaadinServlet extends VaadinServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
myTransactionStartStuff();
try {
super.service(req, resp);
} finally {
myTransactionEndStuff();
}
}
}
The problem with this approach is that WebSockets bypass the servlet machinery entirely. In Vaadin 7.2, there will probably be something like “session access listeners” - please refer to
ticket #12256 .
Perhaps the issue is solved there, but the application back end uses Hibernate.
The reason for using the (standard) session-per-request pattern is to keep the user UI in sync with the back-end. A “fire and forget” approach (i.e. the ui assumes the back end works correctly) can lead to problems.
I’ll try this if the Hibernate “standard” solution here:
https://community.jboss.org/wiki/OpenSessionInView doesn’t work. I’ll post here when I’ve completed it (or given up). I found the link to the above
here , on the HbnContainer home page.
use url filtering to catch requests before they reach the vaadin servlet, i.e. create another servlet as a wrapper around the vaadin servlet
in this new servlet handle hibernate sessions and/or transactions, e.g. create a hibernate session per request, put this as an attribute into the request and correctly close the hibernate session after the request is finished
in your vaadin servlet get the current hibernate session from the request: 1) from the request passed into the init() method and 2) (in callbacks e.g. listeners) from VaadinService.getCurrentRequest().
The codeing looks like this:
Change web.xml to filter through a new servlet. Note: I couldn’t get any other url-pattern than /* to work. Perhaps this is a jetty issue.
the new servlet opens and closes the hibernate sessions and/or transactions if you want. Note: if you’re using jta and hibernate the protocoll is a bit different, 1) use getCurrentSession(), 2) flush() and close() are unneccessary. Whatever exception handling you need can be done here too.
public class HibernateSessionRequestFilter implements Filter {
/*
* Intercept the request before it's passed to the functional servlet.
* POST requests cause a Hibernate session to be opened and closed "bracketing" the functional servlet.
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (httpRequest.getMethod() != "POST"){
// Not a POST request, pass it down the chain
chain.doFilter(request, response);
return;
}
Session session = MySingleton.openSession();
// Add the session to the request
request.setAttribute("HibernateSession", session);
// Call the next filter (continue request processing)
chain.doFilter(request, response);
// Flush and close the session
session.flush();
session.close();
}
catch (StaleObjectStateException staleEx) {
...
}
}
use the hibernate session in your vaadin 7 UI
...
// in the init method
protected void init(VaadinRequest request) {
Session session = request.getAttribute("HibernateSession");
...
}
// in any callbacks triggered by listeners etc
protected void saveEditObject(Object object) {
Session session = VaadinService.getCurrentRequest().getAttribute("HibernateSession");
...
session.beginTransaction();
session.update(object);
session.getTransaction().commit();
...
}
And it works.
I’m using Eclipse Kepler, the internal Jetty server and Hibernate 4 over MySQL, on Mac,
Johannes, is it confirmed that Vaadin 7.2 will support this feature? We are trying to port our application to 7, but it uses both server push and a Hbncontainer/session-per-request listener architecture. We’re pretty well stuck if we can’t get both to work.
There is an implementation of this feature in our code review, but the latest comments on it (from yesterday) indicate it might still need some thought. Thus, I wouldn’t promise it for 7.2 - at least I’m pretty sure it won’t be in 7.2.0.beta1 which is very close now.
Henri, thanks for the info. For what it’s worth, our implementation for Vaadin 6.x used ICEPush and HbnContainer. The container code worked through servlet transaction listeners to implement session-per-request. ICEPush required the ICEPushServlet class rather than the VaadinServlet class. The threads involved in the push operation also used Hibernate sessions, but we kept them separate from the Vaadin events, which worked through the transaction listener.
With Vaadin 7, neither the supported @Push mechanism, nor ICEPush, work with the new HbnContainer replacement for transaction listeners, servlet filters.
Our app relies on this capability, so the sooner the better for us.
I’m a beginner with both Vaadin and Hibernate and I have a question, I hope you can help me.
I wanted to avoid the
session-per-transaction anti-pattern so I tried David Wilson solution.
As I am not sure of how it is supposed to work, I placed some log.debug() to try understanding it better.
It appears that each time I open the login page of my app, one session is opened then immediatly flushed and closed. When I try to log in, 2 sessions are opened, one is immediatly closed and the other is closed after the interaction with the database. Then, when the new page is loaded, another cycle of opening/flusing closing happens. This cycle appears on every interaction I made with my app.
Here are my question :
Does’nt all these sessions that are opened and closed will have an impact on the performance ?
It may seems obvious for you, but I somehow fail to understand it.
HIbernate says the SessionFactory is an “expensive” object to create, but that sessions are relatively “cheap” to create.
Each time you make a request (ie get some data from the server) and access the db within that session you create a hibernate session, which is then closed and flushed. This makes sure the db state is correct while the server waits for the next request.
The session that is opened before you even log in is interesting, perhaps you’re already reading something from the database to create the login page?
Apart from that it sounds normal to me, does the performance (that is of the db part of teh application) seem unduly slow?
Thank you for your clarification David.
I have a lot to learn in the same time so I really appreciate when I can have precisions like this.
For the login page I use the LoginForm add-on with embedded images, I do not read anything in my database.
It does not only happened when there is an interaction with the database but also when, for instance, I press a button that changes the view in my navigator, even if I do not load any data from the db.
Actually, coming from some test with the sessionFactory declared only when I needed it, it doesn’t seems slower. I was just worrying about how it can becomes with more interaction with the db, as it is only an early stage of the development.
A little bit off-topic: What kind of container should I use to feed tables with data from Hibernate queries? It seems that hbnContainer require another pattern…
I have also the problem of using session-per-request in vaadin but when I use vaadin portlet in liferay. How should I customize VaadinPortlet for this purpose?
Thanks!
While using the Session per Request approach David mentioned, my problem is that only the first request / response at application startup is managed through the ServletFilter. Any other requests (e.g. Button clicks) do not trigger the ServletFilter#doFilter(…).
Implementation of my ServletFilter is quite the same as Davids.
Is this maybe because of WebSocket communication that bypasses ServletFilters?
Button clicks and action handlers come through the ServletFilter in my Application (I debugged it to check), so perhaps the difference is somewhere else?
If I turn @push off it seems like there is only http communication, hence the ServletFilter works fine. If @push is activated it looks like there is some other kind of communication too that is not detected by the ServletFilter (WebSockets?)
Any news about session per request pattern? I have a vaadin 7 application which uses jpa repositories with hibernate and I ask myself how I can implement hibernate session per request with vaadin. As I can read using a filter is no longer a suitable way as soon as push is used.
Our application is using hibernate filters and as soon as I get a new hibernate session I lose the filters. The filters are set after the user loged in or a view has changed. Unfortunately this is not enough if I get always a new hibernate session for each transaction.
Please can somebody tell me how I can achieve session per request together with JPA Repositories in a vaadin application?
Did you try the solution I posted above? It start “The “standard” hibernate solution works for vaadin 7 as follows:”
That works for me, but I don’t use Hibernate filters.
The Hibernate documentation says “A Hibernate filter is a global, named, parameterized filter that can be enabled or disabled for a particular Hibernate session”.
Since you get a new session per request, it sounds like you’ll have to enable the filter each time you get a session.
Hello David
Thank you for your reply. So far I didn’t try your solution above because of two reasons.
I can read above the following:
The problem with this approach is that WebSockets bypass the servlet machinery entirely. In Vaadin 7.2, there will probably be something like “session access listeners” - please refer to ticket #12256.
So I’m not sure whether all the communication goes through your HibernateSessionRequestFilter or not but I have to be sure.
I’m using jpa repositories and this means I dont’ have to care about the hibernate session. In a vaadin view I just inject a repository and use it like:
@inject
private UserRepository userRepository;
...
...
List<User> users = userRepository.findAll();
Where would I have to place your code:
Session session = VaadinService.getCurrentRequest().getAttribute("HibernateSession");
...
session.beginTransaction();
session.update(object);
session.getTransaction().commit()
Or in other words how can my UserRepository in a vaadin view use the session from the request?