package am.ik.categolj2.config; import am.ik.categolj2.api.MediaTypeResolver; import am.ik.categolj2.core.message.MessageKeys; import am.ik.categolj2.core.web.cors.CrossOriginFilter; import am.ik.categolj2.core.web.logging.TraceRequestLoggingFilter; import am.ik.categolj2.domain.model.EntryFormat; import am.ik.categolj2.infra.codelist.EnumCodeList; import am.ik.categolj2.infra.dozer.LazyInitDozerMapper; import ch.qos.logback.classic.Level; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; import com.fasterxml.jackson.datatype.joda.JodaModule; import org.apache.http.client.HttpClient; import org.apache.http.conn.ssl.AllowAllHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.HttpClientBuilder; import org.dozer.Mapper; import org.dozer.spring.DozerBeanMapperFactoryBean; import org.springframework.aop.Advisor; import org.springframework.aop.aspectj.AspectJExpressionPointcut; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.beans.TypeMismatchException; import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourceArrayPropertyEditor; import org.springframework.dao.DataAccessException; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.dao.PessimisticLockingFailureException; import org.springframework.http.MediaType; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.validation.BindException; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.client.RestTemplate; import org.terasoluna.gfw.common.codelist.CodeList; import org.terasoluna.gfw.common.codelist.SimpleMapCodeList; import org.terasoluna.gfw.common.date.DateFactory; import org.terasoluna.gfw.common.date.DefaultDateFactory; import org.terasoluna.gfw.common.exception.*; import org.terasoluna.gfw.web.exception.ExceptionLoggingFilter; import org.terasoluna.gfw.web.exception.HandlerExceptionResolverLoggingInterceptor; import org.terasoluna.gfw.web.logging.mdc.MDCClearFilter; import org.terasoluna.gfw.web.logging.mdc.XTrackMDCPutFilter; import javax.net.ssl.SSLContext; import java.util.LinkedHashMap; @Configuration @EnableAsync public class AppConfig { @Bean Mapper dozerBeanMapper(ApplicationContext applicationContext) throws Exception { return new LazyInitDozerMapper(($) -> { DozerBeanMapperFactoryBean factoryBean = new DozerBeanMapperFactoryBean(); ResourceArrayPropertyEditor editor = new ResourceArrayPropertyEditor(); editor.setAsText("classpath*:/dozer/**/*.xml"); factoryBean.setMappingFiles((Resource[]) editor.getValue()); factoryBean.setApplicationContext(applicationContext); try { factoryBean.afterPropertiesSet(); return factoryBean.getObject(); } catch (Exception e) { e.printStackTrace(); throw new IllegalStateException(e); } }); } @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean RestTemplate restTemplate() throws Exception { SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build(); SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier()); HttpClient httpClient = HttpClientBuilder.create() .setSSLSocketFactory(connectionFactory) .build(); return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient)); } // // @Bean // Jackson2ObjectMapperFactoryBean objectMapper() { // Jackson2ObjectMapperFactoryBean factoryBean = new Jackson2ObjectMapperFactoryBean(); // ObjectMapper objectMapper = new ObjectMapper(); // factoryBean.setObjectMapper(objectMapper); // factoryBean.setSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); // return factoryBean; // } @Bean ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // customize objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); objectMapper.registerModule(new JodaModule()); return objectMapper; } @Bean DateFactory dateFactory() { return new DefaultDateFactory(); } @Bean ExceptionCodeResolver exceptionCodeResolver() { SimpleMappingExceptionCodeResolver exceptionCodeResolver = new SimpleMappingExceptionCodeResolver(); exceptionCodeResolver.setDefaultExceptionCode(MessageKeys.E_CT_FW_9001); exceptionCodeResolver.setExceptionMappings(new LinkedHashMap<String, String>() {{ put(ResourceNotFoundException.class.getSimpleName(), MessageKeys.E_CT_FW_5001); put(HttpRequestMethodNotSupportedException.class.getSimpleName(), MessageKeys.E_CT_FW_6001); put(HttpMediaTypeNotAcceptableException.class.getSimpleName(), MessageKeys.E_CT_FW_6002); put(HttpMediaTypeNotSupportedException.class.getSimpleName(), MessageKeys.E_CT_FW_6003); put(MethodArgumentNotValidException.class.getSimpleName(), MessageKeys.E_CT_FW_7001); put(BindException.class.getSimpleName(), MessageKeys.E_CT_FW_7002); put(JsonParseException.class.getSimpleName(), MessageKeys.E_CT_FW_7003); put(UnrecognizedPropertyException.class.getSimpleName(), MessageKeys.E_CT_FW_7004); put(TypeMismatchException.class.getSimpleName(), MessageKeys.E_CT_FW_7006); put(BusinessException.class.getSimpleName(), MessageKeys.E_CT_FW_8001); put(OptimisticLockingFailureException.class.getSimpleName(), MessageKeys.E_CT_FW_8002); put(PessimisticLockingFailureException.class.getSimpleName(), MessageKeys.E_CT_FW_8002); put(DataAccessException.class.getSimpleName(), MessageKeys.E_CT_FW_9002); }}); return exceptionCodeResolver; } @Bean MediaTypeResolver mediaTypeResolver() { MediaTypeResolver mediaTypeResolver = new MediaTypeResolver(new LinkedHashMap<String, MediaType>() {{ put("json", MediaType.APPLICATION_JSON); put("xml", MediaType.APPLICATION_XML); put("gif", MediaType.IMAGE_GIF); put("jpeg", MediaType.IMAGE_JPEG); put("jpg", MediaType.IMAGE_JPEG); put("png", MediaType.IMAGE_PNG); put("html", MediaType.TEXT_HTML); put("text", MediaType.TEXT_PLAIN); put("xhtml", MediaType.TEXT_XML); }}); mediaTypeResolver.setFallbackMediaType(MediaType.APPLICATION_OCTET_STREAM); return mediaTypeResolver; } @Bean Advisor resultMessagesLoggingAdvisor() { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("@within(org.springframework.stereotype.Service)"); ResultMessagesLoggingInterceptor interceptor = new ResultMessagesLoggingInterceptor(); interceptor.setExceptionLogger(exceptionLogger()); return new DefaultPointcutAdvisor(pointcut, interceptor); } @Bean Advisor handlerExceptionResolverLoggingAdvisor() { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* org.springframework.web.servlet.HandlerExceptionResolver.resolveException(..))"); HandlerExceptionResolverLoggingInterceptor interceptor = new HandlerExceptionResolverLoggingInterceptor(); interceptor.setExceptionLogger(exceptionLogger()); return new DefaultPointcutAdvisor(pointcut, interceptor); } @Bean ExceptionLogger exceptionLogger() { ExceptionLogger exceptionLogger = new ExceptionLogger(); exceptionLogger.setExceptionCodeResolver(exceptionCodeResolver()); return exceptionLogger; } @Bean ExceptionLoggingFilter exceptionLoggingFilter() { ExceptionLoggingFilter exceptionLoggingFilter = new ExceptionLoggingFilter(); exceptionLoggingFilter.setExceptionLogger(exceptionLogger()); return exceptionLoggingFilter; } // @Bean // SystemExceptionResolver systemExceptionResolver() { // SystemExceptionResolver systemExceptionResolver = new SystemExceptionResolver(); // systemExceptionResolver.setExceptionCodeResolver(exceptionCodeResolver()); // systemExceptionResolver.setOrder(3); // systemExceptionResolver.setExceptionMappings(new Properties() {{ // put("ResourceNotFoundException", "common/error/resourceNotFoundError"); // put("BusinessException", "common/error/businessError"); // put("InvalidTransactionTokenException", "common/error/transactionTokenError"); // put(".DataAccessException", "common/error/dataAccessError"); // }}); // systemExceptionResolver.setStatusCodes(new Properties() {{ // put("common/error/resourceNotFoundError", "404"); // put("common/error/businessError", "409"); // put("common/error/transactionTokenError", "409"); // put("common/error/dataAccessError", "500"); // }}); // systemExceptionResolver.setDefaultErrorView("common/error/systemError"); // systemExceptionResolver.setDefaultStatusCode(500); // return systemExceptionResolver; // } @Order(Ordered.HIGHEST_PRECEDENCE + 3) @Bean XTrackMDCPutFilter xTrackMDCPutFilter() { return new XTrackMDCPutFilter(); } @Order(Ordered.HIGHEST_PRECEDENCE + 2) @Bean MDCClearFilter mdcClearFilter() { return new MDCClearFilter(); } @Order(Ordered.HIGHEST_PRECEDENCE) @Bean TraceRequestLoggingFilter loggingFilter() { TraceRequestLoggingFilter filter = new TraceRequestLoggingFilter(); filter.setIncludeClientInfo(true); return filter; } @Bean FilterRegistrationBean crossOriginFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new CrossOriginFilter()); filterRegistrationBean.addUrlPatterns( "/api/v1/*", "/management/*"); return filterRegistrationBean; } // Codelist @Bean(name = "CL_FORMAT") CodeList formatCodeList() { EnumCodeList codeList = new EnumCodeList(); codeList.setEnumClass(EntryFormat.class); return codeList; } @Bean(name = "CL_LOGGER_LEVEL") CodeList loggerLevelCodeList() { SimpleMapCodeList codeList = new SimpleMapCodeList(); codeList.setMap(new LinkedHashMap<String, String>() {{ put(Level.OFF.toString(), Level.OFF.toString()); put(Level.ERROR.toString(), Level.ERROR.toString()); put(Level.WARN.toString(), Level.WARN.toString()); put(Level.INFO.toString(), Level.INFO.toString()); put(Level.DEBUG.toString(), Level.DEBUG.toString()); put(Level.TRACE.toString(), Level.TRACE.toString()); }}); return codeList; } }