/* * Copyright 2010-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 com.springsource.greenhouse.config; import java.util.List; import javax.inject.Inject; import org.joda.time.DateTimeZone; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.core.MethodParameter; import org.springframework.core.env.Environment; import org.springframework.format.datetime.joda.JodaTimeContextHolder; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; import org.springframework.mobile.device.DeviceResolverHandlerInterceptor; import org.springframework.security.core.Authentication; import org.springframework.social.facebook.web.FacebookHandlerMethodArgumentResolver; import org.springframework.social.mobile.device.DeviceHandlerMethodArgumentResolver; import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.UrlBasedViewResolver; import org.springframework.web.servlet.view.tiles2.TilesConfigurer; import org.springframework.web.servlet.view.tiles2.TilesView; import com.springsource.greenhouse.account.Account; import com.springsource.greenhouse.home.DateTimeZoneHandlerInterceptor; import com.springsource.greenhouse.home.UserLocationHandlerInterceptor; import com.springsource.greenhouse.signin.AccountExposingHandlerInterceptor; import com.springsource.greenhouse.utils.Location; /** * Spring MVC Configuration. * Implements {@link WebMvcConfigurer}, which provides convenient callbacks that allow us to customize aspects of the Spring Web MVC framework. * These callbacks allow us to register custom interceptors, message converters, argument resovlers, a validator, resource handling, and other things. * @author Keith Donald * @see WebMvcConfigurer */ @Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Inject private Environment environment; // implementing WebMvcConfigurer public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AccountExposingHandlerInterceptor()); registry.addInterceptor(new DateTimeZoneHandlerInterceptor()); registry.addInterceptor(new UserLocationHandlerInterceptor()); registry.addInterceptor(new DeviceResolverHandlerInterceptor()); } public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new AccountHandlerMethodArgumentResolver()); argumentResolvers.add(new DateTimeZoneHandlerMethodArgumentResolver()); argumentResolvers.add(new LocationHandlerMethodArgumentResolver()); argumentResolvers.add(new FacebookHandlerMethodArgumentResolver(environment.getProperty("facebook.appId"), environment.getProperty("facebook.appSecret"))); argumentResolvers.add(new DeviceHandlerMethodArgumentResolver()); } public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); } public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new MappingJacksonHttpMessageConverter()); } public Validator getValidator() { LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean(); ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasename("/WEB-INF/messages/validation"); if (environment.acceptsProfiles("embedded")) { messageSource.setCacheSeconds(0); } factory.setValidationMessageSource(messageSource); return factory; } // additional webmvc-related beans /** * ViewResolver configuration required to work with Tiles2-based views. */ @Bean public ViewResolver viewResolver() { UrlBasedViewResolver viewResolver = new UrlBasedViewResolver(); viewResolver.setViewClass(TilesView.class); return viewResolver; } /** * Configures Tiles at application startup. */ @Bean public TilesConfigurer tilesConfigurer() { TilesConfigurer configurer = new TilesConfigurer(); configurer.setDefinitions(new String[] { "/WEB-INF/layouts/tiles.xml", "/WEB-INF/views/**/tiles.xml" }); configurer.setCheckRefresh(true); return configurer; } /** * Messages to support internationalization/localization. */ @Bean public MessageSource messageSource() { ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasename("/WEB-INF/messages/messages"); if (environment.acceptsProfiles("embedded")) { messageSource.setCacheSeconds(0); } return messageSource; } /** * Supports FileUploads. */ @Bean public MultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setMaxUploadSize(500000); return multipartResolver; } // custom argument resolver inner classes private static class AccountHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { public boolean supportsParameter(MethodParameter parameter) { return Account.class.isAssignableFrom(parameter.getParameterType()); } public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Authentication auth = (Authentication) webRequest.getUserPrincipal(); return auth != null && auth.getPrincipal() instanceof Account ? auth.getPrincipal() : null; } } private static class DateTimeZoneHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { public boolean supportsParameter(MethodParameter parameter) { return DateTimeZone.class.isAssignableFrom(parameter.getParameterType()); } public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return JodaTimeContextHolder.getJodaTimeContext().getTimeZone(); } } private static class LocationHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { public boolean supportsParameter(MethodParameter parameter) { return Location.class.isAssignableFrom(parameter.getParameterType()); } public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return webRequest.getAttribute(UserLocationHandlerInterceptor.USER_LOCATION_ATTRIBUTE, WebRequest.SCOPE_REQUEST); } } }