package org.rosenvold.spring.convention.scope; import org.rosenvold.spring.convention.ConventionContextLoader; import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver; import org.springframework.beans.factory.support.AutowireCandidateResolver; import org.springframework.context.ApplicationContext; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.support.GenericApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpSession; import org.springframework.test.context.ContextCacheKey; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextListener; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.HashMap; import java.util.Locale; import java.util.Map; /** * Context loader that adds the capability of adding request and session-scoped beans that * may run outside the web container. * */ public class MockSessionScopeContextLoader extends ConventionContextLoader { private static final Map<ContextCacheKey, LocalAttrs> ATTR_CACHE = new HashMap<ContextCacheKey, LocalAttrs>(); /** * Activates a scope="session" in the beanfactory allowing us to register and retrieve session-scoped * beans in the context. Spring 2.5 * * @param context the parent scope */ protected void customizeContext(final GenericApplicationContext context) { configureSessionInfrastructure(); final TestSessionScope testSessionScope = new TestSessionScope(); context.getBeanFactory().registerScope("session", testSessionScope); final TestRequestScope requestScope = new TestRequestScope(); context.getBeanFactory().registerScope("request", requestScope); } @Override protected void prepareContext(GenericApplicationContext context) { super.prepareContext(context); } /** * Activates a scope="session" in the beanfactory allowing us to register and retrieve session-scoped * beans in the context. Spring 3.0 adapted * * @param context the parent scope */ protected void customizeContext(final GenericApplicationContext context, final ContextCacheKey cacheKey) { customizeContext(context); final LocalAttrs value = new LocalAttrs(RequestContextHolder.getRequestAttributes(), LocaleContextHolder.getLocale()); synchronized (ATTR_CACHE) { ATTR_CACHE.put(cacheKey, value); } } public void activateForThread(final ApplicationContext applicationContext, final ContextCacheKey key) { synchronized (ATTR_CACHE) { final LocalAttrs localAttrs = ATTR_CACHE.get(key); // We are in a later thread/invocation. Need to set up spring context for this thread. if (localAttrs == null) { System.out.println("You cannot call this method before getApplicationContext, faking it ?"); return; } LocaleContextHolder.setLocale(localAttrs.getLocale(), true); RequestContextHolder.setRequestAttributes(localAttrs.getCopyOfRequestAttributes(), true); } } /** * Configures the necessary session-infrastructure needed to provide SessionScope. */ private void configureSessionInfrastructure() { initRequest(); } private static void initRequest() { final AlwaysOpenMockHttpServletRequest request = new AlwaysOpenMockHttpServletRequest(); request.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11"); MyRequestContextListener.initRequest(request); } static class AlwaysOpenMockHttpServletRequest extends MockHttpServletRequest { private HttpSession session; @Override public HttpSession getSession(boolean create) { if (session == null && create) { session = new MockHttpSession(); } return session; } @Override public String getContextPath() { return null; } @Override public void close() { } } public static void requestStarted() { final ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); //requestAttributes.requestCompleted(); initRequest(); } public static void requestCompleted() { final ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); //requestAttributes.requestCompleted(); } private static final String REQUEST_ATTRIBUTES_ATTRIBUTE = RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES"; static class LocalAttrs { private final RequestAttributes requestAttributes; private final Locale locale; LocalAttrs(final RequestAttributes requestAttributes, final Locale locale) { this.requestAttributes = requestAttributes; this.locale = locale; } public RequestAttributes getCopyOfRequestAttributes() { if (requestAttributes instanceof ServletRequestAttributes) { final ServletRequestAttributes original = (ServletRequestAttributes) requestAttributes; ServletRequestAttributes result; HttpServletRequest nextRequest; if (original.getRequest() instanceof MockHttpServletRequest) { // Mock request, just clone it. nextRequest = new MockHttpServletRequest(); // Maybe need to clone. } else { nextRequest = original.getRequest(); } result = new ServletRequestAttributes(nextRequest); nextRequest.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, original.getRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE)); return result; } return requestAttributes; // Maybe } public Locale getLocale() { return locale; } } }