Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 370377 - Objects serialized and persisted to MongoDB may not be in the classloader of the MongoSessionHandler, causing ClassNotFoundException
Summary: Objects serialized and persisted to MongoDB may not be in the classloader of ...
Status: CLOSED FIXED
Alias: None
Product: Jetty
Classification: RT
Component: other (show other bugs)
Version: unspecified   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 7.5.x   Edit
Assignee: Jesse McConnell CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-01 16:18 EST by David Seymore CLA
Modified: 2012-02-02 17:44 EST (History)
0 users

See Also:


Attachments
Patch generated against the 8.1.0.v20120127 tag AFTER change in bug 370368 (5.16 KB, patch)
2012-02-02 08:57 EST, David Seymore CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description David Seymore CLA 2012-02-01 16:18:11 EST
Build Identifier: 8.1.0.v20120127

2012-02-01 15:18:51.873:WARN:oejnm.MongoSessionManager:
java.lang.ClassNotFoundException: com.i3analytics.maps.SomeMap
	at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:247)
	at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:603)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
	at org.eclipse.jetty.nosql.mongodb.MongoSessionManager.decodeValue(MongoSessionManager.java:447)
	at org.eclipse.jetty.nosql.mongodb.MongoSessionManager.loadSession(MongoSessionManager.java:318)
	at org.eclipse.jetty.nosql.NoSqlSessionManager.getSession(NoSqlSessionManager.java:68)
	at org.eclipse.jetty.server.session.AbstractSessionManager.getHttpSession(AbstractSessionManager.java:270)
	at org.eclipse.jetty.server.session.SessionHandler.checkRequestedSessionId(SessionHandler.java:277)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:158)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:907)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
	at org.eclipse.jetty.server.Server.handle(Server.java:346)
	at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:442)
	at org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:924)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:582)
	at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:218)
	at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:51)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:586)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:44)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
	at java.lang.Thread.run(Thread.java:662)



The ObjectInputStream is using the classloader of the MongoSessionHandler which won't have access to classes in my war (com.i3analytics.*). 

Reproducible: Always

Steps to Reproduce:
1. Configure jetty to use mongoDb session clustering
2. Place an instance of a class, that exists only in the war, into the session
3. Bounce the container
4. Upon call of the loadSession of the MongoSessionHandler on the client accessing the server again, ClassNotFound exception is thrown.

Also, noted in this stackoverflow: http://stackoverflow.com/questions/9066844/jetty-nosql-mongosessionmanager-usage-on-heroku

Potential Fix:

Following the code in the JDBCSessionManager (copy-paste) I created a ClassLoadingObjectInputStream. 

I changed line 446 to:

ClassLoadingObjectInputStream in = new ClassLoadingObjectInputStream(new ByteArrayInputStream((byte[])value));


And the situation was resolved, objects were de-serialized. 

I am seeing another issue now though, that the objects de-serialized don't line up the byte arrays I am getting from the DBObject attr's map of values.  

I'm tracing through that now.
Comment 1 David Seymore CLA 2012-02-02 08:49:18 EST
The other problem I am seeing I just pinned down to the ByteArrayOutputStream and ObjectOutputStream being passed around as parameters to the encodeName method. Even when the reset is called the objects saved into mongodb do not deserialize back into the class that the byte array is supposed to represent. 

My change is:

Line 408:

From:
 protected Object encodeName(ObjectOutputStream out, ByteArrayOutputStream bout, Object value) throws IOException
To:
 protected Object encodeName(Object value) throws IOException


Line 424:
From:
o.append(encodeName(entry.getKey().toString()),encodeName(out,bout,entry.getValue()));
To:
o.append(encodeName(entry.getKey().toString()),encodeName(entry.getValue()));

And then on Line 431, I instantiated a fresh set of outputstreams:

 ByteArrayOutputStream bout = new ByteArrayOutputStream();
 ObjectOutputStream out = new ObjectOutputStream(bout);


Now the classes going into mongodb are the same when they come out.
Comment 2 David Seymore CLA 2012-02-02 08:57:35 EST
Created attachment 210443 [details]
Patch generated against the 8.1.0.v20120127 tag AFTER change in bug 370368

Here is a patch that contains both fix for issue describe in title of this ticket and the change to use of newly instantiated output streams per call to encode.
Comment 3 Jesse McConnell CLA 2012-02-02 17:44:02 EST
Applied, thanks much.

Since your on a roll I figured I would link you this:

http://wiki.eclipse.org/Jetty/Contributor/Contributing_Patches

It makes the easiest to apply patches and gives you credit within our git system.  Gerrit is fast approaching as well. :)

anyway, much appreciate the contributions!