-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Illegal attempt to associate a collection...(new twist)
PostPosted: Thu Dec 04, 2003 6:05 pm 
Newbie

Joined: Fri Nov 14, 2003 8:54 pm
Posts: 7
Location: Atlanta, GA, U.S.A.
Ok, here's a new twist on a frequently asked question:

Given the following classes:

UserSession - stored in a table called user_sessions, represents an http session.

SessionAction - Every click created by the user generates one of these. A SessionAction has a method setSession(UserSession us); to allow association of actions to sessions.

User - information about a user, this class does have a collection of Role objects associated with it.

Neither of the first two classes have collections.

All 3 classes are persisted to the database via Hibernate.

when I log a SessionAction to the database, I do the following:

Code:
//simplified code; retrieve user object:
User user = getUser(username, password);
UserSession us = (UserSession)httpRequest.getSession().getAttribute("userSession");
us.setUser(user);
//now the user is associated with their session


Then, when they view a page, that action is logged:

Code:
UserSession us = (UserSession)httpRequest.getSession().getAttribute("userSession");
SessionAction action = new SessionAction(pageURL);
//associate the action with its session:
action.setSession(us);


Then, in a DAO proxied by a Stateless Session Bean (try/catch blocks removed for clarity), the following method is called:

Code:
public void log(SessionAction action) {

  Session hibernateSession = factory.openSession();
   hibernateSession.save(action);
   hibernateSession.flush();
   hibernateSession.close();

}


This method sometimes throws the "Illegal attempt to associate a collection with two open sessions" exception when hibernateSession.save() is called and works just fine other times.

For example, after logging in, the user is directed to a frameset with 4 different jsp pages. Each page view causes a call to the above log method, since each page view is logged. When the 4th page loads, the exception is thrown. The whole frameset loading happens fairly quickly, and I'm wondering if errors occur due to transactional issues with JBoss/Tomcat. However, every method in my DAO gets a session from the Hibernate factory and closes it before the method returns, so no sessions are being shared or accidentally left open. I even specified an EJB transactional attribute of "RequiresNew" for every method on that SLSB to ensure each call to "log" would operate within a new transaction.

The code that executes per page load is exactly the same. There is one HTTP request processor that logs each http request and calls the SLSB's log(SessionAction) method.

Note that the UserSession object does reside in memory between hibernate session openings/closings. I don't know that this would be a problem. However, it doesn't have any collections that might cause the above exception message.

However, the UserSession object does have a reference to a User object, which in turn does have a roles collection.

Is this (indirect) collection the one that is giving me problems? If so, how come it doesn't fail every time the log method is called?

Just to see if it would work, in the above log method, I first query for the UserSession in the database (instead of using the one already in memory), and use that instance when calling the SessionAction.setSession(UserSession us); method. This approach executes fine every time.

Unfortunately, this is not an acceptable option for me, because it requires a query and an insert to the db for every action that is logged. There is an awful lot of logging going on and this approach essentially doubles my db performance hit.

Gavin, Max, Christian, or anyone else...can you please explain to me why this would be happening (working some times and not others)? Is this due to transactional/session issues with JBoss/Tomcat? (I am using an older version...jboss-3.0.4_tomcat-4.1.12). Any ideas at all?

Thanks very much,

p

P.S. I'm using Hibernate 2.1 beta 2


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 6:42 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
The error happens because you somehow associate a collection with another session. (I guess you know this)

And if it does not happen always - well then sometimes you do not have associated a collection with another session.

...and yes - it can easily be caused by a "cascade association" of the collection.

(note to next time: please show the stacktrace - it make it possible for us to see in what context it's thrown ;)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 8:05 pm 
Newbie

Joined: Fri Nov 14, 2003 8:54 pm
Posts: 7
Location: Atlanta, GA, U.S.A.
Quote:
The error happens because you somehow associate a collection with another session


How is this possible? The only two objects I'm working with don't have collections.

I never explicitly access the referenced User object in any way (which does have a collection) when attempting to log a SessionAction. I'm just trying to save an instance of the SessionAction class.

There is no direct cascade association with a SessionAction to a User.

Also, if you close the session before the end of every method call, and each method call is in its own transaction, how could you be sharing an instance between two sessions?

Here are my mapping entries for those three classes:

Code:
<!-- ======================================================= -->
<!-- User                                                    -->
<!-- ======================================================= -->
<class name="my.company.model.User" table="users">
                                                                                       
  <key>
    <column name="user_id" sql-type="char(36)"/>
  </key>

  <property name="username" type="string" length="100"
                  not-null="true" unique="true"/>

   <!-- other properties truncated for brevity -->
 
    <set name="roles" table="user_role_maps">
      <key>
        <column name="user_id" sql-type="char(36)"/>
      </key>
      <many-to-many class="my.company.model.Role">
        <column name="role_id" sql-type="char(36)"/>
       </many-to-many>
    </set>

</class> <!-- end User class definition -->

<!-- =============================================================== -->
<!-- UserSession                                                     -->
<!-- =============================================================== -->
<class name="my.company.model.UserSession" table="user_sessions">

        <id name="id" type="my.company.hibernate.UUIDType">
            <column name="session_id" sql-type="char(36)"/>
            <generator class="my.company.hibernate.UUIDGenerator"/>
        </id>

        <many-to-one class="my.company.model.User" name="user">
            <column name="user_id" sql-type="char(36)"/>
        </many-to-one>

        <!-- other properties truncated for brevity -->
</class>

<!-- =============================================================== -->
<!-- SessionAction                                                   -->
<!-- =============================================================== -->
<class name="my.company.model.SessionAction" table="session_actions">
                                                                                                                             
            <key>
                <column name="session_action_id" sql-type="char(36)"/>
            </key>
                                                                                                                             
                                                                                                                             
            <many-to-one class="my.company.model.Session" name="session"
                not-null="true">
                <column name="session_id" sql-type="char(36)" not-null="true"/>
            </many-to-one>

             <!-- other properties truncated -->

</class>


Here is the code that attempts to insert a record in the db. When the commented lines are uncommented, everything works. But I don't want to query for the UserSession object when I already have it in memory...

Code:
public void logSessionAction( SessionAction action )
            throws DataAccessException {
        try {
            net.sf.hibernate.Session hibernateSession = _factory.openSession();
            //String queryStr = "from my.company.model.Session session " +
            //        "where session.id = :id";
            //Query query = hibernateSession.createQuery(queryStr);
            //query.setString("id", action.getSession().getId().toString());
            //Session session = (Session)query.list().get(0);
            //action.setSession(session);
            hibernateSession.save(action);
            hibernateSession.flush();
            hibernateSession.close();
        } catch (HibernateException he) {
            String msg =
              "Hibernate error while trying to log session action";
            log.severe(msg + "[" + he.toString() + "]");
            throw new FailedEISException(msg, he);
        }
    }


And finally, here is the stack trace that occurs when the above lines are commented:

Code:
18:55:55,357 ERROR [STDERR] Dec 4, 2003 6:55:55 PM my.company.session.dao.HibernateUserSessionDAO logSessionAction
SEVERE: Hibernate error while trying to log session action[net.sf.hibernate.HibernateException: Illegal attempt to associate
a collection with two open sessions]
18:55:55,423 ERROR [LogInterceptor] RuntimeException:
my.company.framework.dao.FailedEISException: Hibernate error while trying to log session action
        at my.company.session.dao.HibernateUserSessionDAO.logSessionAction(HibernateUserSessionDAO.java:124)
        at my.company.session.UserSessionFacadeBean.log(UserSessionFacadeBean.java:466)
        at sun.reflect.GeneratedMethodAccessor99.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:324)
        at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:660)
        at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:186)
        at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:77)
        at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:107)
        at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:178)
        at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:60)
        at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:130)
        at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:204)
        at org.jboss.ejb.StatelessSessionContainer.invoke(StatelessSessionContainer.java:313)
        at org.jboss.ejb.Container.invoke(Container.java:712)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:517)
        at org.jboss.invocation.local.LocalInvoker.invoke(LocalInvoker.java:98)
        at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor.java:102)
        at org.jboss.proxy.TransactionInterceptor.invoke(TransactionInterceptor.java:77)
        at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:80)
        at org.jboss.proxy.ejb.StatelessSessionInterceptor.invoke(StatelessSessionInterceptor.java:111)
        at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:76)
        at $Proxy41.log(Unknown Source)
        at my.company.session.UserSessionDelegate.log(UserSessionDelegate.java:399)
        at my.company.web.request.HTTPRequestProcessor.process(HTTPRequestProcessor.java:75)
        at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
        at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:260)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2396)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:170)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:469)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.connector.http.HttpProcessor.process(HttpProcessor.java:1040)
        at org.apache.catalina.connector.http.HttpProcessor.run(HttpProcessor.java:1151)
        at java.lang.Thread.run(Thread.java:536)
Caused by: net.sf.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
        at net.sf.hibernate.collection.PersistentCollection.setCurrentSession(PersistentCollection.java:197)
        at net.sf.hibernate.impl.SessionImpl.removeCollectionsFor(SessionImpl.java:1101)
        at net.sf.hibernate.impl.SessionImpl.removeCollectionsFor(SessionImpl.java:1072)
        at net.sf.hibernate.impl.SessionImpl.doUpdate(SessionImpl.java:1316)
        at net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1231)
        at net.sf.hibernate.engine.Cascades$4.cascade(Cascades.java:105)
        at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:280)
        at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:331)
        at net.sf.hibernate.impl.SessionImpl.doUpdate(SessionImpl.java:1324)
        at net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1231)
        at net.sf.hibernate.engine.Cascades$4.cascade(Cascades.java:105)
        at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:280)
        at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:331)
        at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:728)
        at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:640)
        at my.company.session.dao.HibernateUserSessionDAO.logSessionAction(HibernateUserSessionDAO.java:117)
        ... 58 more


Max (et. al), thank you very much for helping,

P


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 9:45 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
You definitely have cascade enabled. Do you have

Code:
<hibernate-mapping default-cascade="save-update">


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2003 10:01 am 
Newbie

Joined: Fri Nov 14, 2003 8:54 pm
Posts: 7
Location: Atlanta, GA, U.S.A.
It is default-cascade="all", which would of course enable the behavior which is causing my problems. This means the User objects's collection of Roles is not the cause after all...

Its been a while since I edited my cascades in my schema, so that never crossed my mind. Thanks very much for catching it.

Just to get things straight...

The SessionAction, in its many-to-one definition with a Session should set cascade="none" to ensure that when the action is saved/updated, the Session object is not saved/updated. Correct? (Session being an object in my model, not a Hibernate Session ;) ). I'm fairly sure this is what is causing my problem...

This means that the SessionAction is the "parent" object of the association and the (model) Session object is the "child" of the association (although application use implies the opposite).

Right?

P


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.