    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.servlet;
    17
    18  import javax.servlet.ServletContext;
    19  import javax.servlet.ServletRequest;
    20  import javax.servlet.http.HttpServletRequest;
    21  import javax.servlet.http.HttpSession;
    22  import javax.servlet.jsp.PageContext;
    23  import org.apache.commons.jxpath.JXPathContext;
    24  import org.apache.commons.jxpath.JXPathContextFactory;
    25  import org.apache.commons.jxpath.JXPathIntrospector;
    26
    27  /***
    28   * Static methods that allocate and cache JXPathContexts bound to PageContext,
    29   * ServletRequest, HttpSession and ServletContext.
    30   * <p>
    31   * The JXPathContext returned by {@link #getPageContext getPageContext()}
    32   * provides access to all scopes via the PageContext.findAttribute()
    33   * method.  Thus, an expression like "foo" will first look for the attribute
    34   * named "foo" in the "page" context, then the "request" context, then
    35   * the "session" one and finally in the "application" context.
    36   * <p>
    37   * If you need to limit the attibute lookup to just one scope, you can use the
    38   * pre-definded variables "page", "request", "session" and "application".
    39   * For example, the expression "$session/foo" extracts the value of the
    40   * session attribute named "foo".
    41   * <p>
    42   * Following are some implementation details. There is a separate JXPathContext
    43   * for each of the four scopes. These contexts are chained according to the
    44   * nesting of the scopes.  So, the parent of the "page" JXPathContext is a
    45   * "request" JXPathContext, whose parent is a "session" JXPathContext (that is
    46   * if there is a session), whose parent is an "application" context.
    47   * <p>
    48   * The  XPath context node for each context is the corresponding object:
    49   * PageContext, ServletRequest, HttpSession or ServletContext.  This feature can
    50   * be used by servlets.  A servlet can use one of the methods declared by this
    51   * class and work with a specific JXPathContext for any scope.
    52   * <p>
    53   * Since JXPath chains lookups for variables and extension functions, variables
    54   * and extension function declared in the outer scopes are also available in
    55   * the inner scopes.
    56   * <p>
    57   * Each  of the four context declares exactly one variable, the value of which
    58   * is the corresponding object: PageContext, etc.
    59   * <p>
    60   * The  "session" variable will be undefined if there is no session for this
    61   * servlet. JXPath does not automatically create sessions.
    62   *
    63   * @author Dmitri Plotnikov
    64   * @version $Revision: 1.6 $ $Date: 2004/05/08 15:10:49 $
    65   */
    66  public final class JXPathServletContexts {
    67
    68      private static JXPathContextFactory factory;
    69
    70      static {
    71          JXPathIntrospector.registerDynamicClass(
    72                  PageScopeContext.class,
    73                  PageScopeContextHandler.class);
    74          JXPathIntrospector.registerDynamicClass(
    75                  PageContext.class,
    76                  PageContextHandler.class);
    77          JXPathIntrospector.registerDynamicClass(
    78                  ServletContext.class,
    79                  ServletContextHandler.class);
    80          JXPathIntrospector.registerDynamicClass(
    81                  ServletRequestAndContext.class,
    82                  ServletRequestHandler.class);
    83          JXPathIntrospector.registerDynamicClass(
    84                  HttpSessionAndServletContext.class,
    85                  HttpSessionHandler.class);
    86          factory = JXPathContextFactory.newInstance();
    87      }
    88
    89      /***
    90       * Returns a JXPathContext bound to the "page" scope. Caches that context
    91       * within the PageContext itself.
    92       */
    93      public static JXPathContext getPageContext(PageContext pageContext) {
    94          JXPathContext context =
    95              (JXPathContext) pageContext.getAttribute(Constants.JXPATH_CONTEXT);
    96          if (context == null) {
    97              JXPathContext parentContext =
    98                  getRequestContext(
    99                      pageContext.getRequest(),
    100                     pageContext.getServletContext());
    101             context = factory.newContext(parentContext, pageContext);
    102             context.setVariables(
    103                 new KeywordVariables(
    104                     Constants.PAGE_SCOPE,
    105                     new PageScopeContext(pageContext)));
    106             pageContext.setAttribute(Constants.JXPATH_CONTEXT, context);
    107         }
    108         return context;
    109     }
    110
    111     /***
    112      * Returns a JXPathContext bound to the "request" scope. Caches that context
    113      * within the request itself.
    114      */
    115     public static JXPathContext getRequestContext(
    116         ServletRequest request,
    117         ServletContext servletContext)
    118     {
    119         JXPathContext context =
    120             (JXPathContext) request.getAttribute(Constants.JXPATH_CONTEXT);
    121         // If we are in an included JSP or Servlet, the request parameter
    122         // will represent the included URL, but the JXPathContext we have
    123         // just acquired will represent the outer request.
    124         if (context != null) {
    125             ServletRequestAndContext handle =
    126                 (ServletRequestAndContext) context.getContextBean();
    127             if (handle.getServletRequest() == request) {
    128                 return context;
    129             }
    130         }
    131
    132         JXPathContext parentContext = null;
    133         if (request instanceof HttpServletRequest) {
    134             HttpSession session =
    135                 ((HttpServletRequest) request).getSession(false);
    136             if (session != null) {
    137                 parentContext = getSessionContext(session, servletContext);
    138             }
    139             else {
    140                 parentContext = getApplicationContext(servletContext);
    141             }
    142         }
    143         ServletRequestAndContext handle =
    144             new ServletRequestAndContext(request, servletContext);
    145         context = factory.newContext(parentContext, handle);
    146         context.setVariables(
    147             new KeywordVariables(Constants.REQUEST_SCOPE, handle));
    148         request.setAttribute(Constants.JXPATH_CONTEXT, context);
    149         return context;
    150     }
    151
    152     /***
    153      * Returns a JXPathContext bound to the "session" scope. Caches that context
    154      * within the session itself.
    155      */
    156     public static JXPathContext getSessionContext(
    157         HttpSession session,
    158         ServletContext servletContext)
    159     {
    160         JXPathContext context =
    161             (JXPathContext) session.getAttribute(Constants.JXPATH_CONTEXT);
    162         if (context == null) {
    163             JXPathContext parentContext = getApplicationContext(servletContext);
    164             HttpSessionAndServletContext handle =
    165                 new HttpSessionAndServletContext(session, servletContext);
    166             context = factory.newContext(parentContext, handle);
    167             context.setVariables(
    168                 new KeywordVariables(Constants.SESSION_SCOPE, handle));
    169             session.setAttribute(Constants.JXPATH_CONTEXT, context);
    170         }
    171         return context;
    172     }
    173
    174     /***
    175      * Returns  a JXPathContext bound to the "application" scope. Caches that
    176      * context within the servlet context itself.
    177      */
    178     public static JXPathContext getApplicationContext(
    179             ServletContext servletContext)
    180     {
    181         JXPathContext context =
    182             (JXPathContext) servletContext.getAttribute(
    183                 Constants.JXPATH_CONTEXT);
    184         if (context == null) {
    185             context = factory.newContext(null, servletContext);
    186             context.setVariables(
    187                 new KeywordVariables(
    188                     Constants.APPLICATION_SCOPE,
    189                     servletContext));
    190             servletContext.setAttribute(Constants.JXPATH_CONTEXT, context);
    191         }
    192         return context;
    193     }
    194 }