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