DataContextProvider (was: Best Practices for Retrieving DataContexts)

From: Scott McClure (scot..martblob.com)
Date: Wed Jun 30 2004 - 15:59:38 EDT

  • Next message: Andrus Adamchik: "Re: templates for class generator"

    Ok, I have created the class that was described in the previous thread.
    The class uses ThreadLocal to do the binding, and it should work in a
    web application. The basic theory is the class extends
    WebApplicationListener and implements a 2.4 Servlet API Listener to get
    notified for requests, and then it places the DataContext in the
    ThreadLocal.

    I have been unable to get to my normal devel location, so this class is
    basically uncompiled and very untested. I was going to wait to send it
    out, but it looks like people are interested. I will post a more final
    version once I actually get to working out the kinks.

    If you have any questions, send them to me personally so we don't flood
    the list.

    Scott

    package org.objectstyle.cayenne.conf;

    import org.objectstyle.cayenne.access.DataContext;
    import org.objectstyle.cayenne.conf.BasicServletConfiguration;
    import org.objectstyle.cayenne.conf.WebApplicationListener;

    import javax.servlet.ServletRequest;
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;

    /**
     * <p>This class allows for a web application to retrieve a DataContext anywhere
     * in a servlet request. This is very useful when you want to decouple the
     * controller layer (Servlets, Struts, etc.) from a DAO layer, and
     * cannot/should not include a implementation-specific DataContext in a DAO
     * interface. To use this class, configure this class as a listener (like the
     * WebApplicationListener):</p>
     * <p>In <code>web.xml</code> deployment descriptor, configure as a listener of
     * context, session, and request events:</p>
     *<pre>&lt;listener&gt;
         &lt;listener-class&gt;org.objectstyle.cayenne.conf.WebApplicationListener&lt;/listener-class&gt;
    &lt;/listener&gt;</pre>
     * You then can retrieve a DataContext by calling the static method
     * ..ink DataContextProvider#getDataContext()} or by calling
     * ..ink BasicServletConfiguration#getDefaultContext(HttpSession)}
     * <p><b>If using DataContextProvider, do not include a WebApplicationListener
     * as well.</b></p>
     * <p>This class relies on the new functionality from Servlet 2.4 API
     * (Tomcat 5.*).</p>
     *..uthor <a href="mailto:scott@smartblob.com">Scott McClure</a>
     */
    public class DataContextProvider extends WebApplicationListener
        implements ServletRequestListener {
        protected static ThreadLocal dataContext = new ThreadLocal();
        /*
        * <p>Given a request, get the DataContext from the Session, and bind the
        * DataContext to the thread.</p>
        */
        public void requestInitialized(ServletRequestEvent sre) {
            ServletRequest req = sre.getServletRequest();

            if (req instanceof HttpServletRequest) {
                HttpSession session = ((HttpServletRequest) req).getSession();
                DataContext dc = (DataContext) session.getAttribute(BasicServletConfiguration.DATA_CONTEXT_KEY);
                if (dc != null) {
                    dataContext.set(dc);
            } else {
                    throw IllegalStateException (
                            "DataContext is null for the session, cannot bind to thread.");
            }
            }
        }

        /*
        * Remove the reference to the DataContext from the thread.
        */
        public void requestDestroyed(ServletRequestEvent sre) {
            //Prevent lingering object references
            dataContext.set(null);
        }

            /*
            * <p>Return the DataContext for this request.</p>
            * <p><b>ONLY CALL THIS METHOD FROM WITHIN THE CONTEXT OF A REQUEST!</b></p>
            *..eturns the DataContext associated with this thread.
            */
        public static DataContext getDataContext() {
            DataContext dc = (DataContext) dataContext.get();

            if (sess == null) {
                throw new IllegalStateException (
                    "DataContextProvider.get() has been called outside the thread associated with a servlet request.");
            }

            return sess;
        }
    }



    This archive was generated by hypermail 2.0.0 : Wed Jun 30 2004 - 15:59:35 EDT