package io.kaif.config;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import freemarker.template.TemplateModelException;
import io.kaif.service.AccountService;
import io.kaif.service.ClientAppService;
import io.kaif.web.AccountAccessTokenArgumentResolver;
import io.kaif.web.support.RelativeTime;
import io.kaif.web.v1.ClientAppUserAccessTokenArgumentResolver;
@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Autowired
private AccountService accountService;
@Autowired
private ClientAppService clientAppService;
@Autowired
private freemarker.template.Configuration freeMarkerConfiguration;
@Autowired
private Environment environment;
@Autowired
private AppProperties appProperties;
@Autowired
private ResourceBundleMessageSource messageSource;
/**
* add module Java 8 Time and AfterBurner in class path
*/
@SuppressWarnings("unchecked")
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder().modulesToInstall(AfterburnerModule.class);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//spring-boot already include `/webjars/**` and `/**` for all static resources
// and it also apply cache header if spring.resources.cache-period property exist.
// so in production, following resources are cached:
//
// /favicon.ico
// /robots.txt
// /webjars/**
// /build-2015..../**
// ...etc
//
// below are source code of WebMvcAutoConfiguration:
//
// registry.addResourceHandler("/webjars/**")
// .addResourceLocations("classpath:/META-INF/resources/webjars/")
// .setCachePeriod(cachePeriod);
// registry.addResourceHandler("/**")
// .addResourceLocations(RESOURCE_LOCATIONS)
// .setCachePeriod(cachePeriod);
// note that to override spring boot default favicon.ico, we must put it in classpath, not
// /webapp/ folder
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AccountAccessTokenArgumentResolver(accountService));
argumentResolvers.add(new ClientAppUserAccessTokenArgumentResolver(clientAppService));
}
// change locale only enable in dev mode, see {@link #addInterceptors}
@Profile(SpringProfile.DEV)
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setCookieName("kaif-locale");
localeResolver.setDefaultLocale(Locale.TAIWAN);
return localeResolver;
}
@Profile(SpringProfile.DEV)
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("kaif-locale");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (environment.acceptsProfiles(SpringProfile.DEV)) {
//currently we only allow change locale in dev mode for debug
registry.addInterceptor(localeChangeInterceptor());
}
}
@PostConstruct
public void init() throws TemplateModelException {
configureFreeMarker();
// default is true, which fallback to system locale, so if
// system locale is jp. fallback bundle file will be messages_jp.properties, not
// messages.properties. This behavior is not what we want. so disable it.
messageSource.setFallbackToSystemLocale(false);
}
private void configureFreeMarker() throws TemplateModelException {
Map<String, Object> variables = new HashMap<>();
variables.put("profilesActive",
Arrays.stream(environment.getActiveProfiles()).collect(Collectors.joining(",")));
freeMarkerConfiguration.setSharedVariable("kaif", variables);
freeMarkerConfiguration.setSharedVariable("relativeTime", new RelativeTime());
}
}