[Lift] Re: One further: JPA + JTA + Lift

2008-09-10 Thread Kris Nuttycombe

The principal reason I'm using Hibernate is because the base JPA
unfortunately doesn't provide support for non-standard type
persistence, and so a few of my entities are annotated with @Type in
order to use custom mappings for some of the org.joda.time classes
(the Order object in question being one of them.)

I've now got debug logging working; here is one interesting bit; after
adding a logging check to see whether the EntityManager is open:

  def list(xhtml: NodeSeq) : NodeSeq = {
Log.info(Entity manager is open:  + em.isOpen().toString())
val orders = em.createQuery(FROM
Order).getResultList().asInstanceOf[java.util.List[Order]]

I get:

INFO  lift - Entity manager is open: true
DEBUG impl.SessionImpl - opened session at timestamp: 12209812983
DEBUG ejb.AbstractEntityManagerImpl - Looking for a JTA transaction to join
DEBUG ejb.AbstractEntityManagerImpl - No JTA transaction found

Since there's no JTA transaction found, I'm suspecting that Hibernate
is creating its own session to use for the fetch, and is closing it
afterward. The failure to find a JTA transaction is a bit telling,
though - I wonder if in the standard Glassfish stack, JTA transactions
are established in a servlet filter that's not being used with Lift -
that Lift does request handling too far upstream or something.

DEBUG ast.QueryTranslatorImpl - parse() - HQL: FROM
com.gaiam.gcsi.entities.subscription.Order
DEBUG ast.HqlParser - weakKeywords() : new LT(1) token -
[Order,120 previously: 41,line=1,col=43,possibleID=true]
DEBUG ast.AST - --- HQL AST ---
 \-[QUERY] 'query'
\-[SELECT_FROM] 'SELECT_FROM'
   \-[FROM] 'FROM'
  \-[RANGE] 'RANGE'
 \-[DOT] '.'
+-[DOT] '.'
|  +-[DOT] '.'
|  |  +-[DOT] '.'
|  |  |  +-[DOT] '.'
|  |  |  |  +-[IDENT] 'com'
|  |  |  |  \-[IDENT] 'gaiam'
|  |  |  \-[IDENT] 'gcsi'
|  |  \-[IDENT] 'entities'
|  \-[IDENT] 'subscription'
\-[IDENT] 'Order'

DEBUG ast.ErrorCounter - throwQueryException() : no errors
DEBUG antlr.HqlSqlBaseWalker - select  begin [level=1, statement=select]
DEBUG tree.FromElement - FromClause{level=1} :
com.gaiam.gcsi.entities.subscription.Order (no alias) - order0_
DEBUG antlr.HqlSqlBaseWalker - select : finishing up [level=1, statement=select]
DEBUG ast.HqlSqlWalker - processQuery() :  ( SELECT (
FromClause{level=1} orders order0_ ) )
DEBUG ast.HqlSqlWalker - Derived SELECT clause created.
DEBUG util.JoinProcessor - Using FROM fragment [orders order0_]
DEBUG antlr.HqlSqlBaseWalker - select  end [level=1, statement=select]
DEBUG ast.AST - --- SQL AST ---
 \-[SELECT] QueryNode: 'SELECT'  querySpaces (orders)
+-[SELECT_CLAUSE] SelectClause: '{derived select clause}'
|  +-[SELECT_EXPR] SelectExpressionImpl: 'order0_.id as id506_'
{FromElement{explicit,not a collection join,not a fetch join,fetch
non-lazy 
properties,classAlias=null,role=null,tableName=orders,tableAlias=order0_,origin=null,colums={,className=com.gaiam.gcsi.entities.subscription.Order}}}
|  \-[SQL_TOKEN] SqlFragment: 'order0_.uuid as uuid506_,
order0_.affiliate_id as affiliate5_506_, order0_.order_date as
order3_506_, order0_.payment_source_id as payment6_506_,
order0_.shipping_address_id as shipping7_506_, order0_.source_id as
source8_506_, order0_.state as state506_, order0_.user_id as
user9_506_'
\-[FROM] FromClause: 'FROM' FromClause{level=1,
fromElementCounter=1, fromElements=1, fromElementByClassAlias=[],
fromElementByTableAlias=[order0_], fromElementsByPath=[],
collectionJoinFromElementsByPath=[], impliedElements=[]}
   \-[FROM_FRAGMENT] FromElement: 'orders order0_'
FromElement{explicit,not a collection join,not a fetch join,fetch
non-lazy 
properties,classAlias=null,role=null,tableName=orders,tableAlias=order0_,origin=null,colums={,className=com.gaiam.gcsi.entities.subscription.Order}}
DEBUG ast.ErrorCounter - throwQueryException() : no errors
DEBUG ast.QueryTranslatorImpl - HQL: FROM
com.gaiam.gcsi.entities.subscription.Order
DEBUG ast.QueryTranslatorImpl - SQL: select order0_.id as id506_,
order0_.uuid as uuid506_, order0_.affiliate_id as affiliate5_506_,
order0_.order_date as order3_506_, order0_.payment_source_id as
payment6_506_, order0_.shipping_address_id as shipping7_506_,
order0_.source_id as source8_506_, order0_.state as state506_,
order0_.user_id as user9_506_ from orders order0_
DEBUG ast.ErrorCounter - throwQueryException() : no errors
DEBUG jdbc.AbstractBatcher - about to open PreparedStatement (open
PreparedStatements: 0, globally: 0)
DEBUG jdbc.ConnectionManager - opening JDBC connection
DEBUG hibernate.SQL - select order0_.id as id506_, order0_.uuid as
uuid506_, order0_.affiliate_id as affiliate5_506_, order0_.order_date
as order3_506_, order0_.payment_source_id as payment6_506_,
order0_.shipping_address_id as shipping7_506_, order0_.source_id as
source8_506_, order0_.state as state506_, 

[Lift] Re: One further: JPA + JTA + Lift

2008-09-10 Thread Kris Nuttycombe

That possibility had occurred to me. Perhaps the best thing is just to
create a separate object for the persistence context that defines both
persistence  transaction operations. You'd then have implementations
for both JTA and RESOURCE_LOCAL type persistence units and store that
in the RequestVar instead. The JTA version would ensure that the
transaction is disposed properly since in JTA you don't actually need
to do anything with the EntityManager in the cleanup hook.
ScalaEntityManager could just become a wrapper like ScalaQuery instead
of it being coupled to the whole request lifecycle.

Kris

On Wed, Sep 10, 2008 at 1:09 PM, Derek Chen-Becker
[EMAIL PROTECTED] wrote:
 I'd be a little concerned about possible race conditions. I don't know
 enough about the underlying handling of the RequestVar lifecycle, but I
 wonder if the transaction RequestVar could get tossed before the EM
 RequestVar (which calls closeEM). You might want to make it a pure
 ThreadLocal to avoid running into any strangeness, although I hope there's a
 cleaner way to do all of this.

 Derek


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: One further: JPA + JTA + Lift

2008-09-10 Thread Derek Chen-Becker
Thanks for pointing that out. I usually use JTA-enabled datasources so I
don't muck around with UserTransaction directly that much.

Derek

On Wed, Sep 10, 2008 at 2:23 PM, Martin Ellis [EMAIL PROTECTED] wrote:


 On Wed, Sep 10, 2008 at 4:27 PM, Kris Nuttycombe
 [EMAIL PROTECTED] wrote:
  The only question I have is thread safety - it doesn't seem
  like I should really be using a variable on the singleton to store the
  transaction; should I instead be creating a separate RequestVar to
  hold it?

 It is thread safe to use a singleton - in fact, it's what Sun do in
 the code that accompanies the Java EE Tutorial...

 web/books/src/main/java/com/sun/books/listeners/ContextListener.java:

 public final class ContextListener implements ServletContextListener {
@PersistenceUnit
private EntityManagerFactory emf;
private ServletContext context = null;
@Resource
private UserTransaction utx;

public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();

try {
context.setAttribute(emf, emf);
Globals.UTX = utx;


 ... where Globals is defined as:

 public class Globals {
public static UserTransaction UTX;
 }


 Hence, using val instead of def should be fine.

 The begin() and commit() javadoc on UserTransaction:
 Create a new transaction and associate it with the current thread.
 Complete the transaction associated with the current thread. When
 this method completes, the thread is no longer associated with a
 transaction.

 The transaction is associated with the thread that called begin()
 'internally', so there's no need to associate it with a thread
 manually.

 See also:
 http://java.sun.com/javaee/5/docs/tutorial/doc/bnafo.html

 Martin

 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: One further: JPA + JTA + Lift

2008-09-10 Thread Kris Nuttycombe

Thanks a lot, Martin. That's definitely useful to know, and, wow...
too much magic.

On Wed, Sep 10, 2008 at 2:23 PM, Martin Ellis [EMAIL PROTECTED] wrote:

 On Wed, Sep 10, 2008 at 4:27 PM, Kris Nuttycombe
 [EMAIL PROTECTED] wrote:
 The only question I have is thread safety - it doesn't seem
 like I should really be using a variable on the singleton to store the
 transaction; should I instead be creating a separate RequestVar to
 hold it?

 It is thread safe to use a singleton - in fact, it's what Sun do in
 the code that accompanies the Java EE Tutorial...

 web/books/src/main/java/com/sun/books/listeners/ContextListener.java:

 public final class ContextListener implements ServletContextListener {
@PersistenceUnit
private EntityManagerFactory emf;
private ServletContext context = null;
@Resource
private UserTransaction utx;

public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();

try {
context.setAttribute(emf, emf);
Globals.UTX = utx;


 ... where Globals is defined as:

 public class Globals {
public static UserTransaction UTX;
 }


 Hence, using val instead of def should be fine.

 The begin() and commit() javadoc on UserTransaction:
 Create a new transaction and associate it with the current thread.
 Complete the transaction associated with the current thread. When
 this method completes, the thread is no longer associated with a
 transaction.

 The transaction is associated with the thread that called begin()
 'internally', so there's no need to associate it with a thread
 manually.

 See also:
 http://java.sun.com/javaee/5/docs/tutorial/doc/bnafo.html

 Martin

 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: One further: JPA + JTA + Lift

2008-09-09 Thread Oliver Lambert
Now, now lets not get testi ;-)

On 09/09/2008, at 9:34 PM, Viktor Klang wrote:



 On Tue, Sep 9, 2008 at 10:09 AM, Oliver [EMAIL PROTECTED] wrote:
 Actually, is this the essence of the cookie. Why has the object been  
 detached in the example Kris gives - is there something wrong with  
 RequestVar lifecycle?

 Actually, just add a simple debug-print when the session is created  
 and when it's closed. And if it prints that it is closed _before_  
 the execption is raised then there certainly is a problem with the  
 requestvar lifecycle.

 Ideally the entitymanager should be managed outside the scope of  
 request-vars, since the order of request-var destruction isn't  
 given, which means that if the cleanup is done in the wrong order,  
 the Session is closed before referenced objects are cleaned up,  
 which introduces the possibility for weirdness.

 Cheers,
 Viktor



 On Tue, Sep 9, 2008 at 5:27 PM, Viktor Klang  
 [EMAIL PROTECTED] wrote:
 Hello Kris,

 this is a quite common problem in the world of JPA and object  
 references.
 I'm not going to bore people out by talking about object lifecycles,  
 but here's the essence of the cookie:

 When a JPA Session is created, it is bound to some context (wether  
 it be the currently running thread, a session-bean, an HTTPSession  
 or a RequestVar)
 Any PEs ( Persistent Entities) loaded through it will be associated  
 with that particular Session instance, however, JPA tries to proxy  
 alot of objects and collections
 to avoid having to load whole object graphs into memory when they  
 haven't been requested.
 Your problem arises when you try to access a proxy outside the scope  
 of the Session ( Google for Detached + JPA for more info on when an  
 object is outside the scope of a Session)


 What I usually do if I want to hang onto references (Detached) to  
 JPA-managed objects is that I create my own proxy around it that  
 does something like the following:

 if(!currentSession.contains(myObject))
currentSession.refresh(myObject); //Reattaches the object to the  
 session

 return myObject;

 However, this is also a pretty dangerous strategy, so you'll have to  
 know what you're doing here. (First-commit-wins, Last-commit-wins,  
 partial overwrites, lost updates... the list goes on)

 Hope someone finds this informative.

 Cheers,
 Viktor


 On Mon, Sep 8, 2008 at 11:31 PM, Kris Nuttycombe [EMAIL PROTECTED] 
  wrote:

 I've been following the advancement of the JPA/Lift tutorial with
 great interest, and have managed to get my app working, but I'm now
 struggling with a problem that occurs whenever I try to retrieve a
 collection that is mapped as a lazy association:

 Exception occured while processing /orders/list

 Message: org.hibernate.LazyInitializationException: failed to lazily
 initialize a collection of role:
 com.gaiam.gcsi.entities.subscription.Order.subscriptions, no session
 or session was closed
 
 org 
 .hibernate 
 .collection 
 .AbstractPersistentCollection 
 .throwLazyInitializationException(AbstractPersistentCollection.java: 
 358)
 
 org 
 .hibernate 
 .collection 
 .AbstractPersistentCollection 
 .throwLazyInitializationExceptionIfNotConnected 
 (AbstractPersistentCollection.java:350)
 
 org 
 .hibernate 
 .collection 
 .AbstractPersistentCollection 
 .readSize(AbstractPersistentCollection.java:97)
 
 org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
com.gaiam.gcsi.snippet.Orders$$anonfun$list 
 $1.apply(Orders.scala:21)
com.gaiam.gcsi.snippet.Orders$$anonfun$list 
 $1.apply(Orders.scala:18)
scala.Seq$class.flatMap(Seq.scala:267)
com.gaiam.gcsi.model.EM$$anon$1.flatMap(EM.scala:11)
com.gaiam.gcsi.snippet.Orders.list(Orders.scala:18)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

 I took the simplest-possible route of encapsulating the EntityManager
 in a RequestVar per Derek's suggestion as such:

 object EM {
  def entityManager() = (new
 InitialContext()).lookup(java:comp/env/persistence/ 
 em).asInstanceOf[EntityManager]
 }

 class Orders {
  object em extends RequestVar(entityManager())

  def list(xhtml: NodeSeq) : NodeSeq = {
val orders = em.createQuery(from
 Order).getResultList().asInstanceOf[java.util.List[Order]]
orders.flatMap(order =
  bind(order, xhtml,
   id -- Text(order.getId().toString),
   count -- Text(order.getSubscriptions().size().toString)))
  }
 }

 The issue appears to be that the transaction that the the query ran in
 is no longer active by the time of the call to
 order.getSubscriptions(). Has anyone else been using JTA and
 encountered this? I'm running the latest stable Glassfish (2.1 UR2)
 and using Hibernate for the persistence layer.

 Thanks,

 Kris





 -- 
 Viktor Klang
 Rogue Software Architect








 -- 
 Viktor Klang
 Senior Systems Analyst

 


--~--~-~--~~~---~--~~
You received this message 

[Lift] Re: One further: JPA + JTA + Lift

2008-09-09 Thread Viktor Klang
On Tue, Sep 9, 2008 at 3:59 PM, Oliver Lambert [EMAIL PROTECTED] wrote:

 Now, now lets not get testi ;-)


*laugh*

It's chill ;)

Cheers,



 On 09/09/2008, at 9:34 PM, Viktor Klang wrote:



 On Tue, Sep 9, 2008 at 10:09 AM, Oliver [EMAIL PROTECTED] wrote:

 Actually, is this the essence of the cookie. Why has the object been
 detached in the example Kris gives - is there something wrong with
 RequestVar lifecycle?


 Actually, just add a simple debug-print when the session is created and
 when it's closed. And if it prints that it is closed _before_ the execption
 is raised then there certainly is a problem with the requestvar lifecycle.

 Ideally the entitymanager should be managed outside the scope of
 request-vars, since the order of request-var destruction isn't given, which
 means that if the cleanup is done in the wrong order, the Session is
 closed before referenced objects are cleaned up, which introduces the
 possibility for weirdness.

 Cheers,
 Viktor




 On Tue, Sep 9, 2008 at 5:27 PM, Viktor Klang [EMAIL PROTECTED]wrote:

 Hello Kris,

 this is a quite common problem in the world of JPA and object references.
 I'm not going to bore people out by talking about object lifecycles, but
 here's the essence of the cookie:

 When a JPA Session is created, it is bound to some context (wether it be
 the currently running thread, a session-bean, an HTTPSession or a
 RequestVar)
 Any PEs ( Persistent Entities) loaded through it will be associated with
 that particular Session instance, however, JPA tries to proxy alot of
 objects and collections
 to avoid having to load whole object graphs into memory when they haven't
 been requested.
 Your problem arises when you try to access a proxy outside the scope of
 the Session ( Google for Detached + JPA for more info on when an object is
 outside the scope of a Session)


 What I usually do if I want to hang onto references (Detached) to
 JPA-managed objects is that I create my own proxy around it that does
 something like the following:

 if(!currentSession.contains(myObject))
currentSession.refresh(myObject); //Reattaches the object to the
 session

 return myObject;

 However, this is also a pretty dangerous strategy, so you'll have to know
 what you're doing here. (First-commit-wins, Last-commit-wins, partial
 overwrites, lost updates... the list goes on)

 Hope someone finds this informative.

 Cheers,
 Viktor


 On Mon, Sep 8, 2008 at 11:31 PM, Kris Nuttycombe 
 [EMAIL PROTECTED] wrote:


 I've been following the advancement of the JPA/Lift tutorial with
 great interest, and have managed to get my app working, but I'm now
 struggling with a problem that occurs whenever I try to retrieve a
 collection that is mapped as a lazy association:

 Exception occured while processing /orders/list

 Message: org.hibernate.LazyInitializationException: failed to lazily
 initialize a collection of role:
 com.gaiam.gcsi.entities.subscription.Order.subscriptions, no session
 or session was closed

  
 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)

  
 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)

  
 org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)

  org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)

  com.gaiam.gcsi.snippet.Orders$$anonfun$list$1.apply(Orders.scala:21)

  com.gaiam.gcsi.snippet.Orders$$anonfun$list$1.apply(Orders.scala:18)
scala.Seq$class.flatMap(Seq.scala:267)
com.gaiam.gcsi.model.EM$$anon$1.flatMap(EM.scala:11)
com.gaiam.gcsi.snippet.Orders.list(Orders.scala:18)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

 I took the simplest-possible route of encapsulating the EntityManager
 in a RequestVar per Derek's suggestion as such:

 object EM {
  def entityManager() = (new

 InitialContext()).lookup(java:comp/env/persistence/em).asInstanceOf[EntityManager]
 }

 class Orders {
  object em extends RequestVar(entityManager())

  def list(xhtml: NodeSeq) : NodeSeq = {
val orders = em.createQuery(from
 Order).getResultList().asInstanceOf[java.util.List[Order]]
orders.flatMap(order =
  bind(order, xhtml,
   id -- Text(order.getId().toString),
   count -- Text(order.getSubscriptions().size().toString)))
  }
 }

 The issue appears to be that the transaction that the the query ran in
 is no longer active by the time of the call to
 order.getSubscriptions(). Has anyone else been using JTA and
 encountered this? I'm running the latest stable Glassfish (2.1 UR2)
 and using Hibernate for the persistence layer.

 Thanks,

 Kris





 --
 Viktor Klang
 Rogue Software Architect








 --
 Viktor Klang
 Senior Systems Analyst





 



-- 
Viktor Klang
Senior Systems Analyst

--~--~-~--~~~---~--~~
You 

[Lift] Re: One further: JPA + JTA + Lift

2008-09-09 Thread Kris Nuttycombe

 On Tue, Sep 9, 2008 at 10:09 AM, Oliver [EMAIL PROTECTED] wrote:

 Actually, is this the essence of the cookie. Why has the object been
 detached in the example Kris gives - is there something wrong with
 RequestVar lifecycle?

Right; sorry, I should have been more clear about my question. I
expected that the persistence session would be bound to the scope of
the request at the appserver level, and that since Lift runs as a
servlet filter that this binding would persist throughout the Lift
call stack.

 Actually, just add a simple debug-print when the session is created and when
 it's closed. And if it prints that it is closed _before_ the execption is
 raised then there certainly is a problem with the requestvar lifecycle.

At this point, I'm beginning to think that this is not even
Lift-related; when I add a log statement immediately after running the
query I'm seeing the same result. It may be that the EntityManager is
not being bound correctly to the request in the first place and that
all retrieved objects are immediately detached, though I'm not certain
how to go about tracking that down.

 Ideally the entitymanager should be managed outside the scope of
 request-vars, since the order of request-var destruction isn't given, which
 means that if the cleanup is done in the wrong order, the Session is
 closed before referenced objects are cleaned up, which introduces the
 possibility for weirdness.

Hrm; in the other Lift/JPA thread folks seem to be moving *toward* the
RequestVar solution, particularly taking advantage of the cleanup
hooks in 0.10.

Thanks,

Kris

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: One further: JPA + JTA + Lift

2008-09-09 Thread Derek Chen-Becker
I'm pretty sure that the RequestVar should be around for the life of the
Lift session, which means that you should still have a valid lift session in
*any* snippet that would get called. Viktor's correct that this is a common
error that people run into with JPA, but it's usually because they're doing
something wrong. For instance, in Struts, you might naievely open and close
an EntityManager within one of your Action classes, but forget that the
lists won't actually be fetched until the resulting JSP is processed. In
Lift, the RequestVar should be set up before any of your code is called and
shouldn't be shut down until all of your code is finished. I haven't used
GlassFish at all, but I would assume that they have some debugging of their
EM implementation that may be helpful in tracking this down. If you're
getting the same error immediately following the call then that's pretty
weird. One other thing: GlassFish provides its own JPA stack; is there a
reason you're still using the Hibernate EM? The fact that you're using JNDI
from inside GlassFish makes me worried that you may have some implementation
conflicts between GlassFish's JPA stack (TopLink, I believe) and the
Hibernate one that would get packaged automatically if you haven't edited
the POM. I think you probably want to change the scope on the persistence
pom so that the javax.persistence's scope is provided and the Hibernate
and HSQLDB are test. Let me know what you find or if that helps.

Derek

On Tue, Sep 9, 2008 at 9:24 AM, Kris Nuttycombe
[EMAIL PROTECTED]wrote:


  On Tue, Sep 9, 2008 at 10:09 AM, Oliver [EMAIL PROTECTED] wrote:
 
  Actually, is this the essence of the cookie. Why has the object been
  detached in the example Kris gives - is there something wrong with
  RequestVar lifecycle?

 Right; sorry, I should have been more clear about my question. I
 expected that the persistence session would be bound to the scope of
 the request at the appserver level, and that since Lift runs as a
 servlet filter that this binding would persist throughout the Lift
 call stack.

  Actually, just add a simple debug-print when the session is created and
 when
  it's closed. And if it prints that it is closed _before_ the execption is
  raised then there certainly is a problem with the requestvar lifecycle.

 At this point, I'm beginning to think that this is not even
 Lift-related; when I add a log statement immediately after running the
 query I'm seeing the same result. It may be that the EntityManager is
 not being bound correctly to the request in the first place and that
 all retrieved objects are immediately detached, though I'm not certain
 how to go about tracking that down.

  Ideally the entitymanager should be managed outside the scope of
  request-vars, since the order of request-var destruction isn't given,
 which
  means that if the cleanup is done in the wrong order, the Session is
  closed before referenced objects are cleaned up, which introduces the
  possibility for weirdness.

 Hrm; in the other Lift/JPA thread folks seem to be moving *toward* the
 RequestVar solution, particularly taking advantage of the cleanup
 hooks in 0.10.

 Thanks,

 Kris

 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: One further: JPA + JTA + Lift

2008-09-08 Thread Oliver
It looks a little like the RequestVar has had its lifecycle closing hook
called by the time you call getSubscriptions
Try touch/get the subscriptions before you pass them into the bind.

cheers
Oliver

On Tue, Sep 9, 2008 at 7:31 AM, Kris Nuttycombe
[EMAIL PROTECTED]wrote:


 I've been following the advancement of the JPA/Lift tutorial with
 great interest, and have managed to get my app working, but I'm now
 struggling with a problem that occurs whenever I try to retrieve a
 collection that is mapped as a lazy association:

 Exception occured while processing /orders/list

 Message: org.hibernate.LazyInitializationException: failed to lazily
 initialize a collection of role:
 com.gaiam.gcsi.entities.subscription.Order.subscriptions, no session
 or session was closed

  
 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)

  
 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)

  
 org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
com.gaiam.gcsi.snippet.Orders$$anonfun$list$1.apply(Orders.scala:21)
com.gaiam.gcsi.snippet.Orders$$anonfun$list$1.apply(Orders.scala:18)
scala.Seq$class.flatMap(Seq.scala:267)
com.gaiam.gcsi.model.EM$$anon$1.flatMap(EM.scala:11)
com.gaiam.gcsi.snippet.Orders.list(Orders.scala:18)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

 I took the simplest-possible route of encapsulating the EntityManager
 in a RequestVar per Derek's suggestion as such:

 object EM {
  def entityManager() = (new

 InitialContext()).lookup(java:comp/env/persistence/em).asInstanceOf[EntityManager]
 }

 class Orders {
  object em extends RequestVar(entityManager())

  def list(xhtml: NodeSeq) : NodeSeq = {
val orders = em.createQuery(from
 Order).getResultList().asInstanceOf[java.util.List[Order]]
orders.flatMap(order =
  bind(order, xhtml,
   id -- Text(order.getId().toString),
   count -- Text(order.getSubscriptions().size().toString)))
  }
 }

 The issue appears to be that the transaction that the the query ran in
 is no longer active by the time of the call to
 order.getSubscriptions(). Has anyone else been using JTA and
 encountered this? I'm running the latest stable Glassfish (2.1 UR2)
 and using Hibernate for the persistence layer.

 Thanks,

 Kris

 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---