blob: 9144562f177ec92a4410c0247cb27b381766c340 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jxpath.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathContextFactory;
import org.apache.commons.jxpath.JXPathIntrospector;
/**
* Static methods that allocate and cache JXPathContexts bound to
* {@link PageContext}, {@link ServletRequest}, {@link HttpSession}
* and {@link ServletContext}.
* <p>
* The {@link JXPathContext} returned by {@link #getPageContext getPageContext()}
* provides access to all scopes via the PageContext.findAttribute()
* method. Thus, an expression like "foo" will first look for the attribute
* named "foo" in the "page" context, then the "request" context, then
* the "session" one and finally in the "application" context.
* <p>
* If you need to limit the attibute lookup to just one scope, you can use the
* pre-definded variables "page", "request", "session" and "application".
* For example, the expression "$session/foo" extracts the value of the
* session attribute named "foo".
* <p>
* Following are some implementation details. There is a separate JXPathContext
* for each of the four scopes. These contexts are chained according to the
* nesting of the scopes. So, the parent of the "page" JXPathContext is a
* "request" JXPathContext, whose parent is a "session" JXPathContext (that is
* if there is a session), whose parent is an "application" context.
* <p>
* The XPath context node for each context is the corresponding object:
* PageContext, ServletRequest, HttpSession or ServletContext. This feature can
* be used by servlets. A servlet can use one of the methods declared by this
* class and work with a specific JXPathContext for any scope.
* <p>
* Since JXPath chains lookups for variables and extension functions, variables
* and extension function declared in the outer scopes are also available in
* the inner scopes.
* <p>
* Each of the four context declares exactly one variable, the value of which
* is the corresponding object: PageContext, etc.
* <p>
* The "session" variable will be undefined if there is no session for this
* servlet. JXPath does not automatically create sessions.
*
* @author Dmitri Plotnikov
* @version $Revision$ $Date$
*/
public final class JXPathServletContexts {
private static JXPathContextFactory factory;
static {
JXPathIntrospector.registerDynamicClass(
PageScopeContext.class,
PageScopeContextHandler.class);
JXPathIntrospector.registerDynamicClass(
PageContext.class,
PageContextHandler.class);
JXPathIntrospector.registerDynamicClass(
ServletContext.class,
ServletContextHandler.class);
JXPathIntrospector.registerDynamicClass(
ServletRequestAndContext.class,
ServletRequestHandler.class);
JXPathIntrospector.registerDynamicClass(
HttpSessionAndServletContext.class,
HttpSessionHandler.class);
factory = JXPathContextFactory.newInstance();
}
/**
* Returns a JXPathContext bound to the "page" scope. Caches that context
* within the PageContext itself.
* @param pageContext as described
* @return JXPathContext
*/
public static JXPathContext getPageContext(PageContext pageContext) {
JXPathContext context =
(JXPathContext) pageContext.getAttribute(Constants.JXPATH_CONTEXT);
if (context == null) {
JXPathContext parentContext =
getRequestContext(
pageContext.getRequest(),
pageContext.getServletContext());
context = factory.newContext(parentContext, pageContext);
context.setVariables(
new KeywordVariables(
Constants.PAGE_SCOPE,
new PageScopeContext(pageContext)));
pageContext.setAttribute(Constants.JXPATH_CONTEXT, context);
}
return context;
}
/**
* Returns a JXPathContext bound to the "request" scope. Caches that context
* within the request itself.
* @param request as described
* @param servletContext operative
* @return JXPathContext
*/
public static JXPathContext getRequestContext(ServletRequest request,
ServletContext servletContext) {
JXPathContext context =
(JXPathContext) request.getAttribute(Constants.JXPATH_CONTEXT);
// If we are in an included JSP or Servlet, the request parameter
// will represent the included URL, but the JXPathContext we have
// just acquired will represent the outer request.
if (context != null) {
ServletRequestAndContext handle =
(ServletRequestAndContext) context.getContextBean();
if (handle.getServletRequest() == request) {
return context;
}
}
JXPathContext parentContext = null;
if (request instanceof HttpServletRequest) {
HttpSession session =
((HttpServletRequest) request).getSession(false);
if (session != null) {
parentContext = getSessionContext(session, servletContext);
}
else {
parentContext = getApplicationContext(servletContext);
}
}
ServletRequestAndContext handle =
new ServletRequestAndContext(request, servletContext);
context = factory.newContext(parentContext, handle);
context.setVariables(
new KeywordVariables(Constants.REQUEST_SCOPE, handle));
request.setAttribute(Constants.JXPATH_CONTEXT, context);
return context;
}
/**
* Returns a JXPathContext bound to the "session" scope. Caches that context
* within the session itself.
* @param session as described
* @param servletContext operative
* @return JXPathContext
*/
public static JXPathContext getSessionContext(HttpSession session,
ServletContext servletContext) {
JXPathContext context =
(JXPathContext) session.getAttribute(Constants.JXPATH_CONTEXT);
if (context == null) {
JXPathContext parentContext = getApplicationContext(servletContext);
HttpSessionAndServletContext handle =
new HttpSessionAndServletContext(session, servletContext);
context = factory.newContext(parentContext, handle);
context.setVariables(
new KeywordVariables(Constants.SESSION_SCOPE, handle));
session.setAttribute(Constants.JXPATH_CONTEXT, context);
}
return context;
}
/**
* Returns a JXPathContext bound to the "application" scope. Caches that
* context within the servlet context itself.
* @param servletContext operative
* @return JXPathContext
*/
public static JXPathContext getApplicationContext(
ServletContext servletContext) {
JXPathContext context =
(JXPathContext) servletContext.getAttribute(
Constants.JXPATH_CONTEXT);
if (context == null) {
context = factory.newContext(null, servletContext);
context.setVariables(
new KeywordVariables(
Constants.APPLICATION_SCOPE,
servletContext));
servletContext.setAttribute(Constants.JXPATH_CONTEXT, context);
}
return context;
}
}