I have a question, on behalf of a client, concerning Tomcat clustering
and deserialization, in the context of a Tapestry 5 application.
Here's the short form: some of the objects that a Tapestry
application may put into the HttpSession will only deserialize
correctly
if the Tapestry application (in the form of a Servlet Filter) has
initialized first ... but it appears that when starting up a Tomcat
instance,
the HttpSession data is deserialized from disk *before* the filter is
initialized.
Here's the stack trace:
ERROR ( ManagerBase:412 ) - IOException while loading
persisted sessions: java.io.InvalidObjectException: Service token for
service 'ProductConfig' can not be converted back into a proxy because
no proxy provider has been registered. This may indicate that an IoC
Registry has not been started yet.
java.io.InvalidObjectException: Service token for service
'ProductConfig' can not be converted back into a proxy because no
proxy provider has been registered. This may indicate that an IoC
Registry has not been started yet.
at
org.apache.tapestry5.ioc.internal.ServiceProxyToken.readResolve(ServiceProxyToken.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1061)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1762)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at
java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at
org.apache.catalina.session.StandardSession.readObject(StandardSession.java:1407)
at
org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:931)
at
org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:394)
at
org.apache.catalina.session.StandardManager.load(StandardManager.java:321)
at
org.apache.catalina.session.StandardManager.start(StandardManager.java:637)
at
org.apache.catalina.core.ContainerBase.setManager(ContainerBase.java:432)
at
org.apache.catalina.core.StandardContext.start(StandardContext.java:4160)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:736)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at
org.apache.catalina.core.StandardService.start(StandardService.java:448)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:700)
at org.apache.catalina.startup.Catalina.start(Catalina.java:552)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:295)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:433)
Caused by: java.lang.RuntimeException: Service token for service
'ProductConfig' can not be converted back into a proxy because no
proxy provider has been registered. This may indicate that an IoC
Registry has not been started yet.
at
org.apache.tapestry5.ioc.internal.SerializationSupport.readResolve(SerializationSupport.java:72)
at
org.apache.tapestry5.ioc.internal.ServiceProxyToken.readResolve(ServiceProxyToken.java:37)
The failure occurs inside this code:
class ServiceProxyToken implements Serializable
{
private final String serviceId;
ServiceProxyToken(String serviceId)
{
this.serviceId = serviceId;
}
Object readResolve() throws ObjectStreamException
{
try
{
return SerializationSupport.readResolve(serviceId);
}
catch (Exception ex)
{
ObjectStreamException ose = new
InvalidObjectException(ex.getMessage());
ose.initCause(ex);
throw ose;
}
}
}
This occurs because the Tapestry IoC container has not been
initialized by the Tapestry Filter yet.
SerializationSupport.readResolve() requires that the Filter be
initialized.
In case you are curious: these ServiceProxyToken objects are
placeholder for Tapestry IoC services. In Tapestry IoC, every service
implements an interface, and is exposed to user code as an instance of
a proxy. The proxy hides the lifecycle of the service (i.e., to
support just-in-time instantiation), and the proxy is Serializable
where the actual service implementation class is not.
Sometimes an HttpSession object will hold a reference to a Tapestry
service. When serialized, the proxy serializes a ServiceProxyToken.
When that's deserialized, we get back an equivalent service in the new
server.
So ... is there a configuration option somewhere to defer loading of
the HttpSession until after the filters are instantiated? Is there
some other mechanism that will support what I want to do?
Alternately, I'd appreciate some pointers on what code would need to
be modified to support this scenario. It makes a big difference to
Tapestry 5 users who use Tomcat clustering!
--
Howard M. Lewis Ship
Creator of Apache Tapestry
The source for Tapestry training, mentoring and support. Contact me to
learn how I can get you up and productive in Tapestry fast!
(971) 678-5210
http://howardlewisship.com
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]