Details
Description
This can be reproduced with Tomcat 6 or JBoss 4.2.1, but when JBoss is used, some extra error messages appear in the console that I think are related, but might actually be a separate bug -- I'm not sure.
1. Copy the attached SampleAjaxPush1.war_ file to your $HOME/YourUserName/liferay/deploy folder
2. Rename SampleAjaxPush1.war_ to SampleAjaxPush1.war
3. Start Liferay-4.3.4-JBoss-4.2.1-Tomcat bundle
4. Watch the JBoss console and make sure the WAR hot deploys properly
5. Start IE7 (should be reproducible with any browser though)
6. Login to Liferay Portal as test@liferay.com
7. Create a new portal page named "Ajax Push"
8. Add the "Customers" and "Bookings" portlets from under the "Samples" category
9. Click on each customer and make sure Ajax Push is working
10. Monitor the JBoss console and make sure there are no errors at this point
11. Sign-out of Liferay Portal
12. Sign back in to Liferay Portal as test@liferay.com
13. Click on the "Ajax Push" portal page
14. Click on one of the customers
15. Note that in the JBoss console, there should be "Session already invalidated" error messages
16. Note that killing IE7 browser and signing back in doesn't fix this problem
17. Repeat steps 11-14 in order to create yet another session "instance" of these portlets
18. Run the "jboss/bin/shutdown.bat ---shutdown" command
19. Note that in the JBoss console, each instance of these portlets have not yet been deallocated.
The instances actually never get deallocated unless the portal shuts down. And the default connection pool size in worker.properties is 10 so not very many sessions can get created before the server gets bogged down.
Also note the error java.lang.IllegalStateException: getAttributeNames: Session already invalidated after all the sessions are deallocated.
-
- ICE-3073.patch
- 18 kB
- Mircea Toma
-
Hide
- SampleAjaxPush1.war_
- 4.07 MB
- Neil Griffin
-
- WEB-INF/lib/util-taglib.jar 134 kB
- WEB-INF/web.xml 5 kB
- WEB-INF/lib/util-bridges.jar 36 kB
- WEB-INF/src/log4j.xml 0.9 kB
- WEB-INF/portlet.xml 2 kB
- WEB-INF/.../ICEfacesPortletSession.class 3 kB
- WEB-INF/src/com/.../model/Booking.java 2 kB
- WEB-INF/classes/com/.../model/Customer.java 2 kB
- WEB-INF/lib/commons-validator.jar 136 kB
- WEB-INF/liferay-display.xml 0.3 kB
- WEB-INF/lib/commons-lang.jar 240 kB
- META-INF/MANIFEST.MF 0.1 kB
- WEB-INF/classes/.../CustomerTable.java 8 kB
- xhtml/CustomerTable.xhtml 3 kB
- WEB-INF/lib/oro.jar 64 kB
- images/icefaces-showcase/arrowDown.gif 0.3 kB
- images/.../arrowCollapsed.gif 1 kB
- css/portlet-override.css 0.1 kB
- WEB-INF/lib/commons-beanutils.jar 184 kB
- css/icefaces-override.css 0.4 kB
- WEB-INF/classes/Language_en.properties 0.2 kB
- WEB-INF/classes/.../dao/CustomerUtil.class 2 kB
- xhtml/Bookings.xhtml 3 kB
- WEB-INF/tld/liferay-portlet.tld 2 kB
- WEB-INF/lib/commons-digester.jar 137 kB
- WEB-INF/lib/commons-logging.jar 52 kB
- WEB-INF/classes/com/.../model/Customer.class 2 kB
- WEB-INF/lib/backport-util-concurrent.jar 319 kB
- WEB-INF/classes/com/.../model/Booking.class 1 kB
- WEB-INF/lib/icefaces-facelets.jar 593 kB
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
I attached a patch for this issue. SessionDispatcher is now notified when the session is invalidated by the portal. It is using the same session shutdown sequence as the one used when session is invalidated internally.
I found the patch to work fine for the issue of the IllegalStateExceptions. The Views are disposed by the SessionDispatcher who also removes the Session from its SessionMap.
But the application now had a slightly different problem. There were instances of PersistentFacesState still being rendered when the user interacted with the application in the above way. These were detected by seeing FatalRenderingExceptions in a code branch that tested whether the PFState object was already disposed on entering the execute and render methods.
It turns out that the threadLocal variable in the PersistentFacesState objects can be set 'entering' the execute and render methods. This is a bit unexpected from the work in 1.7 where we checked threadLocal variable status on exiting the MainServlet and exiting the RunnableRender.run() method. Anyway, if the ThreadLocal is non-null on entry, it's not going to be cleared because an exception is thrown, and the cycle would continue the next time someone interacted with the application.
I've checked in a couple of lines that clears the PersistentFacesState thread local in this code path.
I'm still having issues with long gone http sessions related data keeping in the memory.
After some load testing the JVM's CMS Old gen is filled to the max and "[com.icesoft.util.MonitorRunner] Failed to run monitor: null" is printed to log.
Also in a heapdump generated by jmap ( no activity on the server, all users logged out) there are still instances of IceFaces components (and some others too);
Object Histogram:
num #instances #bytes Class description
--------------------------------------------------------------------------
1: 1128218 562200216 char[]
2: 66617 220418688 byte[]
3: 506870 62469240 java.lang.Object[]
4: 294296 50821464 java.util.HashMap$Entry[]
5: 1203744 48149760 java.lang.String
6: 655296 36696576 java.util.HashMap$Entry
7: 259976 36408944 * ConstMethodKlass
8: 259976 31209920 * MethodKlass
9: 477604 26745824 org.apache.xerces.dom.AttrImpl
10: 20310 24144616 * ConstantPoolKlass
11: 230341 22112736 org.apache.xerces.dom.ElementImpl
12: 115115 17497480 java.lang.reflect.Method
13: 234893 16912296 java.util.HashMap
14: 20310 16597248 * InstanceKlassKlass
15: 265972 14311280 * SymbolKlass
16: 16999 13846848 * ConstantPoolCacheKlass
17: 64748 10392800 int[]
18: 23498 9399200 com.icesoft.faces.component.ext.HtmlPanelGrid
19: 230089 9203560 org.apache.xerces.dom.AttributeMap
20: 117920 8490240 java.util.LinkedHashMap$Entry
21: 212176 8487040 java.util.Vector
22: 141765 6804720 java.util.concurrent.locks.ReentrantLock$NonfairSync
23: 141572 6795456 java.util.concurrent.ConcurrentHashMap$Segment
24: 96064 6148096 javax.servlet.jsp.tagext.TagAttributeInfo
25: 150502 6020080 java.util.ArrayList
26: 122127 5862096 java.lang.ref.WeakReference
27: 97606 5465936 java.lang.ref.SoftReference
28: 96999 5423528 java.lang.String[]
29: 141572 5104296 java.util.concurrent.ConcurrentHashMap$HashEntry[]
30: 14951 5023536 com.icesoft.faces.component.ext.HtmlOutputText
31: 61876 4455072 com.icesoft.faces.context.DOMContext
32: 48453 4263864 java.util.LinkedHashMap
33: 7173 4231696 * MethodDataKlass
34: 43430 4169280 java.beans.MethodDescriptor
35: 21642 3982128 java.lang.Class
36: 28371 3631488 java.lang.reflect.Field
37: 31769 3244968 * System ObjArray
38: 4271 3143456 com.icesoft.faces.component.selectinputtext.SelectInputText
39: 64053 3074544 javax.faces.component.UIComponentBase$ChildrenList
40: 74762 2990480 javax.faces.component.UIComponentBase$AttributesMap
41: 14178 2495328 org.springframework.beans.GenericTypeAwarePropertyDescriptor
42: 57954 2318160 com.liferay.portlet.Preference
43: 25960 2294552 short[]
44: 16706 2138368 java.beans.PropertyDescriptor
45: 23432 2062016 java.util.TreeMap$Node
46: 10719 2058048 com.liferay.portal.model.impl.LayoutImpl
I'll create another issue to track this issue.
When the user opens the "Ajax Push" portlet page, two portletProxySessions are created, and those are associated with an HttpSession from the user. When the user logs out, he/she is logging out from the Portal Web application. The HttpSession is invalidated, but the SessionDispatcher is not informed via callback, and therefore the ICEfaces core never disposes of the Session.
When a user application logs out, and that's done entirely from within an ICEfaces servlet, the incoming HttpServlet is wrapped in an InterceptingServletSession, which overrides invalidate() and uses this to notify the SessionDispatcher. In the Portlet example, the request to log out is handled by the Portal application, outside the ICEfaces servlet path which is why this mechanism is subverted.
The ContextEventRepeater gets notified of the SessionDestroyed event, but the SessionDispatcher is not a client of the repeater. It may be possible to make the Dispatcher an event listener but care must be taken and difficult to verify differences in timing may occur, since the ContextEventRepeater is downstream of the events generated by the SessionDispatcher.