Save This Page
Home » jdo2-util-2.3-ea-src » org.apache.jdo.util.web » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software 
   12    * distributed under the License is distributed on an "AS IS" BASIS, 
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
   14    * See the License for the specific language governing permissions and 
   15    * limitations under the License.
   16    */
   17   package org.apache.jdo.util.web;
   18   
   19   import java.io.InputStream;
   20   import java.io.IOException;
   21   
   22   import javax.jdo.JDOHelper;
   23   import javax.jdo.PersistenceManagerFactory;
   24   import javax.jdo.PersistenceManager;
   25   
   26   import javax.servlet.Filter;
   27   import javax.servlet.FilterChain;
   28   import javax.servlet.FilterConfig;
   29   import javax.servlet.ServletContext;
   30   import javax.servlet.ServletException;
   31   import javax.servlet.ServletRequest;
   32   import javax.servlet.ServletResponse;
   33   
   34   import org.apache.commons.logging.Log;
   35   import org.apache.commons.logging.LogFactory;
   36   
   37   /** 
   38    * This implementation of the servlet Filter interface creates a JDO 
   39    * PersistenceManager, stores it as a request attribute and as a ThreadLocal. 
   40    * It closes the PersistenceManager after the filter chain has returned.
   41    * The idea for this class is taken from the JavaOne 2003 presentation 
   42    * "Using Struts with Java Data Objects" by Craig Russell, Craig McClanahan
   43    * and Amy Roh.
   44    * <p>
   45    * To setup the filter add the following to your deployment descriptor:
   46    * <pre>
   47    * &lt;filter&gt;
   48    *     &lt;filter-name&gt;JDOFilter&lt;/filter-name&gt;
   49    *     &lt;filter-class&gt;org.apache.jdo.util.web.JDOFilter&lt;/filter-class&gt;
   50    * &lt;/filter&gt;
   51    * &lt;filter-mapping&gt;
   52    *     &lt;filter-name&gt;JDOFilter&lt;/filter-name&gt;
   53    *     &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
   54    * &lt;/filter-mapping&gt;
   55    * </pre>
   56    * The JDOFilter supports two filter initialization paramters:
   57    * <ul>
   58    * <li><code>pmfPropsResource</code>: the name of the PersistenceManagerFactory
   59    * properties resource. Default is <code>/WEB-INF/pmf.properties</code>.</li>
   60    * <li><code>pmRequestAttrName</code>: the name of the request attribute used to
   61    * store the PersistenceManager instance. Default is <code>jdoPM</code>.
   62    * </ul>
   63    * This is an sample filter definition using initialization parameter:
   64    * <pre>
   65    * &lt;filter&gt;
   66    *     &lt;filter-name&gt;JDOFilter&lt;/filter-name&gt;
   67    *     &lt;filter-class&gt;org.apache.jdo.util.web.JDOFilter&lt;/filter-class&gt;
   68    *     &lt;init-param&gt;
   69    *         &lt;param-name&gt;pmfPropsResource&lt;/param-name&gt;
   70    *         &lt;param-value&gt;/WEB-INF/pmf.properties&lt;/param-value&gt;
   71    *     &lt;/init-param&gt;
   72    *     &lt;init-param&gt;
   73    *         &lt;param-name&gt;pmRequestAttrName&lt;/param-name&gt;
   74    *         &lt;param-value&gt;jdoPM&lt;/param-value&gt;
   75    *     &lt;/init-param&gt;
   76    * &lt;/filter&gt;
   77    * </pre>
   78    * It is possible to define multiple filters in the deployment descriptor, all 
   79    * using the JDOFilter class. In this case it is important to specify the name 
   80    * of the PersistenceManager request attribute in the filter configuration by 
   81    * setting the pmRequestAttrName initialization paramter. Otherwise, the 
   82    * different filter instances would try to use the same request attribute. 
   83    * Please note, in case of multiple JDOFilter instances, only the first filter 
   84    * stores its PersistenceManager as a ThreadLocal. 
   85    * <p>
   86    * The static method {@link #getThreadLocalPM()} allows retrieving the 
   87    * PersistenceManager instance bound to the current thread.
   88    */
   89   public class JDOFilter
   90       implements Filter  {
   91   
   92       /** The name of the JDOFilter initialization parameter allowing to specify 
   93        * the name of the pmf properties resource. */
   94       public static final String PMF_PROPS_RESOURCE_PARAM = "pmfPropsResource";
   95   
   96       /** The default PMF properties resource. */
   97       public static final String PMF_PROPS_RESOURCE_DEFAULT = 
   98           "/WEB-INF/pmf.properties";
   99       
  100       /** The name of the JDOFilter initialization parameter allowing to specify 
  101        * the name of the pm request attribute.  */
  102       public static final String PM_REQUEST_ATTR_NAME_PARAM = "pmRequestAttrName";
  103       
  104       /** The name of the request attribute storing the PersistenceManager. */
  105       public static final String PM_REQUEST_ATTR_NAME_DEFAULT = "jdoPM";
  106   
  107       /** The ThreadLocal storing the PersistenceManager. */
  108       private static ThreadLocal pmThreadLocal = new ThreadLocal();
  109       
  110       /** Logging support. */
  111       private static final Log logger = LogFactory.getLog(JDOFilter.class);
  112           
  113       /** The PMF instance created by the init method. */
  114       private PersistenceManagerFactory pmf;
  115       
  116       /** The name of the request attribute holding the PersistenceManager. */
  117       private String pmRequestAttrName;
  118           
  119       // ===== javax.servlet.Filter methods =====
  120   
  121       /** Called by the web container to indicate to a filter that it is being 
  122        * placed into service. 
  123        * <p>
  124        * This implementation creates a JDO PersistenceManagerFactory instance 
  125        * using a properties resource specified by an initialization parameter 
  126        * called {@link #PMF_PROPS_RESOURCE_PARAM} or defaulted to 
  127        * {@link #PMF_PROPS_RESOURCE_DEFAULT}. The method checks for another 
  128        * initialization parameter {@link #PM_REQUEST_ATTR_NAME_PARAM} that may be
  129        * used to specify the name of the request attribute holding the 
  130        * PersistenceManager instance. The name defaults to 
  131        * {@link #PM_REQUEST_ATTR_NAME_DEFAULT} if there is no such initialization
  132        * parameter.
  133        * @param filterConfig the filter configuration object. 
  134        */
  135       public void init(FilterConfig filterConfig) throws ServletException {
  136           String pmfPropsResource = 
  137               filterConfig.getInitParameter(PMF_PROPS_RESOURCE_PARAM);
  138           boolean usingPMFPropsResourceDefault = false;
  139           if ((pmfPropsResource == null) || pmfPropsResource.length() == 0) {
  140               pmfPropsResource = PMF_PROPS_RESOURCE_DEFAULT;
  141               usingPMFPropsResourceDefault = true;
  142           }
  143           ServletContext context = filterConfig.getServletContext();
  144           InputStream stream = context.getResourceAsStream(pmfPropsResource);
  145           if (stream == null) {
  146               ServletException ex = new ServletException(
  147                   "Error during initialization of JDOFilter: " + 
  148                   "Cannot find JDO PMF properties resource " +
  149                   (usingPMFPropsResourceDefault ? "defaulted to " : "") +
  150                   pmfPropsResource);
  151               throw ex;
  152           }
  153           pmf = JDOHelper.getPersistenceManagerFactory(stream);
  154           if (logger.isDebugEnabled()) {
  155               logger.debug(
  156                   "Created PMF " + pmf +
  157                   "\nPMF properties: " +
  158                   "\n\t driver         = " + pmf.getConnectionDriverName() + 
  159                   "\n\t URL            = " + pmf.getConnectionURL() + 
  160                   "\n\t userName       = " + pmf.getConnectionUserName() + 
  161                   "\n\t mapping        = " + pmf.getMapping() +
  162                   "\n\t optimistic     = " + pmf.getOptimistic() +
  163                   "\n\t retainValues   = " + pmf.getRetainValues() +
  164                   "\n\t restoreValues  = " + pmf.getRestoreValues() +
  165                   "\n\t nonTxRead      = " + pmf.getNontransactionalRead() +
  166                   "\n\t nonTxWrite     = " + pmf.getNontransactionalWrite() +
  167                   "\n\t ignoreCache    = " + pmf.getIgnoreCache() +
  168                   "\n\t detachOnCommit = " + pmf.getDetachAllOnCommit() +
  169                   "\n\t properties     = " + pmf.getProperties());
  170           }
  171   
  172           // get the name of the request attribute holding the PersistenceManager
  173           pmRequestAttrName = 
  174               filterConfig.getInitParameter(PM_REQUEST_ATTR_NAME_PARAM);
  175           if ((pmRequestAttrName == null) || pmRequestAttrName.length() == 0) {
  176               pmRequestAttrName = PM_REQUEST_ATTR_NAME_DEFAULT;
  177           }
  178       }
  179   
  180       /** The doFilter method of the Filter is called by the container each time a
  181        * request/response pair is passed through the chain due to a client request
  182        * for a resource at the end of the chain. This implementation creates a 
  183        * PersistenceManager, stores it as a request attribute and in a ThreadLocal
  184        * and then calls the filter chain. It closes the PersistenceManager after 
  185        * the chain returns.
  186        * @param request the resquest
  187        * @param response the response 
  188        * @param chain the filter chain   
  189        */
  190       public void doFilter(ServletRequest request, ServletResponse response, 
  191                            FilterChain chain) 
  192           throws IOException, ServletException {
  193           PersistenceManager pm = null;
  194           try {
  195               pm = initializePM(request);
  196               if (logger.isDebugEnabled()) {
  197                   logger.debug("Created PM " + pm);
  198               }
  199               chain.doFilter(request, response);
  200           } finally {
  201               if (logger.isDebugEnabled()) {
  202                   logger.debug("Close PM " + pm);
  203               }
  204               finalizePM(request, pm);
  205           }
  206       }
  207   
  208       /** Called by the web container to indicate to a filter that it is being 
  209        * taken out of service. This implementation closes the 
  210        * PersistenceManagerFactory. 
  211        */
  212       public void destroy() {
  213           if (pmf != null) {
  214               if (logger.isDebugEnabled()) {
  215                   logger.debug("Close PMF " + pmf);
  216               }
  217               pmf.close();
  218               pmf = null;
  219           }
  220       }
  221       
  222       // ===== Public methods not defined in Filter =====
  223       
  224       /** Returns the PersistenceManager instance bound to the current thread 
  225        * using a ThreadLocal. 
  226        * @return the PersistenceManager bound to the current thread.
  227        */
  228       public static PersistenceManager getThreadLocalPM() {
  229            return (PersistenceManager)pmThreadLocal.get();
  230       }
  231       
  232       // ===== Internal helper methods =====
  233   
  234       /** Helper method to create and store a new PersistenceManager. The method 
  235        * stores the PersistenceManager as value of the request attribute denoted 
  236        * by {@link #pmRequestAttrName} and in a ThreadLocal. Use static method
  237        * {@link #getThreadLocalPM()} to retrieve the PersistenceManager instance 
  238        * bound to the current thread.
  239        * @param request the request to store in the PersistenceManager as 
  240        * attribute.
  241        * @return a new PersistenceManager
  242        */
  243       private PersistenceManager initializePM(ServletRequest request) 
  244           throws ServletException {
  245           PersistenceManager pm = pmf.getPersistenceManager();
  246           if (request.getAttribute(pmRequestAttrName) != null) {
  247               ServletException ex = new ServletException(
  248                   "JDOFilter: error during PM intialization, request attribute " +
  249                   pmRequestAttrName + " already defined as " + 
  250                    request.getAttribute(pmRequestAttrName));
  251               throw ex;
  252           }
  253           request.setAttribute(pmRequestAttrName, pm);
  254           if (pmThreadLocal.get() == null) {
  255               pmThreadLocal.set(pm);
  256           }
  257           return pm;
  258       }    
  259   
  260       /** Helper method to finalize a PersistenceManager. The method closes the 
  261        * specified PersistenceManager. If there is an active transaction it is 
  262        * rolled back before the PersistenceManager is closed. The method also 
  263        * removes the request attribute holding a PersistenceManager and nullifies
  264        * the ThreadLocal value, but only if it is the specified 
  265        * PersistenceManager.
  266        * @param request the request holding the PersistenceManager as attribute.
  267        * @param the PersistenceManager
  268        */
  269       private void finalizePM(ServletRequest request, PersistenceManager pm) {
  270           if (pm == null) {
  271               return;
  272           }
  273           if (!pm.isClosed()) {
  274               if (pm.currentTransaction().isActive()) {
  275                   pm.currentTransaction().rollback();
  276               }
  277               pm.close();
  278           }
  279           // Remove request attribute if it is the specified pm
  280           if (request.getAttribute(pmRequestAttrName) == pm) {
  281               request.removeAttribute(pmRequestAttrName);
  282           }
  283           // Nullify the thread local if it is the specified pm
  284           if (pmThreadLocal.get() == pm) {
  285               pmThreadLocal.set(null);
  286           }
  287       }
  288   
  289   }

Save This Page
Home » jdo2-util-2.3-ea-src » org.apache.jdo.util.web » [javadoc | source]