001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.context.request; 018 019import javax.faces.context.FacesContext; 020 021import org.springframework.core.NamedInheritableThreadLocal; 022import org.springframework.core.NamedThreadLocal; 023import org.springframework.util.ClassUtils; 024 025/** 026 * Holder class to expose the web request in the form of a thread-bound 027 * {@link RequestAttributes} object. The request will be inherited 028 * by any child threads spawned by the current thread if the 029 * {@code inheritable} flag is set to {@code true}. 030 * 031 * <p>Use {@link RequestContextListener} or 032 * {@link org.springframework.web.filter.RequestContextFilter} to expose 033 * the current web request. Note that 034 * {@link org.springframework.web.servlet.DispatcherServlet} and 035 * {@link org.springframework.web.portlet.DispatcherPortlet} already 036 * expose the current request by default. 037 * 038 * @author Juergen Hoeller 039 * @author Rod Johnson 040 * @since 2.0 041 * @see RequestContextListener 042 * @see org.springframework.web.filter.RequestContextFilter 043 * @see org.springframework.web.servlet.DispatcherServlet 044 * @see org.springframework.web.portlet.DispatcherPortlet 045 */ 046public abstract class RequestContextHolder { 047 048 private static final boolean jsfPresent = 049 ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader()); 050 051 private static final ThreadLocal<RequestAttributes> requestAttributesHolder = 052 new NamedThreadLocal<RequestAttributes>("Request attributes"); 053 054 private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = 055 new NamedInheritableThreadLocal<RequestAttributes>("Request context"); 056 057 058 /** 059 * Reset the RequestAttributes for the current thread. 060 */ 061 public static void resetRequestAttributes() { 062 requestAttributesHolder.remove(); 063 inheritableRequestAttributesHolder.remove(); 064 } 065 066 /** 067 * Bind the given RequestAttributes to the current thread, 068 * <i>not</i> exposing it as inheritable for child threads. 069 * @param attributes the RequestAttributes to expose 070 * @see #setRequestAttributes(RequestAttributes, boolean) 071 */ 072 public static void setRequestAttributes(RequestAttributes attributes) { 073 setRequestAttributes(attributes, false); 074 } 075 076 /** 077 * Bind the given RequestAttributes to the current thread. 078 * @param attributes the RequestAttributes to expose, 079 * or {@code null} to reset the thread-bound context 080 * @param inheritable whether to expose the RequestAttributes as inheritable 081 * for child threads (using an {@link InheritableThreadLocal}) 082 */ 083 public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) { 084 if (attributes == null) { 085 resetRequestAttributes(); 086 } 087 else { 088 if (inheritable) { 089 inheritableRequestAttributesHolder.set(attributes); 090 requestAttributesHolder.remove(); 091 } 092 else { 093 requestAttributesHolder.set(attributes); 094 inheritableRequestAttributesHolder.remove(); 095 } 096 } 097 } 098 099 /** 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}