-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Joe,
On 10/8/2009 12:12 PM, Joe Hansen wrote: > I will now think twice before I store anything in the session and > will make sure I remove no longer used objects from the HTTP > Session. It's always a good goal to limit your session size, but it's not always foolproof because users don't always do the things you expect. For instance, if you have a process your user goes through, and you store a big object (or set of objects) in the session during that process, and the user does not finish the process, you still need to clean-up after that. >> You can couple session-object expiration with lazy >> instantiation/fetch for a solution that can keep your sessions >> lightweight yet allow insanely long session timeouts. > > Chris, can you please elaborate what you mean by coupling > session-object expiration with lazy fetch? So, lazy instantiation (or initialization) is a design pattern where you only create objects when you are actually going to use them, as opposed to creating everything you /might/ need just in case it's necessary. "Lazy fetch" is just a term I used to describe grabbing your Foto objects only when actually needed (rather than speculatively loading them). This concept is illustrated easily in a few lines of code: // This would be speculative instantiation Vector v = new Vector(1000); // Just in case ... if(something) { // use the Vector object } // This would be lazy instantiation Vector v = null; if(something) { if(null == v) v = new Vector(); // use the Vector object } It sounds simple, and it is. The same concept can be applied when fetching large objects from the database and possibly storing them in the session. You can use the session as a poor-mans cache something like this: // You probably already do this kind of thing in your code: Foto foto = (Foto)session.getAttribute("myFotoObject"); // But now, you can plan for the case where the object either // was never there, or has disappeared because it has been // removed to save memory: if(null == foto) { foto = fotoManager.fetch(whatever); session.setAttribute("myFotoObject", foto); } Using this technique, you can get the benefit of session "caching" that is tolerant of disappearing objects due to the "lazy-fetching" technique I describe. See below for how to hook it up to cache-flushing schemes. >> Is it an absolute requirement that these objects be stored in the >> session at all? If so, then maybe the caching strategy can be tweaked a >> bit to allow both requirements to peacefully coexist. > > The code is 3 years old and it does not use a caching strategy at all. > However, I am planning to use ehcache when we developer our future > websites. 3 years is not a ripe old age for code. Our best code is the stuff that has lasted for 3 or more years without having to be rewritten. ;) If ehcache is your thing, go for it. There are other possibilities, too. >> There are even techniques that will allow your session objects to expire >> when memory gets tight (which is super cool IMO). One way to retrofit your web application is to use SoftReferences to store objects within your session attributes. You can either re-write all your code to deal with SoftReferences (see examples below), or you can get tricky and write a simple wrapper around your request/session objects to do the magic for you. I'll show you how such tricks could be implemented. Let's say that you always use the prefix "foto" for all Foto objects in the session. You could use this technique with all session objects, but it really only makes sense with the big ones. Here's the plan: 1. Alter your code that deals with Foto objects stored in the session to tolerate the objects apparently disappearing from the session without notice. That is, always check for null and re-fetch from the database or wherever you get your Foto data. 2. SoftReference objects will be used to store your actual Foto objects in the session. 3. Write a Filter which wraps the HttpServletRequest object to return a wrapped HttpSession object which will handle the SoftReferences mentioned in #2 (got all that?) It's easier than it sounds. Let's assume #1 is already done. Here's how to write the filter (which implements both #2 and #2 above): public class SoftReferenceFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { if(request instanceof HttpServletRequest) request = new SoftReferenceRequestWrapper((HttpServletRequest)request); chain.doFilter(request, response); } public static class SoftReferenceRequestWrapper extends HttpServletRequestWrapper { public SoftReferenceRequestWrapper(HttpServletRequest request) { super(request); } // Override public HttpSession getSession() { HttpSession session = super.getSession(); if(null != session) session = new SoftReferenceSessionWrapper(session); return session; } // Override public HttpSession getSession(boolean create) { HttpSession session = super.getSession(create); if(null != session) session = new SoftReferenceSessionWrapper(session); return session; } } public static class SoftReferenceSessionWrapper implements HttpSession { private HttpSession _base; public SoftReferenceSessionWrapper(HttpSession base) { _base = base; } // Here's where the magic happens public Object getAttribute(String key) { Object o = super.getAttribute(key); // Get the stored object // Unwrap the SoftReference if appropriate if(null != o && key.startsWith("foto") && o instanceof SoftReference) o = ((SoftReference)o).get(); return o; } public Object setAttribute(String key, Object value) { // Wrap the value in a SoftReference if appropriate if(key.startsWith("foto") && null != value) value = new SoftReference(value); super.setAttribute(key, value); } // Now you get to implement all the other methods of HttpSession // as pass-throughs to the superclass. I'm not typing all that trash // right now. ;) } } It's amazing the kinds of trickery you can pull when you wrap objects such as the request and session. I hope that all makes sense. Feel free to post questions about this code if you have any. Good luck, - -chris -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkrOSfAACgkQ9CaO5/Lv0PC7YwCeI1vkuvYnfdRQArBcX66OirTT CRMAnR53/xSUiVBiVSAXT/I2G6Pir0M1 =VUTk -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org