tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@clearink.com
Subject Re: Servlet reloading?
Date Sat, 12 Feb 2000 20:44:10 GMT
> 
> jon@clearink.com wrote:
> 
> > There is a way to "copy" those HttpSession objects into a new
> > classloader by serializing them to an outputstream, 
> 
> Cool trick.  What happens to objects in the session that aren't
> serializable, such as happens with a non-distributed webapp?  

Right now, they are just discarded silently which can be annoying if 
you forget to make them serializable...but in the case of a
non-distributed webapp, that doesn't apply. All you have to do is add
"implements Serializable" to those objects and that is enough. Remember,
we are not trying to copy those objects to a file or anything, this is
just for the purpose of simply "moving" them into a new classloader by
re-instantiating them through serialization (I can't believe i just said
that). ;-)

> And do you see this as a way to satisfy the API 2.2 requirement that no
> unexpected ClassCastException problems occur?  What about objects not 
> in a session that are shared by servlets?

I see this as a way to solve the problems. JServ has been doing this since
like 1.1b3. Other servlet engines do the same exact thing. I posted
something to the experts group about making this behavior as part of the
ServletAPI, but no one commented...sigh...

Note that the contexts were originally created in the context of the
systemclassloader so they can be stored and retrieved without issues.

Note the use of the inner class...ACLObjectInputStream...this is the KEY
to all of this working...it de-serializes the inputstream with the
AdaptiveClassloader instance.

-jon

Here is the jist of the code since none of you will actually look at
it...


    class ACLObjectInputStream extends ObjectInputStream {
        ACLObjectInputStream(InputStream bIn) throws IOException {
            super(bIn);
        }
	protected Class resolveClass(ObjectStreamClass v)
          throws IOException, ClassNotFoundException {
            return loader.loadClass(v.getName());
        }
    }


here is the bulk of the work that does the
serialization/de-serialization...


        // This code allows the sessions to be restored even after 
        // the AdaptiveClassLoader has been re-instantiated.
        if (sessions != null) {
            try {
                // save the contexts...they are not serializable, but 
                // we need to save them anyways.
                Hashtable theContexts = new Hashtable(sessions.size());
                
                Enumeration keys = sessions.keys();
                String key = null;
                JServSession value = null;

                while(keys.hasMoreElements()) {
                    key = (String) keys.nextElement();
                    value = (JServSession) sessions.get(key);

                    theContexts.put (key, (JServServletManager)
value.getSessionContext());
                }
                
                // writes the session data out, but loses the contexts
                // because they cannot be serialized
                ByteArrayOutputStream b = new ByteArrayOutputStream();
                ObjectOutputStream o = new ObjectOutputStream(b);
                
                o.writeObject(sessions);
                o.flush();
                
                ByteArrayInputStream bIn = new ByteArrayInputStream
(b.toByteArray());
                ObjectInputStream oOut= new ACLObjectInputStream(bIn);
                
                // unserialize the sessions
                sessions = (Hashtable) oOut.readObject();

                // restore the contexts
                keys = sessions.keys();
                while(keys.hasMoreElements()) {
                    key = (String) keys.nextElement();
                    value = (JServSession) sessions.get(key);

                    value.setSessionContext((JServServletManager)
theContexts.get ( key ));
                }

                if (JServ.log.active)
                    JServ.log.log(CH_DEBUG, "Restoring sessions
hashtable.");

            } 
            catch (Exception e) {
                if (JServ.log.active)
                    JServ.log.log(CH_DEBUG, "Restoring sessions hashtable
failed:" + e.toString());
                                    
                sessions = new Hashtable();
            }
        } else {
            if (JServ.log.active)
                JServ.log.log(CH_DEBUG, "Creating new sessions
hashtable.");

            sessions = new Hashtable();
        }

you also have to override the write/readObject methods in
JServSession (HttpSession implementation) as well...the reason is because
of the servlet contexts above...you have to only read/write the data that
is important for the session...

    private void readObject(ObjectInputStream stream)
        throws ClassNotFoundException, IOException {

        // Read the session identifier
        id = (String) stream.readObject();

        // Read the other scalar instance variables
        creationTime = ((Date) stream.readObject()).getTime();
        lastAccessTime = ((Date) stream.readObject()).getTime();
        valid = ((Boolean) stream.readObject()).booleanValue();
        isNew = ((Boolean) stream.readObject()).booleanValue();

        sessionData = (Hashtable) stream.readObject();
    }

    private synchronized void writeObject(ObjectOutputStream stream)
        throws IOException {

        // Write the session identifier
        stream.writeObject(id);

        // Write the other scalar instance variables
        stream.writeObject(new Date(creationTime));
        stream.writeObject(new Date(lastAccessTime));
        stream.writeObject(new Boolean(valid));
        stream.writeObject(new Boolean(isNew));

        // write out the user session data that is Serializable
        Hashtable saveData = new Hashtable(sessionData.size());
        String key = null;
        Object value = null;
        
        Enumeration keys = sessionData.keys();
        while(keys.hasMoreElements())
        {
            key = (String) keys.nextElement();
            value = sessionData.get(key);
            if (value instanceof Serializable) {
                saveData.put(key, value);
            }
            // if we can't serialize the object stored in 
            // the session, then check to see if it implements 
            // HttpSessionBindingListener and then call its 
            // valueUnbound method, allowing it to save its state
            // correctly instead of just being lost into the etherworld
            else if (value instanceof HttpSessionBindingListener ) {
                try {
                    HttpSessionBindingListener event = 
                        (HttpSessionBindingListener) sessionData.get(key);
                    event.valueUnbound(new HttpSessionBindingEvent(this,
key));
                } catch (Exception e) {
                }
            }
        }
        stream.writeObject(saveData);
    }

Mime
View raw message