/** * Copyright © 2014 Instituto Superior Técnico * * This file is part of Bennu Spring. * * Bennu Spring is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Bennu Spring is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Bennu Spring. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.bennu.spring; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.fenixedu.bennu.core.util.CoreConfiguration; import org.fenixedu.bennu.core.util.CoreConfiguration.ConfigurationProperties; import org.fenixedu.bennu.spring.converters.LocalizedStringConverter; import org.fenixedu.bennu.spring.converters.UserFromUsernameConverter; import org.fenixedu.bennu.spring.portal.PortalHandlerInterceptor; import org.fenixedu.bennu.spring.portal.PortalHandlerMapping; import org.fenixedu.bennu.spring.resolvers.AuthenticatedUserArgumentResolver; import org.fenixedu.bennu.spring.resolvers.BennuSpringExceptionResolver; import org.fenixedu.bennu.spring.security.CSRFInterceptor; import org.fenixedu.bennu.spring.security.CSRFTokenRepository; import org.fenixedu.commons.i18n.I18N; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.core.annotation.Order; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.support.StandardServletMultipartResolver; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @ComponentScan("org.fenixedu.bennu") public class BennuSpringConfiguration extends WebMvcConfigurationSupport implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(BennuSpringConfiguration.class); @Bean public ConfigurationProperties bennuCoreConfiguration() { return CoreConfiguration.getConfiguration(); } @Bean public ViewResolver getViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(JstlView.class); resolver.setExposeContextBeansAsAttributes(true); resolver.setPrefix("/WEB-INF/"); resolver.setSuffix(".jsp"); resolver.setOrder(1_000_000); return resolver; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CSRFInterceptor(csrfTokenRepository())); registry.addInterceptor(new PortalHandlerInterceptor()); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Bean public MessageSource messageSource(ApplicationContext context) { ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource(); source.setDefaultEncoding("UTF-8"); final String[] baseNames = getBaseNames(context).toArray(new String[0]); logger.debug("Adding basenames by @BennuSpringModule configuration: {}", Arrays.toString(baseNames)); source.setBasenames(baseNames); // Reload resources only when in development mode source.setCacheSeconds(bennuCoreConfiguration().developmentMode() ? 1 : -1); // Allow using the message code as the message itself, as it is preferable // to have an interface without a proper label, than one that doesn't work at all source.setUseCodeAsDefaultMessage(true); return source; } @Bean @Order public CSRFTokenRepository csrfTokenRepository() { return new CSRFTokenRepository(); } private Set<String> getBaseNames(ApplicationContext context) { final Set<String> baseNames = new HashSet<>(); baseNames.add(getBundleBasename("BennuSpringResources")); final String[] beanNames = context.getBeanNamesForAnnotation(BennuSpringModule.class); for (String beanName : beanNames) { BennuSpringModule bennuSpringModuleAnnotation = context.findAnnotationOnBean(beanName, BennuSpringModule.class); if (bennuSpringModuleAnnotation != null) { baseNames.addAll(Arrays.stream(bennuSpringModuleAnnotation.bundles()).map(this::getBundleBasename) .collect(Collectors.toSet())); } } return baseNames; } private String getBundleBasename(String bundle) { return "/WEB-INF/resources/" + bundle; } @Bean public I18NBean i18n(MessageSource messageSource) { return new I18NBean(messageSource); } @Bean public LocaleResolver localeResolver() { return new LocaleResolver() { @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { I18N.setLocale(request.getSession(), locale); } @Override public Locale resolveLocale(HttpServletRequest request) { return I18N.getLocale(); } }; } @Override public PortalHandlerMapping requestMappingHandlerMapping() { PortalHandlerMapping handlerMapping = new PortalHandlerMapping(); handlerMapping.setOrder(0); handlerMapping.setInterceptors(getInterceptors()); handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager()); return handlerMapping; } @Bean public ConversionService conversionService(GenericConversionService service) { service.addConverter(new DomainObjectConverter()); service.addConverter(new LocalizedStringConverter()); service.addConverter(new UserFromUsernameConverter()); return service; } @Bean public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } @Override public void afterPropertiesSet() throws Exception { // This is required to add the resolver as first on the list List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(); resolvers.add(new AuthenticatedUserArgumentResolver()); resolvers.addAll(requestMappingHandlerAdapter().getArgumentResolvers()); requestMappingHandlerAdapter().setArgumentResolvers(resolvers); } @Override protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { exceptionResolvers.add(new BennuSpringExceptionResolver()); addDefaultHandlerExceptionResolvers(exceptionResolvers); } }