package org.javers.spring.boot.sql; import org.hibernate.SessionFactory; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.javers.core.Javers; import org.javers.core.MappingStyle; import org.javers.core.diff.ListCompareAlgorithm; import org.javers.hibernate.integration.HibernateUnproxyObjectAccessHook; import org.javers.repository.sql.ConnectionProvider; import org.javers.repository.sql.DialectName; import org.javers.repository.sql.JaversSqlRepository; import org.javers.repository.sql.SqlRepositoryBuilder; import org.javers.spring.auditable.AuthorProvider; import org.javers.spring.auditable.CommitPropertiesProvider; import org.javers.spring.auditable.EmptyPropertiesProvider; import org.javers.spring.auditable.MockAuthorProvider; import org.javers.spring.auditable.SpringSecurityAuthorProvider; import org.javers.spring.auditable.aspect.JaversAuditableAspect; import org.javers.spring.auditable.aspect.springdata.JaversSpringDataAuditableRepositoryAspect; import org.javers.spring.jpa.JpaHibernateConnectionProvider; import org.javers.spring.jpa.TransactionalJaversBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.transaction.PlatformTransactionManager; import javax.persistence.EntityManagerFactory; /** * @author pawelszymczyk */ @Configuration @EnableAspectJAutoProxy @EnableConfigurationProperties(value = {JaversProperties.class, JpaProperties.class}) @AutoConfigureAfter(HibernateJpaAutoConfiguration.class) public class JaversSqlAutoConfiguration { private static final Logger logger = LoggerFactory.getLogger(JaversSqlAutoConfiguration.class); private final DialectMapper dialectMapper = new DialectMapper(); @Autowired private JaversProperties javersProperties; @Autowired private EntityManagerFactory entityManagerFactory; @Bean public DialectName javersSqlDialectName() { SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) entityManagerFactory.unwrap(SessionFactory.class); Dialect hibernateDialect = sessionFactory.getDialect(); logger.info("detected Hibernate dialect: " + hibernateDialect.getClass().getSimpleName()); return dialectMapper.map(hibernateDialect); } @Bean @ConditionalOnMissingBean public JaversSqlRepository javersSqlRepository(ConnectionProvider connectionProvider) { return SqlRepositoryBuilder .sqlRepository() .withConnectionProvider(connectionProvider) .withDialect(javersSqlDialectName()) .build(); } @Bean(name = "javers") @ConditionalOnMissingBean public Javers javers(JaversSqlRepository sqlRepository, PlatformTransactionManager transactionManager) { return TransactionalJaversBuilder .javers() .withTxManager(transactionManager) .registerJaversRepository(sqlRepository) .withObjectAccessHook(new HibernateUnproxyObjectAccessHook()) .withListCompareAlgorithm(ListCompareAlgorithm.valueOf(javersProperties.getAlgorithm().toUpperCase())) .withMappingStyle(MappingStyle.valueOf(javersProperties.getMappingStyle().toUpperCase())) .withNewObjectsSnapshot(javersProperties.isNewObjectSnapshot()) .withPrettyPrint(javersProperties.isPrettyPrint()) .withTypeSafeValues(javersProperties.isTypeSafeValues()) .withPackagesToScan(javersProperties.getPackagesToScan()) .build(); } @Bean(name = "authorProvider") @ConditionalOnMissingBean @ConditionalOnClass(name = {"org.springframework.security.core.context.SecurityContextHolder"}) public AuthorProvider springSecurityAuthorProvider() { return new SpringSecurityAuthorProvider(); } @Bean(name = "authorProvider") @ConditionalOnMissingBean @ConditionalOnMissingClass({"org.springframework.security.core.context.SecurityContextHolder"}) public AuthorProvider unknownAuthorProvider() { return new MockAuthorProvider(); } @Bean(name = "commitPropertiesProvider") @ConditionalOnMissingBean public CommitPropertiesProvider commitPropertiesProvider() { return new EmptyPropertiesProvider(); } @Bean @ConditionalOnMissingBean public ConnectionProvider jpaConnectionProvider() { return new JpaHibernateConnectionProvider(); } @Bean @ConditionalOnProperty(name = "javers.auditableAspectEnabled", havingValue = "true", matchIfMissing = true) public JaversAuditableAspect javersAuditableAspect(Javers javers, AuthorProvider authorProvider) { return new JaversAuditableAspect(javers, authorProvider, commitPropertiesProvider()); } @Bean @ConditionalOnProperty(name = "javers.springDataAuditableRepositoryAspectEnabled", havingValue = "true", matchIfMissing = true) public JaversSpringDataAuditableRepositoryAspect javersSpringDataAuditableAspect(Javers javers, AuthorProvider authorProvider) { return new JaversSpringDataAuditableRepositoryAspect(javers, authorProvider, commitPropertiesProvider()); } }