View Javadoc
1   /*
2    * Copyright 2002-2012 the original author or authors.
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  
17  package org.springframework.web.context.request;
18  
19  import javax.faces.context.FacesContext;
20  
21  import org.springframework.core.NamedInheritableThreadLocal;
22  import org.springframework.core.NamedThreadLocal;
23  import org.springframework.util.ClassUtils;
24  
25  /**
26   * Holder class to expose the web request in the form of a thread-bound
27   * {@link RequestAttributes} object. The request will be inherited
28   * by any child threads spawned by the current thread if the
29   * {@code inheritable} flag is set to {@code true}.
30   *
31   * <p>Use {@link RequestContextListener} or
32   * {@link org.springframework.web.filter.RequestContextFilter} to expose
33   * the current web request. Note that
34   * {@link org.springframework.web.servlet.DispatcherServlet} and
35   * {@link org.springframework.web.portlet.DispatcherPortlet} already
36   * expose the current request by default.
37   *
38   * @author Juergen Hoeller
39   * @author Rod Johnson
40   * @since 2.0
41   * @see RequestContextListener
42   * @see org.springframework.web.filter.RequestContextFilter
43   * @see org.springframework.web.servlet.DispatcherServlet
44   * @see org.springframework.web.portlet.DispatcherPortlet
45   */
46  public abstract class RequestContextHolder  {
47  
48  	private static final boolean jsfPresent =
49  			ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
50  
51  	private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
52  			new NamedThreadLocal<RequestAttributes>("Request attributes");
53  
54  	private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
55  			new NamedInheritableThreadLocal<RequestAttributes>("Request context");
56  
57  
58  	/**
59  	 * Reset the RequestAttributes for the current thread.
60  	 */
61  	public static void resetRequestAttributes() {
62  		requestAttributesHolder.remove();
63  		inheritableRequestAttributesHolder.remove();
64  	}
65  
66  	/**
67  	 * Bind the given RequestAttributes to the current thread,
68  	 * <i>not</i> exposing it as inheritable for child threads.
69  	 * @param attributes the RequestAttributes to expose
70  	 * @see #setRequestAttributes(RequestAttributes, boolean)
71  	 */
72  	public static void setRequestAttributes(RequestAttributes attributes) {
73  		setRequestAttributes(attributes, false);
74  	}
75  
76  	/**
77  	 * Bind the given RequestAttributes to the current thread.
78  	 * @param attributes the RequestAttributes to expose,
79  	 * or {@code null} to reset the thread-bound context
80  	 * @param inheritable whether to expose the RequestAttributes as inheritable
81  	 * for child threads (using an {@link InheritableThreadLocal})
82  	 */
83  	public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) {
84  		if (attributes == null) {
85  			resetRequestAttributes();
86  		}
87  		else {
88  			if (inheritable) {
89  				inheritableRequestAttributesHolder.set(attributes);
90  				requestAttributesHolder.remove();
91  			}
92  			else {
93  				requestAttributesHolder.set(attributes);
94  				inheritableRequestAttributesHolder.remove();
95  			}
96  		}
97  	}
98  
99  	/**
100 	 * Return the RequestAttributes currently bound to the thread.
101 	 * @return the RequestAttributes currently bound to the thread,
102 	 * or {@code null} if none bound
103 	 */
104 	public static RequestAttributes getRequestAttributes() {
105 		RequestAttributes attributes = requestAttributesHolder.get();
106 		if (attributes == null) {
107 			attributes = inheritableRequestAttributesHolder.get();
108 		}
109 		return attributes;
110 	}
111 
112 	/**
113 	 * Return the RequestAttributes currently bound to the thread.
114 	 * <p>Exposes the previously bound RequestAttributes instance, if any.
115 	 * Falls back to the current JSF FacesContext, if any.
116 	 * @return the RequestAttributes currently bound to the thread
117 	 * @throws IllegalStateException if no RequestAttributes object
118 	 * is bound to the current thread
119 	 * @see #setRequestAttributes
120 	 * @see ServletRequestAttributes
121 	 * @see FacesRequestAttributes
122 	 * @see javax.faces.context.FacesContext#getCurrentInstance()
123 	 */
124 	public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
125 		RequestAttributes attributes = getRequestAttributes();
126 		if (attributes == null) {
127 			if (jsfPresent) {
128 				attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();
129 			}
130 			if (attributes == null) {
131 				throw new IllegalStateException("No thread-bound request found: " +
132 						"Are you referring to request attributes outside of an actual web request, " +
133 						"or processing a request outside of the originally receiving thread? " +
134 						"If you are actually operating within a web request and still receive this message, " +
135 						"your code is probably running outside of DispatcherServlet/DispatcherPortlet: " +
136 						"In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
137 			}
138 		}
139 		return attributes;
140 	}
141 
142 
143 	/**
144 	 * Inner class to avoid hard-coded JSF dependency.
145  	 */
146 	private static class FacesRequestAttributesFactory {
147 
148 		public static RequestAttributes getFacesRequestAttributes() {
149 			FacesContext facesContext = FacesContext.getCurrentInstance();
150 			return (facesContext != null ? new FacesRequestAttributes(facesContext) : null);
151 		}
152 	}
153 
154 }