Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent the same object from being associated to two different sessions in hibernate

Using jsf 1.2, hibernate, richfaces 3.3.0GA and facelets.

I have this code in my backing bean:

public List<Rater> getFreeRaters(){
    GP myGP = (GP) user;
    update(myGP.getContract());
    ArrayList<Rater> raters = new ArrayList<Rater>(myGP.getContract().getRaters());
    ArrayList<Rater> selectedRaters = this.getSelectedRaters();
    raters.removeAll(selectedRaters);
    return raters;

}

and this code for the UI:

<a4j:form id="gradersForm" ajaxSingle="true">
    <rich:listShuttle sourceValue="#{user.gradersTab.freeRaters}" id="gradersTab_listShuttle"
    targetValue="#{user.gradersTab.selectedRaters}" var="rater" listsHeight="150"
        sourceListWidth="130" targetListWidth="130" sourceCaptionLabel="Available Items"
        targetCaptionLabel="Currently Active Items" > 
        <rich:column>
            <h:outputText value="#{rater.username}"></h:outputText>
        </rich:column>
    </rich:listShuttle>         
    <a4j:commandButton value="Save"></a4j:commandButton>

</a4j:form>

This is my session filter:

public class HibernateSessionRequestFilter implements Filter {

private static Log log = LogFactory.getLog(HibernateSessionRequestFilter.class);

private SessionFactory sf;

public void doFilter(ServletRequest request,
                     ServletResponse response,
                     FilterChain chain)
        throws IOException, ServletException {
    HttpServletResponse resp= (HttpServletResponse) response;
    try {
        log.info("Starting a database transaction");
        Session session = sf.getCurrentSession();
        session.beginTransaction();

        // Call the next filter (continue request processing)
        chain.doFilter(request, resp);

        // Commit and cleanup
        log.info("Committing the database transaction");

        session.getTransaction().commit();


    } catch (StaleObjectStateException staleEx) {...

The problem comes when the UI is re-rendered twice or more at the same time through AJAX. Being two different requests, each of them gets a Session, and the object is tried to be attached to both of them at the same time because neither of them had enought time to finish and to do session.close(), so hibernate throws an exception org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions

Any suggestion to prevent this from happening? Thanks.

Update:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-   app_2_5.xsd">
<display-name>eyeprevent</display-name>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/functions.taglib.xml</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>#{user.skin}</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.CONTROL_SKINNING</param-name>
<param-value>enable</param-value>
</context-param>
<filter>
<filter-name>HibernateFilter</filter-name>
<filter-class>com.eyeprevent.util.HibernateSessionRequestFilter</filter-class>
</filter>
<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<url-pattern>/pages/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<url-pattern>/upload/*</url-pattern>
</filter-mapping>

<filter-mapping>

<filter-name>richfaces</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<listener>
<listener-class>com.eyeprevent.util.MySessionListener</listener-class>
</listener>
<servlet>
<display-name>EPConnectServlet</display-name>
<servlet-name>EPConnectServlet</servlet-name>
<servlet-class>com.eyeprevent.servlets.EPConnectServlet</servlet-class>
<init-param>
<param-name>imagePath</param-name>
<param-value>/home/pako/images</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>imageServlet</servlet-name>
<servlet-class>com.eyeprevent.servlets.ImageServlet</servlet-class>
<init-param>
<param-name>imagePath</param-name>
<param-value>/home/pako/images</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>EPConnectServlet</servlet-name>
<url-pattern>/upload/EPConnectServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>imageServlet</servlet-name>
<url-pattern>/image/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>0</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.xhtml</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>pages/login.xhtml</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/pages/error.xhtml</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/pages/unauthorized.xhtml</location>
</error-page>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>
like image 939
pakore Avatar asked Nov 05 '22 16:11

pakore


1 Answers

Apparently using merge instead of update appears to solve the problem...

Remember that merge returns the new updated instance, so you should do

myInstance = (myInstanceClass) Session.merge(myInstance);
like image 123
pakore Avatar answered Nov 11 '22 04:11

pakore