Author: ate
Date: Fri Jul 6 21:26:41 2012
New Revision: 1358430
URL: http://svn.apache.org/viewvc?rev=1358430&view=rev
Log:
RAVE-698: add a temporarily forked version of Spring
RequestMappingHandlerAdapter.
The original Spring provided version of this class has a final protected
handleInternal method as well as a private invokeHandlerMethod method.
Those two restrictions make it impossible to extend the class for our purposes.
The temporary forked version has these two methods 'hacked' open, e.g. now
provided as non-final protected methods instead.
The HmvcHandlerMethodHandlerAdapter now can extend this minimally modified
forked version to build up our own logic.
When/once everything works as needed a patch for the original Spring
RequestMappingHandlerAdapter can be created and proposed for Springframework
so to be able to extend the original in the future and drop the temporary
forked class.
Added:
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java
(with props)
Added:
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java
URL:
http://svn.apache.org/viewvc/rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java?rev=1358430&view=auto
==============================================================================
---
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java
(added)
+++
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java
Fri Jul 6 21:26:41 2012
@@ -0,0 +1,719 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.springframework.web.servlet.mvc.method.annotation;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.xml.transform.Source;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.http.converter.ByteArrayHttpMessageConverter;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.xml.SourceHttpMessageConverter;
+import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
+import org.springframework.ui.ModelMap;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ReflectionUtils.MethodFilter;
+import org.springframework.web.bind.annotation.InitBinder;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.support.DefaultDataBinderFactory;
+import org.springframework.web.bind.support.DefaultSessionAttributeStore;
+import org.springframework.web.bind.support.SessionAttributeStore;
+import org.springframework.web.bind.support.WebBindingInitializer;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.method.HandlerMethodSelector;
+import org.springframework.web.method.annotation.ErrorsMethodArgumentResolver;
+import org.springframework.web.method.annotation.MapMethodProcessor;
+import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
+import org.springframework.web.method.annotation.ModelFactory;
+import org.springframework.web.method.annotation.ModelMethodProcessor;
+import
org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver;
+import
org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver;
+import org.springframework.web.method.annotation.SessionAttributesHandler;
+import
org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver;
+import
org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
+import
org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
+import
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
+import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
+import
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
+import org.springframework.web.method.support.InvocableHandlerMethod;
+import org.springframework.web.method.support.ModelAndViewContainer;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
+import org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import org.springframework.web.servlet.support.RequestContextUtils;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
+ * with the signature -- method argument and return types, defined in
+ * {@code @RequestMapping}.
+ *
+ * <p>Support for custom argument and return value types can be added via
+ * {@link #setCustomArgumentResolvers} and {@link
#setCustomReturnValueHandlers}.
+ * Or alternatively to re-configure all argument and return value types use
+ * {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ * @see HandlerMethodArgumentResolver
+ * @see HandlerMethodReturnValueHandler
+ */
+public class ForkedRequestMappingHandlerAdapter extends
AbstractHandlerMethodAdapter implements BeanFactoryAware,
+ InitializingBean {
+
+ private List<HandlerMethodArgumentResolver> customArgumentResolvers;
+
+ private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
+
+ private List<ModelAndViewResolver> modelAndViewResolvers;
+
+ private List<HttpMessageConverter<?>> messageConverters;
+
+ private WebBindingInitializer webBindingInitializer;
+
+ private int cacheSecondsForSessionAttributeHandlers = 0;
+
+ private boolean synchronizeOnSession = false;
+
+ private ParameterNameDiscoverer parameterNameDiscoverer = new
LocalVariableTableParameterNameDiscoverer();
+
+ private ConfigurableBeanFactory beanFactory;
+
+ private SessionAttributeStore sessionAttributeStore = new
DefaultSessionAttributeStore();
+
+ private boolean ignoreDefaultModelOnRedirect = false;
+
+ private final Map<Class<?>, SessionAttributesHandler>
sessionAttributesHandlerCache =
+ new ConcurrentHashMap<Class<?>, SessionAttributesHandler>();
+
+ private HandlerMethodArgumentResolverComposite argumentResolvers;
+
+ private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
+
+ private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
+
+ private final Map<Class<?>, Set<Method>> dataBinderFactoryCache = new
ConcurrentHashMap<Class<?>, Set<Method>>();
+
+ private final Map<Class<?>, Set<Method>> modelFactoryCache = new
ConcurrentHashMap<Class<?>, Set<Method>>();
+
+ /**
+ * Default constructor.
+ */
+ public ForkedRequestMappingHandlerAdapter() {
+
+ StringHttpMessageConverter stringHttpMessageConverter = new
StringHttpMessageConverter();
+ stringHttpMessageConverter.setWriteAcceptCharset(false); // See
SPR-7316
+
+ this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
+ this.messageConverters.add(new ByteArrayHttpMessageConverter());
+ this.messageConverters.add(stringHttpMessageConverter);
+ this.messageConverters.add(new SourceHttpMessageConverter<Source>());
+ this.messageConverters.add(new XmlAwareFormHttpMessageConverter());
+ }
+
+ /**
+ * Provide resolvers for custom argument types. Custom resolvers are
ordered
+ * after built-in ones. To override the built-in support for argument
+ * resolution use {@link #setArgumentResolvers} instead.
+ */
+ public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver>
argumentResolvers) {
+ this.customArgumentResolvers = argumentResolvers;
+ }
+
+ /**
+ * Return the custom argument resolvers, or {@code null}.
+ */
+ public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
+ return this.customArgumentResolvers;
+ }
+
+ /**
+ * Configure the complete list of supported argument types thus overriding
+ * the resolvers that would otherwise be configured by default.
+ */
+ public void setArgumentResolvers(List<HandlerMethodArgumentResolver>
argumentResolvers) {
+ if (argumentResolvers == null) {
+ this.argumentResolvers = null;
+ }
+ else {
+ this.argumentResolvers = new
HandlerMethodArgumentResolverComposite();
+ this.argumentResolvers.addResolvers(argumentResolvers);
+ }
+ }
+
+ /**
+ * Return the configured argument resolvers, or possibly {@code null} if
+ * not initialized yet via {@link #afterPropertiesSet()}.
+ */
+ public HandlerMethodArgumentResolverComposite getArgumentResolvers() {
+ return this.argumentResolvers;
+ }
+
+ /**
+ * Configure the supported argument types in {@code @InitBinder} methods.
+ */
+ public void
setInitBinderArgumentResolvers(List<HandlerMethodArgumentResolver>
argumentResolvers) {
+ if (argumentResolvers == null) {
+ this.initBinderArgumentResolvers = null;
+ }
+ else {
+ this.initBinderArgumentResolvers = new
HandlerMethodArgumentResolverComposite();
+ this.initBinderArgumentResolvers.addResolvers(argumentResolvers);
+ }
+ }
+
+ /**
+ * Return the argument resolvers for {@code @InitBinder} methods, or
possibly
+ * {@code null} if not initialized yet via {@link #afterPropertiesSet()}.
+ */
+ public HandlerMethodArgumentResolverComposite
getInitBinderArgumentResolvers() {
+ return this.initBinderArgumentResolvers;
+ }
+
+ /**
+ * Provide handlers for custom return value types. Custom handlers are
+ * ordered after built-in ones. To override the built-in support for
+ * return value handling use {@link #setReturnValueHandlers}.
+ */
+ public void
setCustomReturnValueHandlers(List<HandlerMethodReturnValueHandler>
returnValueHandlers) {
+ this.customReturnValueHandlers = returnValueHandlers;
+ }
+
+ /**
+ * Return the custom return value handlers, or {@code null}.
+ */
+ public List<HandlerMethodReturnValueHandler>
getCustomReturnValueHandlers() {
+ return this.customReturnValueHandlers;
+ }
+
+ /**
+ * Configure the complete list of supported return value types thus
+ * overriding handlers that would otherwise be configured by default.
+ */
+ public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler>
returnValueHandlers) {
+ if (returnValueHandlers == null) {
+ this.returnValueHandlers = null;
+ }
+ else {
+ this.returnValueHandlers = new
HandlerMethodReturnValueHandlerComposite();
+ this.returnValueHandlers.addHandlers(returnValueHandlers);
+ }
+ }
+
+ /**
+ * Return the configured handlers, or possibly {@code null} if not
+ * initialized yet via {@link #afterPropertiesSet()}.
+ */
+ public HandlerMethodReturnValueHandlerComposite getReturnValueHandlers() {
+ return this.returnValueHandlers;
+ }
+
+ /**
+ * Provide custom {@link ModelAndViewResolver}s.
+ * <p><strong>Note:</strong> This method is available for backwards
+ * compatibility only. However, it is recommended to re-write a
+ * {@code ModelAndViewResolver} as {@link HandlerMethodReturnValueHandler}.
+ * An adapter between the two interfaces is not possible since the
+ * {@link HandlerMethodReturnValueHandler#supportsReturnType} method
+ * cannot be implemented. Hence {@code ModelAndViewResolver}s are limited
+ * to always being invoked at the end after all other return value
+ * handlers have been given a chance.
+ * <p>A {@code HandlerMethodReturnValueHandler} provides better access to
+ * the return type and controller method information and can be ordered
+ * freely relative to other return value handlers.
+ */
+ public void setModelAndViewResolvers(List<ModelAndViewResolver>
modelAndViewResolvers) {
+ this.modelAndViewResolvers = modelAndViewResolvers;
+ }
+
+ /**
+ * Return the configured {@link ModelAndViewResolver}s, or {@code null}.
+ */
+ public List<ModelAndViewResolver> getModelAndViewResolvers() {
+ return modelAndViewResolvers;
+ }
+
+ /**
+ * Provide the converters to use in argument resolvers and return value
+ * handlers that support reading and/or writing to the body of the
+ * request and response.
+ */
+ public void setMessageConverters(List<HttpMessageConverter<?>>
messageConverters) {
+ this.messageConverters = messageConverters;
+ }
+
+ /**
+ * Return the configured message body converters.
+ */
+ public List<HttpMessageConverter<?>> getMessageConverters() {
+ return messageConverters;
+ }
+
+ /**
+ * Provide a WebBindingInitializer with "global" initialization to apply
+ * to every DataBinder instance.
+ */
+ public void setWebBindingInitializer(WebBindingInitializer
webBindingInitializer) {
+ this.webBindingInitializer = webBindingInitializer;
+ }
+
+ /**
+ * Return the configured WebBindingInitializer, or {@code null}.
+ */
+ public WebBindingInitializer getWebBindingInitializer() {
+ return webBindingInitializer;
+ }
+
+ /**
+ * Specify the strategy to store session attributes with. The default is
+ * {@link
org.springframework.web.bind.support.DefaultSessionAttributeStore},
+ * storing session attributes in the HttpSession with the same attribute
+ * name as in the model.
+ */
+ public void setSessionAttributeStore(SessionAttributeStore
sessionAttributeStore) {
+ this.sessionAttributeStore = sessionAttributeStore;
+ }
+
+ /**
+ * Cache content produced by <code>@SessionAttributes</code> annotated
handlers
+ * for the given number of seconds. Default is 0, preventing caching
completely.
+ * <p>In contrast to the "cacheSeconds" property which will apply to all
general
+ * handlers (but not to <code>@SessionAttributes</code> annotated
handlers),
+ * this setting will apply to <code>@SessionAttributes</code> handlers
only.
+ * @see #setCacheSeconds
+ * @see org.springframework.web.bind.annotation.SessionAttributes
+ */
+ public void setCacheSecondsForSessionAttributeHandlers(int
cacheSecondsForSessionAttributeHandlers) {
+ this.cacheSecondsForSessionAttributeHandlers =
cacheSecondsForSessionAttributeHandlers;
+ }
+
+ /**
+ * Set if controller execution should be synchronized on the session,
+ * to serialize parallel invocations from the same client.
+ * <p>More specifically, the execution of the
<code>handleRequestInternal</code>
+ * method will get synchronized if this flag is "true". The best available
+ * session mutex will be used for the synchronization; ideally, this will
+ * be a mutex exposed by HttpSessionMutexListener.
+ * <p>The session mutex is guaranteed to be the same object during
+ * the entire lifetime of the session, available under the key defined
+ * by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a
+ * safe reference to synchronize on for locking on the current session.
+ * <p>In many cases, the HttpSession reference itself is a safe mutex
+ * as well, since it will always be the same object reference for the
+ * same active logical session. However, this is not guaranteed across
+ * different servlet containers; the only 100% safe way is a session mutex.
+ * @see org.springframework.web.util.HttpSessionMutexListener
+ * @see
org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
+ */
+ public void setSynchronizeOnSession(boolean synchronizeOnSession) {
+ this.synchronizeOnSession = synchronizeOnSession;
+ }
+
+ /**
+ * Set the ParameterNameDiscoverer to use for resolving method parameter
+ * names if needed (e.g. for default attribute names). Default is a
+ * {@link
org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
+ */
+ public void setParameterNameDiscoverer(ParameterNameDiscoverer
parameterNameDiscoverer) {
+ this.parameterNameDiscoverer = parameterNameDiscoverer;
+ }
+
+ /**
+ * By default the content of the "default" model is used both during
+ * rendering and redirect scenarios. Alternatively a controller method
+ * can declare a {@link RedirectAttributes} argument and use it to provide
+ * attributes for a redirect.
+ * <p>Setting this flag to {@code true} guarantees the "default" model is
+ * never used in a redirect scenario even if a RedirectAttributes argument
+ * is not declared. Setting it to {@code false} means the "default" model
+ * may be used in a redirect if the controller method doesn't declare a
+ * RedirectAttributes argument.
+ * <p>The default setting is {@code false} but new applications should
+ * consider setting it to {@code true}.
+ * @see RedirectAttributes
+ */
+ public void setIgnoreDefaultModelOnRedirect(boolean
ignoreDefaultModelOnRedirect) {
+ this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>A {@link ConfigurableBeanFactory} is expected for resolving
+ * expressions in method argument default values.
+ */
+ public void setBeanFactory(BeanFactory beanFactory) {
+ if (beanFactory instanceof ConfigurableBeanFactory) {
+ this.beanFactory = (ConfigurableBeanFactory) beanFactory;
+ }
+ }
+
+ /**
+ * Return the owning factory of this bean instance, or {@code null}.
+ */
+ protected ConfigurableBeanFactory getBeanFactory() {
+ return this.beanFactory;
+ }
+
+ public void afterPropertiesSet() {
+ if (this.argumentResolvers == null) {
+ List<HandlerMethodArgumentResolver> resolvers =
getDefaultArgumentResolvers();
+ this.argumentResolvers = new
HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
+ }
+ if (this.initBinderArgumentResolvers == null) {
+ List<HandlerMethodArgumentResolver> resolvers =
getDefaultInitBinderArgumentResolvers();
+ this.initBinderArgumentResolvers = new
HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
+ }
+ if (this.returnValueHandlers == null) {
+ List<HandlerMethodReturnValueHandler> handlers =
getDefaultReturnValueHandlers();
+ this.returnValueHandlers = new
HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
+ }
+ }
+
+ /**
+ * Return the list of argument resolvers to use including built-in
resolvers
+ * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
+ */
+ private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
+ List<HandlerMethodArgumentResolver> resolvers = new
ArrayList<HandlerMethodArgumentResolver>();
+
+ // Annotation-based argument resolution
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(),
false));
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver());
+ resolvers.add(new ServletModelAttributeMethodProcessor(false));
+ resolvers.add(new
RequestResponseBodyMethodProcessor(getMessageConverters()));
+ resolvers.add(new
RequestPartMethodArgumentResolver(getMessageConverters()));
+ resolvers.add(new
RequestHeaderMethodArgumentResolver(getBeanFactory()));
+ resolvers.add(new RequestHeaderMapMethodArgumentResolver());
+ resolvers.add(new
ServletCookieValueMethodArgumentResolver(getBeanFactory()));
+ resolvers.add(new
ExpressionValueMethodArgumentResolver(getBeanFactory()));
+
+ // Type-based argument resolution
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+ resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
+ resolvers.add(new RedirectAttributesMethodArgumentResolver());
+ resolvers.add(new ModelMethodProcessor());
+ resolvers.add(new MapMethodProcessor());
+ resolvers.add(new ErrorsMethodArgumentResolver());
+ resolvers.add(new SessionStatusMethodArgumentResolver());
+ resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
+
+ // Custom arguments
+ if (getCustomArgumentResolvers() != null) {
+ resolvers.addAll(getCustomArgumentResolvers());
+ }
+
+ // Catch-all
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(),
true));
+ resolvers.add(new ServletModelAttributeMethodProcessor(true));
+
+ return resolvers;
+ }
+
+ /**
+ * Return the list of argument resolvers to use for {@code @InitBinder}
+ * methods including built-in and custom resolvers.
+ */
+ private List<HandlerMethodArgumentResolver>
getDefaultInitBinderArgumentResolvers() {
+ List<HandlerMethodArgumentResolver> resolvers = new
ArrayList<HandlerMethodArgumentResolver>();
+
+ // Annotation-based argument resolution
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(),
false));
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver());
+ resolvers.add(new
ExpressionValueMethodArgumentResolver(getBeanFactory()));
+
+ // Type-based argument resolution
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+
+ // Custom arguments
+ if (getCustomArgumentResolvers() != null) {
+ resolvers.addAll(getCustomArgumentResolvers());
+ }
+
+ // Catch-all
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(),
true));
+
+ return resolvers;
+ }
+
+ /**
+ * Return the list of return value handlers to use including built-in and
+ * custom handlers provided via {@link #setReturnValueHandlers}.
+ */
+ private List<HandlerMethodReturnValueHandler>
getDefaultReturnValueHandlers() {
+ List<HandlerMethodReturnValueHandler> handlers = new
ArrayList<HandlerMethodReturnValueHandler>();
+
+ // Single-purpose return value types
+ handlers.add(new ModelAndViewMethodReturnValueHandler());
+ handlers.add(new ModelMethodProcessor());
+ handlers.add(new ViewMethodReturnValueHandler());
+ handlers.add(new HttpEntityMethodProcessor(getMessageConverters()));
+
+ // Annotation-based return value types
+ handlers.add(new ModelAttributeMethodProcessor(false));
+ handlers.add(new
RequestResponseBodyMethodProcessor(getMessageConverters()));
+
+ // Multi-purpose return value types
+ handlers.add(new ViewNameMethodReturnValueHandler());
+ handlers.add(new MapMethodProcessor());
+
+ // Custom return value types
+ if (getCustomReturnValueHandlers() != null) {
+ handlers.addAll(getCustomReturnValueHandlers());
+ }
+
+ // Catch-all
+ if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
+ handlers.add(new
ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
+ }
+ else {
+ handlers.add(new ModelAttributeMethodProcessor(true));
+ }
+
+ return handlers;
+ }
+
+ /**
+ * Return {@code true} if all arguments and the return value of the given
+ * HandlerMethod are supported by the configured resolvers and handlers.
+ */
+ @Override
+ protected boolean supportsInternal(HandlerMethod handlerMethod) {
+ return supportsMethodParameters(handlerMethod.getMethodParameters()) &&
+ supportsReturnType(handlerMethod.getReturnType());
+ }
+
+ private boolean supportsMethodParameters(MethodParameter[]
methodParameters) {
+ for (MethodParameter methodParameter : methodParameters) {
+ if (! this.argumentResolvers.supportsParameter(methodParameter)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean supportsReturnType(MethodParameter methodReturnType) {
+ return (this.returnValueHandlers.supportsReturnType(methodReturnType)
||
+ Void.TYPE.equals(methodReturnType.getParameterType()));
+ }
+
+ /**
+ * This implementation always returns -1. An {@code @RequestMapping}
+ * method can calculate the lastModified value, call
+ * {@link WebRequest#checkNotModified(long)}, and return {@code null}
+ * if the result of that call is {@code true}.
+ */
+ @Override
+ protected long getLastModifiedInternal(HttpServletRequest request,
HandlerMethod handlerMethod) {
+ return -1;
+ }
+
+ @Override
+ protected ModelAndView handleInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ HandlerMethod handlerMethod)
throws Exception {
+
+ if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes())
{
+ // Always prevent caching in case of session attribute management.
+ checkAndPrepare(request, response,
this.cacheSecondsForSessionAttributeHandlers, true);
+ }
+ else {
+ // Uses configured default cacheSeconds setting.
+ checkAndPrepare(request, response, true);
+ }
+
+ // Execute invokeHandlerMethod in synchronized block if required.
+ if (this.synchronizeOnSession) {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ Object mutex = WebUtils.getSessionMutex(session);
+ synchronized (mutex) {
+ return invokeHandlerMethod(request, response,
handlerMethod);
+ }
+ }
+ }
+
+ return invokeHandlerMethod(request, response, handlerMethod);
+ }
+
+ /**
+ * Return the {@link SessionAttributesHandler} instance for the given
+ * handler type, never {@code null}.
+ */
+ private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod
handlerMethod) {
+ Class<?> handlerType = handlerMethod.getBeanType();
+ SessionAttributesHandler sessionAttrHandler =
this.sessionAttributesHandlerCache.get(handlerType);
+ if (sessionAttrHandler == null) {
+ synchronized(this.sessionAttributesHandlerCache) {
+ sessionAttrHandler =
this.sessionAttributesHandlerCache.get(handlerType);
+ if (sessionAttrHandler == null) {
+ sessionAttrHandler = new
SessionAttributesHandler(handlerType, sessionAttributeStore);
+ this.sessionAttributesHandlerCache.put(handlerType,
sessionAttrHandler);
+ }
+ }
+ }
+ return sessionAttrHandler;
+ }
+
+ /**
+ * Invoke the {@link RequestMapping} handler method preparing a {@link
ModelAndView} if view resolution is required.
+ */
+ protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response,
+ HandlerMethod handlerMethod) throws Exception {
+
+ ServletWebRequest webRequest = new ServletWebRequest(request,
response);
+
+ WebDataBinderFactory binderFactory =
getDataBinderFactory(handlerMethod);
+ ModelFactory modelFactory = getModelFactory(handlerMethod,
binderFactory);
+ ServletInvocableHandlerMethod requestMappingMethod =
createRequestMappingMethod(handlerMethod, binderFactory);
+
+ ModelAndViewContainer mavContainer = new ModelAndViewContainer();
+
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
+ modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
+
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
+
+ requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
+ modelFactory.updateModel(webRequest, mavContainer);
+
+ if (mavContainer.isRequestHandled()) {
+ return null;
+ }
+ else {
+ ModelMap model = mavContainer.getModel();
+ ModelAndView mav = new ModelAndView(mavContainer.getViewName(),
model);
+ if (!mavContainer.isViewReference()) {
+ mav.setView((View) mavContainer.getView());
+ }
+ if (model instanceof RedirectAttributes) {
+ Map<String, ?> flashAttributes = ((RedirectAttributes)
model).getFlashAttributes();
+
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
+ }
+ return mav;
+ }
+ }
+
+ private ServletInvocableHandlerMethod
createRequestMappingMethod(HandlerMethod handlerMethod,
+
WebDataBinderFactory binderFactory) {
+ ServletInvocableHandlerMethod requestMethod;
+ requestMethod = new
ServletInvocableHandlerMethod(handlerMethod.getBean(),
handlerMethod.getMethod());
+
requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
+
requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
+ requestMethod.setDataBinderFactory(binderFactory);
+ requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
+ return requestMethod;
+ }
+
+ private ModelFactory getModelFactory(HandlerMethod handlerMethod,
WebDataBinderFactory binderFactory) {
+ SessionAttributesHandler sessionAttrHandler =
getSessionAttributesHandler(handlerMethod);
+ Class<?> handlerType = handlerMethod.getBeanType();
+ Set<Method> methods = this.modelFactoryCache.get(handlerType);
+ if (methods == null) {
+ methods = HandlerMethodSelector.selectMethods(handlerType,
MODEL_ATTRIBUTE_METHODS);
+ this.modelFactoryCache.put(handlerType, methods);
+ }
+ List<InvocableHandlerMethod> attrMethods = new
ArrayList<InvocableHandlerMethod>();
+ for (Method method : methods) {
+ InvocableHandlerMethod attrMethod = new
InvocableHandlerMethod(handlerMethod.getBean(), method);
+
attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
+
attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
+ attrMethod.setDataBinderFactory(binderFactory);
+ attrMethods.add(attrMethod);
+ }
+ return new ModelFactory(attrMethods, binderFactory,
sessionAttrHandler);
+ }
+
+ private WebDataBinderFactory getDataBinderFactory(HandlerMethod
handlerMethod) throws Exception {
+ Class<?> handlerType = handlerMethod.getBeanType();
+ Set<Method> methods = this.dataBinderFactoryCache.get(handlerType);
+ if (methods == null) {
+ methods = HandlerMethodSelector.selectMethods(handlerType,
INIT_BINDER_METHODS);
+ this.dataBinderFactoryCache.put(handlerType, methods);
+ }
+ List<InvocableHandlerMethod> binderMethods = new
ArrayList<InvocableHandlerMethod>();
+ for (Method method : methods) {
+ InvocableHandlerMethod binderMethod = new
InvocableHandlerMethod(handlerMethod.getBean(), method);
+
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
+ binderMethod.setDataBinderFactory(new
DefaultDataBinderFactory(this.webBindingInitializer));
+
binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
+ binderMethods.add(binderMethod);
+ }
+ return createDataBinderFactory(binderMethods);
+ }
+
+ /**
+ * Template method to create a new ServletRequestDataBinderFactory
instance.
+ * <p>The default implementation creates a ServletRequestDataBinderFactory.
+ * This can be overridden for custom ServletRequestDataBinder subclasses.
+ * @param binderMethods {@code @InitBinder} methods
+ * @return the ServletRequestDataBinderFactory instance to use
+ * @throws Exception in case of invalid state or arguments
+ */
+ protected ServletRequestDataBinderFactory
createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
+ throws Exception {
+ return new ServletRequestDataBinderFactory(binderMethods,
getWebBindingInitializer());
+ }
+
+ /**
+ * MethodFilter that matches {@link InitBinder @InitBinder} methods.
+ */
+ public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() {
+
+ public boolean matches(Method method) {
+ return AnnotationUtils.findAnnotation(method, InitBinder.class) !=
null;
+ }
+ };
+
+ /**
+ * MethodFilter that matches {@link ModelAttribute @ModelAttribute}
methods.
+ */
+ public static final MethodFilter MODEL_ATTRIBUTE_METHODS = new
MethodFilter() {
+
+ public boolean matches(Method method) {
+ return ((AnnotationUtils.findAnnotation(method,
RequestMapping.class) == null) &&
+ (AnnotationUtils.findAnnotation(method,
ModelAttribute.class) != null));
+ }
+ };
+
+}
\ No newline at end of file
Propchange:
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ForkedRequestMappingHandlerAdapter.java
------------------------------------------------------------------------------
svn:keywords = Id