[
https://issues.apache.org/jira/browse/WICKET-3470?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13008166#comment-13008166
]
Martin Grigorov commented on WICKET-3470:
-----------------------------------------
In a brainstorm session in IRC between me and ivaynberg here is our proposal
for this problem:
Background:
Servlet containers deserialize persisted sessions before initializing the
Servlet Filters (there is a problem reported that GAE (Jetty 6.x) fails to
deserialize persisted session because there is no
org.apache.wicket.page.PersistentPageManager for an application with name
"XYZ").
The problem described in this ticket is similar but in the opposite direction:
Tomcat destroys WicketFilter and then tries to persist the sessions and
PersistentPageManager is no more available.
Also by Servlet specification the container can destroy a Servlet (it is not
clear for Filter but Tomcat manages them the same way) at any time without
stopping the whole application and later re-initialize them again.
Proposed solution:
We need a ServletContextListener (SCL) that will setup the PageManager before
the start of WicketFilter and stop it after its destroy.
This SCL will be put in web-fragment.xml in wicket-core.jar and will be used
for free for all users which use Servlet 3.0 complaint web containers. Servlet
2.x users will have to add it manually in their web.xml files.
We would like to avoid parsing of web.xml so the SCL to be able to find the
name of the Filter and the name of the Application class the setup will look
like:
for Application:
<context-param>
<param-name>wicket-app-filterName1</param-name>
<param-value>com.mycompany.MyApp</param-value>
</context-param>
<filter>
<filter-name>wicket-app-filterName1</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
</filter>
for ApplicationFactory:
<context-param>
<param-name>wicket-app-factory-filterName2</param-name>
<param-value>com.mycompany.MyAppFactory</param-value>
</context-param>
<filter>
<filter-name>wicket-app-factory-filterName2</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
</filter>
Here 'wicket-app-' and 'wicket-app-factory-' are special prefixes! SCL will
iterate over all context parameters and all starting with these special
prefixes will be processed.
Later when WicketFilter is being initialized it will parse its filterName like
it does it currently and will find its application/applicationFactory class
from the servlet context parameters.
The same logic will be applied for WicketServlet.
Specific parameters like wicket.configuration, or Guice module names, etc. will
still be in filter's <init-param>.
Opinions?
> Can't write session to disk with tomcat : Servlet is destroyed before
> serialization
> -----------------------------------------------------------------------------------
>
> Key: WICKET-3470
> URL: https://issues.apache.org/jira/browse/WICKET-3470
> Project: Wicket
> Issue Type: Bug
> Components: wicket-core
> Affects Versions: 1.5-RC1
> Environment: Windows 7 x64
> apache-tomcat-6.0.32-windows-x86
> (Running from Eclipse view, Faceted project)
> Reporter: SegFault
> Labels: persistent, session, storage, tomcat
> Fix For: 1.5.0
>
> Original Estimate: 4h
> Remaining Estimate: 4h
>
> Hi,
> When I stop my tomcat, I have the following error :
> GRAVE: Exception au déchargement des sessions vers le stockage persistant
> (persistent storage)
> java.lang.IllegalStateException: PageManager for application wicket not
> registered.
> at
> lm.lbx.application.PersistentPageManager$SessionEntry.getPageStore(PersistentPageManager.java:86)
> at
> lm.lbx.application.PersistentPageManager$SessionEntry.writeObject(PersistentPageManager.java:197)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
> at java.lang.reflect.Method.invoke(Unknown Source)
> at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
> at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
> at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
> at java.io.ObjectOutputStream.writeObject0(Unknown Source)
> at java.io.ObjectOutputStream.writeObject(Unknown Source)
> at
> org.apache.catalina.session.StandardSession.writeObject(StandardSession.java:1561)
> at
> org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:1004)
> at
> org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:528)
> at
> org.apache.catalina.session.StandardManager.unload(StandardManager.java:469)
> at
> org.apache.catalina.session.StandardManager.stop(StandardManager.java:678)
> at
> org.apache.catalina.core.StandardContext.stop(StandardContext.java:4875)
> at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1106)
> at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1106)
> at org.apache.catalina.core.StandardEngine.stop(StandardEngine.java:468)
> at
> org.apache.catalina.core.StandardService.stop(StandardService.java:604)
> at org.apache.catalina.core.StandardServer.stop(StandardServer.java:788)
> at org.apache.catalina.startup.Catalina.stop(Catalina.java:662)
> at org.apache.catalina.startup.Catalina.start(Catalina.java:629)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
> at java.lang.reflect.Method.invoke(Unknown Source)
> at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
> at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
> After a little digging, it's because tomcat first unload the servlet mapping
> and destroy the servlet, and then, ask for serialization. I'm not sure it's a
> wiket bug, tell me if i have to report it against tomcat.
> Here is the trace of the destroy :
> Thread [main] (Suspended (breakpoint at line 357 in PersistentPageManager))
> PersistentPageManager.destroy() line: 357
> PageAccessSynchronizer$1(PageManagerDecorator).destroy() line: 86
> LibellexApplication(Application).internalDestroy() line: 658
> LibellexApplication(WebApplication).internalDestroy() line: 470
> WicketFilter.destroy() line: 456
> ApplicationFilterConfig.release() line: 357
> StandardContext.filterStop() line: 4106
> StandardContext.stop() line: 4869
> StandardHost(ContainerBase).stop() line: 1106
> StandardEngine(ContainerBase).stop() line: 1106
> StandardEngine.stop() line: 468
> StandardService.stop() line: 604
> StandardServer.stop() line: 788
> Catalina.stop() line: 662
> Catalina.start() line: 629
> NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
> available [native method]
> NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
> DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not
> available
> Method.invoke(Object, Object...) line: not available
> Bootstrap.start() line: 289
> Bootstrap.main(String[]) line: 414
> And the trace requesting serialization :
> Thread [main] (Suspended (breakpoint at line 83 in
> PersistentPageManager$SessionEntry))
> PersistentPageManager$SessionEntry.getPageStore() line: 83
> PersistentPageManager$SessionEntry.writeObject(ObjectOutputStream)
> line: 197
> NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
> available [native method]
> NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
> DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not
> available
> Method.invoke(Object, Object...) line: not available
> ObjectStreamClass.invokeWriteObject(Object, ObjectOutputStream) line:
> not available
> ObjectOutputStream.writeSerialData(Object, ObjectStreamClass) line: not
> available
> ObjectOutputStream.writeOrdinaryObject(Object, ObjectStreamClass,
> boolean) line: not available
> ObjectOutputStream.writeObject0(Object, boolean) line: not available
> ObjectOutputStream.writeObject(Object) line: not available
> StandardSession.writeObject(ObjectOutputStream) line: 1561
> StandardSession.writeObjectData(ObjectOutputStream) line: 1004
> StandardManager.doUnload() line: 528
> StandardManager.unload() line: 469
> StandardManager.stop() line: 678
> StandardContext.stop() line: 4875
> StandardHost(ContainerBase).stop() line: 1106
> StandardEngine(ContainerBase).stop() line: 1106
> StandardEngine.stop() line: 468
> StandardService.stop() line: 604
> StandardServer.stop() line: 788
> Catalina.stop() line: 662
> Catalina.start() line: 629
> NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
> available [native method]
> NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
> DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not
> available
> Method.invoke(Object, Object...) line: not available
> Bootstrap.start() line: 289
> Bootstrap.main(String[]) line: 414
> Well at this time, a simple dirty hack is to bypass destroy chain to avoid
> removal of app from managers properties of class PersistentPageManager. But I
> would like to have a real clean solution.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira