/**
* Copyright 2013 the original author or authors.
* <p/>
* Licensed 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 io.neba.core.web;
import org.apache.sling.bgservlets.BackgroundHttpServletRequest;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.filter.RequestContextFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.springframework.util.ClassUtils.isPresent;
/**
* A modified {@link RequestContextFilter} wrapping
* {@link org.apache.sling.bgservlets.BackgroundHttpServletRequest sling background requests}
* using the {@link BackgroundServletRequestWrapper} to prevent
* {@link UnsupportedOperationException unsupported operation exceptions} when
* {@link ServletRequestAttributes#requestCompleted()} attempts to access the
* {@link HttpServletRequest#getSession() session}, which is unsupported by
* {@link BackgroundHttpServletRequest background requests}.
*
* @author Olaf Otto
* @see RequestContextFilter
*/
public class NebaRequestContextFilter extends RequestContextFilter {
private static final boolean IS_BGSERVLETS_PRESENT = isPresent(
"org.apache.sling.bgservlets.BackgroundHttpServletRequest",
NebaRequestContextFilter.class.getClassLoader());
private boolean threadContextInheritable = false;
/**
* Set whether to expose the LocaleContext and RequestAttributes as inheritable
* for child threads (using an {@link java.lang.InheritableThreadLocal}).
* <p>Default is "false", to avoid side effects on spawned background threads.
* Switch this to "true" to enable inheritance for custom child threads which
* are spawned during request processing and only used for this request
* (that is, ending after their initial task, without reuse of the thread).
* <p><b>WARNING:</b> Do not use inheritance for child threads if you are
* accessing a thread pool which is configured to potentially add new threads
* on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}),
* since this will expose the inherited context to such a pooled thread.
*/
public void setThreadContextInheritable(boolean threadContextInheritable) {
this.threadContextInheritable = threadContextInheritable;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ServletRequestAttributes attributes = createServletRequestAttributes(request);
initContextHolders(request, attributes);
try {
filterChain.doFilter(request, response);
} finally {
resetContextHolders();
if (logger.isDebugEnabled()) {
logger.debug("Cleared thread-bound request context: " + request);
}
attributes.requestCompleted();
}
}
private ServletRequestAttributes createServletRequestAttributes(HttpServletRequest request) {
if (IS_BGSERVLETS_PRESENT && request instanceof BackgroundHttpServletRequest) {
return new ServletRequestAttributes(new BackgroundServletRequestWrapper(request));
}
return new ServletRequestAttributes(request);
}
private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {
LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
if (logger.isDebugEnabled()) {
logger.debug("Bound request context to thread: " + request);
}
}
private void resetContextHolders() {
LocaleContextHolder.resetLocaleContext();
RequestContextHolder.resetRequestAttributes();
}
}