package net.petrikainulainen.springdata.jpa.config; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import net.petrikainulainen.springdata.jpa.common.AuditingDateTimeProvider; import net.petrikainulainen.springdata.jpa.common.DateTimeService; import net.petrikainulainen.springdata.jpa.common.UsernameAuditorAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.data.auditing.DateTimeProvider; import org.springframework.data.domain.AuditorAware; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.Properties; /** * This configuration class configures the persistence layer of our example application and * enables annotation driven transaction management. * * This configuration is put to a single class because this way we can write integration * tests for our persistence layer by using the configuration used by our example * application. In other words, we can ensure that the persistence layer of our application * works as expected. * * @author Petri Kainulainen */ @Configuration @EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider") @EnableJpaRepositories(basePackages = { "net.petrikainulainen.springdata.jpa.todo" }) @EnableTransactionManagement @EnableSpringDataWebSupport class PersistenceContext { private static final String[] ENTITY_PACKAGES = { "net.petrikainulainen.springdata.jpa.todo" }; private static final String PROPERTY_NAME_DB_DRIVER_CLASS = "db.driver"; private static final String PROPERTY_NAME_DB_PASSWORD = "db.password"; private static final String PROPERTY_NAME_DB_URL = "db.url"; private static final String PROPERTY_NAME_DB_USER = "db.username"; private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect"; private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql"; private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto"; private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy"; private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql"; @Bean AuditorAware<String> auditorProvider() { return new UsernameAuditorAware(); } @Bean DateTimeProvider dateTimeProvider(DateTimeService dateTimeService) { return new AuditingDateTimeProvider(dateTimeService); } /** * Creates and configures the HikariCP datasource bean. * @param env The runtime environment of our application. * @return */ @Bean(destroyMethod = "close") DataSource dataSource(Environment env) { HikariConfig dataSourceConfig = new HikariConfig(); dataSourceConfig.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DB_DRIVER_CLASS)); dataSourceConfig.setJdbcUrl(env.getRequiredProperty(PROPERTY_NAME_DB_URL)); dataSourceConfig.setUsername(env.getRequiredProperty(PROPERTY_NAME_DB_USER)); dataSourceConfig.setPassword(env.getRequiredProperty(PROPERTY_NAME_DB_PASSWORD)); return new HikariDataSource(dataSourceConfig); } /** * Creates the bean that creates the JPA entity manager factory. * @param dataSource The datasource that provides the database connections. * @param env The runtime environment of our application. * @return */ @Bean LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, Environment env) { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource); entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); entityManagerFactoryBean.setPackagesToScan(ENTITY_PACKAGES); Properties jpaProperties = new Properties(); //Configures the used database dialect. This allows Hibernate to create SQL //that is optimized for the used database. jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT)); //Specifies the action that is invoked to the database when the Hibernate //SessionFactory is created or closed. jpaProperties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO)); //Configures the naming strategy that is used when Hibernate creates //new database objects and schema elements jpaProperties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY)); //If the value of this property is true, Hibernate writes all SQL //statements to the console. jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL)); //If the value of this property is true, Hibernate will use prettyprint //when it writes SQL to the console. jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL)); entityManagerFactoryBean.setJpaProperties(jpaProperties); return entityManagerFactoryBean; } /** * Creates the transaction manager bean that integrates the used JPA provider with the * Spring transaction mechanism. * @param entityManagerFactory The used JPA entity manager factory. * @return */ @Bean JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; } }