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