-->
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.  [ 8 posts ] 
Author Message
 Post subject: Lazy hell using Tiles
PostPosted: Tue Apr 12, 2005 5:32 pm 
Pro
Pro

Joined: Wed Nov 05, 2003 7:22 pm
Posts: 211
Hi,

I'm beating my head against the wall trying to resolve lazy exceptions. I have implemented the Open-session-in-view. I have done this in the TilesRequestProcessor that we extend from the regular Struts request processor. We do this, because tiles causes a regular filter to be called multiple times in one request. Using logger output I can see that the tilesrequestprocessor actually gets opened and closed once per request, as it should

The structure of the domain model basically is:
* categories
+ items
+relatedItems
+relatedGuides
+ guides
+ relatedGuides
etc



Hibernate version:2.1.8

Mapping documents:
I've edited these slightly to remove simple properties and hopefully make it a little easier to read.
<hibernate-mapping
>
<class
name="nl.tfe.ddb.business.entities.Category"
table="Categories"
>

<id
name="id"
column="id"
type="long"
unsaved-value="null"
>
<generator class="native">
</generator>
</id>

<set
name="items"
lazy="true"
inverse="false"
cascade="save-update"
sort="unsorted"
>

<key
column="FK_category_id"
>
</key>

<one-to-many
class="nl.tfe.ddb.business.entities.Item"
/>

</set>

<set
name="guides"
lazy="true"
inverse="false"
cascade="save-update"
sort="unsorted"
>

<key
column="FK_category_id"
>
</key>

<one-to-many
class="nl.tfe.ddb.business.entities.Guide"
/>

</set>

</class>

</hibernate-mapping>

<hibernate-mapping>
<class
name="nl.tfe.ddb.business.entities.IItem"
table="Items"
>

<id
name="id"
column="id"
type="long"
unsaved-value="0"
>
<generator class="native">
</generator>
</id>

<discriminator
column="Subclass"
type="string"
length="5"
/>

<subclass
name="nl.tfe.ddb.business.entities.Item"
discriminator-value="ITEM"
>

<set
name="relatedItems"
table="Itemrelatedinfo"
lazy="true"
cascade="none"
sort="unsorted"
>

<key
column="FK_item_id"
>
</key>

<many-to-many
class="nl.tfe.ddb.business.entities.Item"
column="FK_itemrelated_id"
outer-join="auto"
/>

</set>

<set
name="relatedGuides"
table="Itemrelatedguideinfo"
lazy="true"
cascade="none"
sort="unsorted"
>

<key
column="FK_item_id"
>
</key>

<many-to-many
class="nl.tfe.ddb.business.entities.Guide"
column="FK_relatedguide_id"
outer-join="auto"
/>

</set>


<many-to-one
name="category"
class="nl.tfe.ddb.business.entities.Category"
cascade="none"
outer-join="auto"
update="true"
insert="true"
column="FK_category_id"
/>


<set
name="orderForms"
table="Items_OrderForms"
lazy="true"
cascade="none"
sort="unsorted"
>

<key
column="FK_item_id"
>
</key>

<many-to-many
class="nl.tfe.ddb.business.entities.OrderForms"
column="FK_orderform_id"
outer-join="auto"
/>

</set>

<set
name="itemVersions"
table="item_versions"
lazy="true"
inverse="true"
cascade="all-delete-orphan"
sort="unsorted"
>

<key
column="FK_itemid"
>
</key>

<one-to-many
class="nl.tfe.ddb.business.entities.ItemVersions"
/>

</set>

</subclass>

</class>

</hibernate-mapping>



Code between sessionFactory.openSession() and session.close():
public class HibernateTilesProcessor extends TilesRequestProcessor {

public void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
synchronized (request.getSession()) {
User user = null;
user = (User) request.getSession().getAttribute("user");
if (user != null) {
try {
HibernateSession.currentSession().lock(user, LockMode.NONE);
} catch (HibernateException he) {
throw new ServletException(he);
} catch (Exception e) {
throw new ServletException(e);
}
}
}
try {
super.process(request, response);
} catch (Exception e) {
logger.error(e);
} finally {
try {
HibernateSession.closeSession();
} catch (Exception e) {
throw new ServletException(e);
}
}
}



Full stack trace of any exception that occurs:
Hibernate: select count(*) as x0_0_ from Categories category0_ inner join Items items1_ on category0_.id=items1_.FK_category_id where (category0_.id=? )and((items1_.status=? )or(items1_.status=? ))
DEBUG nl.tfe.ddb.data.hibernate.CategoryDAO : itemcount, category: Leefomgeving & Veiligheid = 15
ERROR net.sf.hibernate.LazyInitializationException : Failed to lazily initialize a collection - no session or session was closed
net.sf.hibernate.LazyInitializationException: Failed to lazily initialize a collection - no session or session was closed
at net.sf.hibernate.collection.PersistentCollection.initialize(PersistentCollection.java:209)
at net.sf.hibernate.collection.PersistentCollection.read(PersistentCollection.java:71)
at net.sf.hibernate.collection.Set.iterator(Set.java:130)
at nl.tfe.ddb.business.application.ProductHelper.getOrganizedirectly(ProductHelper.java:691)
at nl.tfe.ddb.business.delegate.ProductDelegate.getCategoryPageContent(ProductDelegate.java:127)
at nl.tfe.ddb.process.application.DisplayProductCategoryAction.execute(DisplayProductCategoryAction.java:114)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:421)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:226)
at nl.tfe.ddb.util.HibernateTilesProcessor.process(HibernateTilesProcessor.java:67)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1164)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:397)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Unknown Source)


Name and version of the database you are using:mySQL4.1

HibernateSession
public static Session currentSession() throws DataBaseException {
Session s = (Session) threadSession.get();
try {
if(s != null && !s.isOpen()){
s = null;
}
if(s == null) {
s = sessionFactory.openSession();
threadSession.set(s);
}
} catch (HibernateException he) {
logger.error("Error in opening session", he);
throw new DataBaseException(he);
}
return s;
}



public static void closeSession()throws DataBaseException {
try{
Session s = (Session) threadSession.get();
threadSession.set(null);
if(s != null && s.isOpen())s.close();
}catch(HibernateException he){
throw new DataBaseException(he);
}
}



Any help's appreciated.

Kind regards,

Marc


Top
 Profile  
 
 Post subject: Possibly a jsp issue
PostPosted: Wed Apr 13, 2005 2:13 am 
Pro
Pro

Joined: Wed Nov 05, 2003 7:22 pm
Posts: 211
I'm thinking, after a good night's sleep, that it may actually be an issue in the jsp. I believe that the filter actually covers the entire process from data layer to the JSP render. But the tilesrequestprocessor probably just covers the process from the data layer to the action.

I'll need to check that. Boy, it would all be a lot easier if you would just have one single global filter you can put around an entire request.

Marc


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 13, 2005 3:00 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Filter can be invoked many times per request ( "forward/include" ). Workaround is to count references. Increment counter before to invoke "chain.next", decrement it in "finally" block and close session if counter equals zero.


Top
 Profile  
 
 Post subject: That doesn't work in Tiles
PostPosted: Wed Apr 13, 2005 2:21 pm 
Pro
Pro

Joined: Wed Nov 05, 2003 7:22 pm
Posts: 211
Hi,

Unfortunately, that doesn't seem to work in tiles. Every tile is processed as a seperate request, so the counter reaches zero with every tile. I also tried putting everything in a request listener but that also gets destroyed multiple times. What I really want (and expect from a "requestDestroyed" method in a listener!) is to be notified when the request is being destroyed at the end of the rendering life cycle, i.e. at the end of the jsp-servlet.

I suppose I could include a close session in the footer of the site, but that's an ugly hack. Is there really no good way to solve this issue? I mean, doesn't just about everybody have the same problem?

Kind regards,

Marc


Top
 Profile  
 
 Post subject: Don't know anymore
PostPosted: Thu Apr 14, 2005 12:27 pm 
Pro
Pro

Joined: Wed Nov 05, 2003 7:22 pm
Posts: 211
Hi,

I'm stumped. Don't know what to do anymore. I get lazy exceptions after the first request. I tried placing the session at the bottom of the main JSP tile template. In my mind that is the absolute last place that gets processed and should ensure at least that all JSPs have access to the same session. If I leave the closeSession out of the app completely, everything works fine (until you get open session issues).

I still see 10 requests being initialized and destroyed after Hibernate.closeSession statement, don't know why:


DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.util.HibernateTilesProcessor : HibernateTilesFilter end
DEBUG nl.tfe.ddb.data.hibernate.HibernateSession : Closing session
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request created.
DEBUG nl.tfe.ddb.data.hibernate.HibernateRequestListener : Request destroyed.



Any help's appreciated. I'm beating my head agaisnt the wall. What should I look for to debug the reason for this?

Kind regards,

Marc


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 15, 2005 2:45 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
this stuff is implemented as "include" in struts, it runs in the same thread and counter must work without problems (try to print thread name in debug). It must be possible to map filter by some pattern to exclude "tiles" and it must work without counter using this configuration.


Top
 Profile  
 
 Post subject: Maybe barking up the wrong alley
PostPosted: Fri Apr 15, 2005 9:06 am 
Pro
Pro

Joined: Wed Nov 05, 2003 7:22 pm
Posts: 211
Hi,

It would seem that one of our developers implemented OSCache by directly getting the cache administrator in stead of through Hibernate. I expect this is the reason b/c object references would be stored across requests without being reattached to the hibernate session.

The tiles requestprocessor approach does in fact seem to ensure a single hibernate session for the entire request, including the JSP.

Of course, this does not negate the fact that the servlet filter approach simply doesn't work for an open session in view approach in many cases b/c the filter is entered and exited with every include. IMHO this fact does not get the attention it deserves by a long shot in the documentation or the book, even though a developer may be expected to know the technology they work with.

It will only work in all cases if all of the lazy collections used in the JSP have been initialized before they are sent to the JSP. This is something we should be (made) aware off.

Kind regards,

Marc


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 15, 2005 4:44 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Yes, it must be taken into account. I prefer reference counting, it does not depend on filter mapping.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.