I hope someone can help me with my problem. I write at the moment a Spring MVC Server and a client. Unfortunatly my Rest Controller only returns a 404. I am using a Tomcat 8. What I know is that the Spring Application is deployed correctly because I can visit my index.jsp page. The context, under which it is deployed is /backend. So my base url is localhost:8080/backend. Now I have a restcontroller whitch looks like this.
#Controller
#RequestMapping("/api/developer")
public class DeveloperController {
#Autowired
private DeveloperOutboundDipatcher service;
#RequestMapping(method = RequestMethod.GET, value = "/getAll")
public List<DeveloperDTO> findAll() {
return service.findAllDeveloper();
}
#RequestMapping(method = RequestMethod.GET, value = "/get/{name}")
public DeveloperDTO findByName(#PathVariable String name) {
return service.findOneByName(name);
}
#RequestMapping(method = RequestMethod.DELETE, value = "/delete/{name}")
public void deleteDeveloper(#PathVariable String name) {
service.deleteDeveloper(name);
}
#RequestMapping(method = RequestMethod.POST, value = "/save/")
public void saveDeveloper(#RequestBody DeveloperDTO developer) {
service.save(developer);
}
#RequestMapping(method = RequestMethod.PUT, value = "/edit/")
public void editDeveloper(#RequestBody DeveloperDTO developer) {
service.edit(developer);
}
}
my config class looks like this:
package gamescreation;
#Configuration
#ComponentScan(basePackages= "gamescreation")
#EnableJpaRepositories("gamescreation")
#EnableTransactionManagement
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
#Autowired
Environment environment;
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("gamescreation.entity" );
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibernateProperties());
return em;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource ();
dataSource.setDriverClassName("org.postgresql.Driver");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(
EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
Properties hibernateProperties() {
return new Properties() {
{
setProperty("hibernate.hbm2ddl.auto",
"false");
setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL82Dialect");
setProperty("hibernate.globally_quoted_identifiers",
"true");
}
};
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
#Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setChangeLog("classpath:/db-changelog-master.xml");
liquibase.setDataSource(dataSource());
return liquibase;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
I hope someone can tell me what is missing.
My client class looks like this:
#Service
public class DeveloperService {
private static final String DEVELOPER_BASEURL = "http://localhost:8080/backend/api/developer";
public List<DeveloperDTO> getDeveloperList() {
RestTemplate restTemplate = new RestTemplate();
DeveloperList response = restTemplate.getForObject(DEVELOPER_BASEURL + "/getAll", DeveloperList.class);
return response.getDevelopers();
}
public DeveloperDTO getSelectedDeveloper(String name) {
String url = DEVELOPER_BASEURL + "/get/{name}";
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).queryParam("name", name);
RestTemplate restTemplate = new RestTemplate();
DeveloperDTO response = restTemplate.getForObject(builder.toUriString(), DeveloperDTO.class);
return response;
}
public void delete(String name) {
String url = DEVELOPER_BASEURL + "/delete/{name}";
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).queryParam("name", name);
RestTemplate restTemplate = new RestTemplate();
restTemplate.delete(builder.toUriString());
}
public DeveloperDTO save(DeveloperDTO dto) {
String url = DEVELOPER_BASEURL + "/save";
HttpEntity<DeveloperDTO> request = new HttpEntity<>(dto);
RestTemplate restTemplate = new RestTemplate();
DeveloperDTO response = restTemplate.postForObject(url, request, DeveloperDTO.class);
return response;
}
}
Thank you in advance for your help. If you need any other information from my project, feel free to ask.
#Controller alone will not work please use #Responsebody to get the response in REST or use the #RestController.
Related
I'm not using spring-boot in this app.
I'm testing profiles to use different datasource in integration tests.
I have entity User as follow:
#Table(name = "user_inf")
#Entity
#NamedQuery(name="User.findById", query="select u from User u where u.id=:id")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "userName", length = 25)
private String userName;
#Column(name = "userEmail", unique = true, length = 320)
private String userEmail;
}
for that entity I have the service and dao(Service only invokes dao method)
UserDao :
#Repository
#Transactional
public class UserDaoImpl implements UserDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public User findById(Long id) {
TypedQuery<User> query = entityManager.createNamedQuery("User.findById", User.class);
query.setParameter("id", id);
return query.getSingleResult();
}
}
User service :
#Service
public class UserServiceImpl implements UserService{
#Autowired
private UserDao userDao;
#Override
public User getUser(Long id) {
return userDao.findById(id);
}
}
#Configuration
#PropertySource(value = {"classpath:database/jdbc.properties"})
#EnableTransactionManagement
#ComponentScan({"com.example.test.repository", "com.example.test.service"})
public class SpringConfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
private static final String PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE = "hibernate.jdbc.fetch_size";
private static final String PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE = "hibernate.jdbc.batch_size";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String ENTITY_MANAGER_PACKAGES_TO_SCAN = "com.example.test.entity";
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
#Bean
#Profile("test")
public DataSource dataSourceForTest() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.test.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
#Bean
public PlatformTransactionManager jpaTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
return transactionManager;
}
private HibernateJpaVendorAdapter vendorAdaptor() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource mainDataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdaptor());
entityManagerFactoryBean.setDataSource(mainDataSource);
entityManagerFactoryBean.setPackagesToScan(ENTITY_MANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(jpaHibernateProperties());
return entityManagerFactoryBean;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties jpaHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH, env.getProperty(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH));
properties.put(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE));
properties.put(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put("hibernate.hbm2ddl.auto", "none");
return properties;
}
}
Property file which is used for datasource and hibernate (jdbc.properties) contains following :
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdatabase
jdbc.username=Bruce
jdbc.password=givanchy
jdbc.test.url=jdbc:mysql://localhost:3306/testdatabase1
hibernate.max_fetch_depth = 3
hibernate.jdbc.fetch_size = 50
hibernate.jdbc.batch_size = 10
hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
Entry point for application :
public class EntryClass {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
User user =userService.getUser(1L);
System.out.println("userName is "+user.getUserName());
}
}
It works as it should.
But in test source
I have only one test for service to understand how profiles work
#SpringJUnitConfig(SpringConfig.class)
#ActiveProfiles("test")
class UserServiceImplTest {
#Autowired
private UserService userService;
#Test
void getUser() {
User user = userService.getUser(5L);
Assertions.assertEquals("Vector", user.getUserName());
}
}
And I get "No qualifying bean" exception because there are two beans of datasource type, but I set which profile it should use?Can you explain why It doesn't work?
When you launch it normally, the datasource bean with 'test' profile is not created. (becasue there is no test profile set.)
When you run it as a test, then both datasource beans are created. The default is created because there is no any condition on it, and the other is becasue its annotated with the test profile.
Simply add #Profile("!test") to the default bean. This way it will be created only if the test profile is NOT active.
Hi everyone.
I am trying to map class (FileEntity) to Hibernate using .setAnnotatedClasses() or .setPackagesToScan() methods. But I get the same error over and over again.
org.hibernate.hql.internal.ast.QuerySyntaxException: FileEntity is not mapped
When I mapped the class with .xml all worked fine.
Please tell me, where is my mistake?
ApplicationContextConfig.java
#Configuration
#ComponentScan("com.group.appName")
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class ApplicationContextConfig {
#Autowired
Environment environment;
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
return new InternalResourceViewResolver();
}
#Bean(name = "dataSource")
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(environment.getProperty("spring.datasource.url"));
dataSource.setUsername(environment.getProperty("spring.datasource.username"));
dataSource.setPassword(environment.getProperty("spring.datasource.password"));
return dataSource;
}
#Autowired
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(#Qualifier("dataSource") DataSource dataSource) throws Exception {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getProperty("spring.jpa.show-sql"));
properties.put("current_session_context_class", environment.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setHibernateProperties(properties);
factoryBean.afterPropertiesSet();
factoryBean.setPackagesToScan("com.group.appName.model");
// or another method
factoryBean.setAnnotatedClasses(FileEntity.class);
return factoryBean.getObject();
}
#Autowired
#Bean(name = "transactionManager" )
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager(sessionFactory);
return transactionManager;
}
#Bean(name = "multipartResolver")
public CommonsMultipartResolver getCommonsMultipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(20971520); // 20MB
multipartResolver.setMaxInMemorySize(1048576); // 1MB
return multipartResolver;
}
}
FileEntity.java
#Entity
#Table(name ="files_upload")
public class FileEntity {
private String fileName;
private Byte[] fileData;
#Id
#Column(name = "file_name")
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
#Column(name = "file_data")
public Byte [] getFileData() {
return fileData;
}
public void setFileData(Byte [] fileData) {
this.fileData = fileData;
}
}
application.properties
server.port=9090
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/filedb?serverTimezone=Europe/Moscow
spring.datasource.username=root
spring.datasource.password=241299
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
Ok. I fixed it.
The point is that in method getSessionFactory after creating an object of class LocalSessionFactoryBean the first line should be
factoryBean.setAnnotatedClasses(FileEntity.class);
So the correct creating an object of LocalSessionFactoryBean class is:
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setAnnotatedClasses(FileEntity.class); - first line.
factoryBean.setDataSource(dataSource);
factoryBean.setHibernateProperties(properties);
factoryBean.afterPropertiesSet();
I have a spring application with java config:
#Controller
#RequestMapping("/")
public class MainController {
#Inject
#Named("dbDaoService")
IDaoService dbDaoService;
#RequestMapping(value="/saveNoteAsync", method = RequestMethod.POST)
public #ResponseBody String saveNoteAsync(#RequestBody CreateRequest createRequest, HttpServletRequest request) {
Notes newNote = new Notes(
createRequest.getTitle(),
createRequest.getNote(),
tagService.getTagMask(createRequest.getTags())
);
Long newId = dbDaoService.createNotes(newNote);
return ""+newId;
}
}
DBService:
#Service("dbDaoService")
public class DBDaoService implements IDaoService {
#PersistenceContext(unitName = "MyEntityManager")
private EntityManager entityManager;
private List<Tags> tags = null;
#Override
#Transactional
public Long createNotes(Notes data) {
entityManager.persist(data);
return data.getId();
}
}
Configuration class
#Configuration
#EnableWebMvc
#ComponentScan("ru.mypackage")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/WEB-INF/views/**").addResourceLocations("/views/");
}
#Bean
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Bean
public BasicDataSource getBasicDataSource(){
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUrl("jdbc:mysql://localhost:3306/test");
bds.setUsername("root");
bds.setPassword("root");
return bds;
}
#Bean
public HibernateJpaVendorAdapter getHibernateJpaVendorAdapter(){
HibernateJpaVendorAdapter hjva = new HibernateJpaVendorAdapter();
hjva.setShowSql(true);
hjva.setGenerateDdl(true);
hjva.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return hjva;
}
#Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName("MyEntityManager");
em.setDataSource(getBasicDataSource());
em.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
em.setPackagesToScan("ru.eastwind.persistance");
return em;
}
#Bean
public HibernateJpaDialect getHibernateJpaDialect(){
return new HibernateJpaDialect();
}
#Bean
public JpaTransactionManager getJpaTransactionManager(){
JpaTransactionManager jtm = new JpaTransactionManager();
jtm.setEntityManagerFactory(getEntityManagerFactory().getObject());
jtm.setJpaDialect(getHibernateJpaDialect());
return jtm;
}
}
In line entityManager.persist(data); I get the error:
javax.persistence.TransactionRequiredException: No transactional EntityManager available
But all select queries are woking correct! Please, help.
Use #EnableTransactionManagement on #Configuration class
#Configuration
#EnableWebMvc
#ComponentScan("ru.mypackage")
#EnableTransactionManagement
public class WebConfig extends WebMvcConfigurerAdapter {
// ... Your code
}
See Also : http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/EnableTransactionManagement.html
i am developing web application which uses multitenant database configuration.
I want to add tenant dynamically.
I added master controller to create master schema which hold tenant record created dynamically.
but problem is when i request to create tenant it went to MultitenantConnectionProvider i created database there but in database i want to scan package com.appointment.schedular.model.tenant and create table in ne database as well.
Source code
MasterDatabaseConfig.java
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.appointment.schedular.dao.master",
entityManagerFactoryRef = "masterEntityManager",
transactionManagerRef = "masterTransactionManager"
)
#PropertySource("classpath:application.properties")
public class MasterDatabaseConfig {
#Autowired
private Environment springEnvironment;
#Bean(name="masterDataSource")
public DataSource masterDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("master.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("master.datasource.url") + "?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("master.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("master.datasource.password"));
return dataSource;
}
#Bean(name = "masterEntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean masterEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
= new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(masterDataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setPackagesToScan(new String[]{"com.appointment.schedular.model.master"});
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
entityManagerFactoryBean.setPersistenceUnitName("master");
return entityManagerFactoryBean;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect","org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql", "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql", "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto", "update"));
return properties;
}
#Bean(name = "masterTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory masterEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(masterEntityManager);
return transactionManager;
}
}
TenantDatabaseConfig.java
#Configuration
#EnableTransactionManagement
#ComponentScan("com.appointment.schedular.tenant")
#EnableJpaRepositories(
entityManagerFactoryRef = "tenantEntityManager",
transactionManagerRef = "tenantTransactionManager",
basePackages = {"com.appointment.schedular.dao.tenant"})
#PropertySource("classpath:application.properties")
public class TenantDatabaseConfig {
#Autowired
private Environment springEnvironment;
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
#Bean(name = "tenantDataSource")
public DataSource tenantDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url")+"xy" + "?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
return dataSource;
}
#Bean(name = "tenantEntityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
MultiTenantConnectionProvider connectionProvider,
CurrentTenantIdentifierResolver tenantResolver) {
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(tenantDataSource());
emfBean.setPackagesToScan("com.appointment.schedular.model.tenant");
emfBean.setJpaVendorAdapter(jpaVendorAdapter());
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql"
, "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql"
, "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto"
, "update"));
emfBean.setJpaPropertyMap(properties);
emfBean.setPersistenceUnitName("master");
return emfBean;
}
#Bean(name = "tenantTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(tenantEntityManager);
return transactionManager;
}
}
MultitenantConnectionProviderImpl.java
#SuppressWarnings("serial")
#Component
#PropertySource("classpath:application.properties")
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private Environment springEnvironment;
#Autowired
private TenantDao tenantDao;
#Autowired
#Qualifier("tenantDataSource")
DataSource masterDataSource;
/*#Autowired
#Qualifier("tenantEntityManager")
EntityManager*/
private final Map<String, DataSource> map = new HashMap<>();
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
init();
}
private void init() {
List<Tenant> tenants = tenantDao.findAll();
for (Tenant tenant : tenants) {
DataSource genDatasource = constructDataSource(tenant.getTenantKey());
map.put(tenant.getTenantKey(), genDatasource);
/*
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
= new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(genDatasource);
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setPackagesToScan(new String[]{"com.appointment.schedular.model.tenant"});
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql"
, "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql"
, "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto"
, "update"));
entityManagerFactoryBean.setJpaPropertyMap(properties);
*/
}
}
private DataSource constructDataSource(String dbName) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+ "?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
try {
dataSource.getConnection().createStatement().execute("CREATE DATABASE IF NOT EXISTS " + dbName);
} catch (Exception ex) {
System.out.println(ex);
}
return dataSource;
}
#Override
protected DataSource selectAnyDataSource() {
return masterDataSource;
}
#Override
protected DataSource selectDataSource(String key) {
return map.get(key);
}
public void addTenant(String tenantKey) {
map.put(tenantKey, constructDataSource(tenantKey));
}
}
TenantController.java
#Controller
#RequestMapping("/tenant")
public class TenantController {
#Autowired
TenantDao tenantRepo;
#Autowired
MultiTenantConnectionProviderImpl multiTenantConnectionProviderImpl;
#SuppressWarnings("rawtypes")
#CrossOrigin
#RequestMapping(value = "/",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String registerTenant(#RequestBody Map map) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Tenant tenant = mapper.convertValue(map, Tenant.class);
String tenantKey = tenant.getName().replaceAll("[^a-zA-Z]+", "").toLowerCase().trim();
Optional<Tenant> previouslyStored = tenantRepo.findByTenantKey(tenantKey);
String response="Sorry your company name ("+tenant.getName()+")"+" is already taken";
if (!previouslyStored.isPresent()) {
tenant.setTenantKey(tenantKey);
tenantRepo.save(tenant);
multiTenantConnectionProviderImpl.addTenant(tenantKey);
response = "Successfully registered, your key is " + tenantKey;
return response;
}
return new ObjectMapper().writeValueAsString(response);
}
}
Replace your MultitenantConnectionProviderImpl.java with this code. Use inject service for creating your tables using configuration class.
#SuppressWarnings("serial")
#Component
#PropertySource("classpath:application.properties")
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent>,ServiceRegistryAwareService {
#Autowired
private Environment springEnvironment;
#Autowired
private TenantDao tenantDao;
#Autowired
#Qualifier("dataSource1")
DataSource masterDataSource;
#Autowired
MultiTenantConnectionProvider connectionProvider;
#Autowired
CurrentTenantIdentifierResolver tenantResolver;
#Autowired
TenantDatabaseConfig tenantDatabaseConfig;
private final Map<String, DataSource> map = new HashMap<>();
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
init();
}
private void init() {
List<Tenant> tenants = tenantDao.findAll();
for (Tenant tenant : tenants) {
map.put(tenant.getTenantKey(), constructDataSource(tenant.getTenantKey()));
}
}
private DataSource constructDataSource(String dbName) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+"?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
entityManagerFactory(dataSource,connectionProvider, tenantResolver);
return dataSource;
}
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
MultiTenantConnectionProvider connectionProvider,
CurrentTenantIdentifierResolver tenantResolver) {
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(dataSource);
emfBean.setPackagesToScan("com.appointment.schedular.model.tenant");
emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
emfBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql"
, "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql"
, "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto"
, "update"));
emfBean.setJpaPropertyMap(properties);
emfBean.setPersistenceUnitName(dataSource.toString());
emfBean.afterPropertiesSet();
//emfBean.setEntityManagerFactoryInterface((EntityMana)emfBean);
//emfBean.setBeanName("srgsrohtak");
return emfBean;
}
public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(tenantEntityManager);
transactionManager.afterPropertiesSet();
return transactionManager;
}
#Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
Map lSettings = serviceRegistry.getService(ConfigurationService.class).getSettings();
DataSource localDs = (DataSource) lSettings.get("hibernate.connection.datasource");
masterDataSource = localDs;
}
#Override
protected DataSource selectAnyDataSource() {
return masterDataSource;
}
#Override
protected DataSource selectDataSource(String key) {
return map.get(key);
}
public void addTenant(String tenantKey) {
map.put(tenantKey, constructDataSource(tenantKey));
}
}
The programmatic configuration seems in place but for some reason the application throws exception:
org.springframework.orm.jpa.JpaSystemException: createQuery is not valid without active transaction; nested exception is org.hibernate.HibernateException: createQuery is not valid without active transaction
Code:
#Repository
public class FilmDAOImpl implements FilmDAO {
#Autowired
private HibernateUtil hibernateUtil;
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Film> findFilms(int actorId, int categoryId, int languageId, int releaseYear) {
Query searchQuery = sessionFactory.getCurrentSession().createQuery("from Film " +
"join Actor " +
"join Category " +
"where Category.categoryId=:categoryId " +
"and Film.language.id=:languageId " +
"and Film.releaseYear=:releaseYear " +
"and Actor.actorId=:actorId");
searchQuery.setParameter("categoryId", categoryId);
searchQuery.setParameter("languageId", languageId);
searchQuery.setParameter("releaseYear", releaseYear);
searchQuery.setParameter("actorId", actorId);
return (List<Film>)searchQuery.list();
}
}
Configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories (basePackages = { "com.hibernate.query.performance.persistence" }, transactionManagerRef = "jpaTransactionManager")
#EnableJpaAuditing
#PropertySource({ "classpath:persistence-postgresql.properties" })
#ComponentScan(basePackages = { "com.hibernate.query.performance" })
public class ApplicationConfig {
#Autowired
private Environment env;
public ApplicationConfig() {
super();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(applicationDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(applicationDataSource());
emf.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(hibernateProperties());
return emf;
}
#Primary
#Bean
public DriverManagerDataSource applicationDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
#Bean
#Primary
public PlatformTransactionManager hibernateTransactionManager() {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
transactionManager.setDataSource(applicationDataSource());
return transactionManager;
}
#Bean
public PlatformTransactionManager jpaTransactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
hibernateProperties.setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache"));
hibernateProperties.setProperty("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache"));
hibernateProperties.setProperty("hibernate.current_session_context_class", "managed");
hibernateProperties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext");
return hibernateProperties;
}
}
UPDATE
#Service
#Transactional
public class FilmServiceImpl implements FilmService {
#Autowired
private FilmDAO filmDAO;
#Override
public int createFilm(Film film) {
return filmDAO.createFilm(film);
}
#Override
public Film updateFilm(Film film) {
return filmDAO.updateFilm(film);
}
#Override
public void deleteFilm(int id) {
filmDAO.deleteFilm(id);
}
#Override
public List<Film> getAllFilms() {
return filmDAO.getAllFilms();
}
#Override
public Film getFilm(int id) {
return filmDAO.getFilm(id);
}
#Override
public List<Film> findFilms(int actorId, int categoryId, int languageId, int releaseYear) {
return filmDAO.findFilms(actorId, categoryId, languageId, releaseYear);
}
}
Try using openSession() as below, Since getCurrentSession() just attaches to the current session:
Query searchQuery = sessionFactory.openSession().createQuery(...
Also, you need to surround code with proper try..catch..finally block and in finally close the session using session.close()