first commit

This commit is contained in:
Jay Ehsaniara
2019-12-31 00:19:27 -08:00
commit a26fb3b14c
14 changed files with 453 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
package com.ehsaniara.multidatasource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.Properties;
@SpringBootApplication
public class DemoApplication {
public final static String MODEL_PACKAGE = "com.ehsaniara.multidatasource.model";
public final static Properties JPA_PROPERTIES = new Properties() {{
put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL10Dialect");
put("hibernate.hbm2ddl.auto", "update");
put("hibernate.ddl-auto", "update");
put("show-sql", "true");
}};
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@@ -0,0 +1,58 @@
package com.ehsaniara.multidatasource.configurations;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import static com.ehsaniara.multidatasource.DemoApplication.JPA_PROPERTIES;
import static com.ehsaniara.multidatasource.DemoApplication.MODEL_PACKAGE;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@Configuration
@ConfigurationProperties("spring.datasource-read")
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryRead",
transactionManagerRef = "transactionManagerRead",
basePackages = {"com.ehsaniara.multidatasource.repository.readRepository"}
)
public class DataSourceConfigRead extends HikariConfig {
public final static String PERSISTENCE_UNIT_NAME = "read";
@Bean
public HikariDataSource dataSourceRead() {
return new HikariDataSource(this);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryRead(
final HikariDataSource dataSourceRead) {
return new LocalContainerEntityManagerFactoryBean() {{
setDataSource(dataSourceRead);
setPersistenceProviderClass(HibernatePersistenceProvider.class);
setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
setPackagesToScan(MODEL_PACKAGE);
setJpaProperties(JPA_PROPERTIES);
}};
}
@Bean
public PlatformTransactionManager transactionManagerRead(EntityManagerFactory entityManagerFactoryRead) {
return new JpaTransactionManager(entityManagerFactoryRead);
}
}

View File

@@ -0,0 +1,57 @@
package com.ehsaniara.multidatasource.configurations;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import static com.ehsaniara.multidatasource.DemoApplication.JPA_PROPERTIES;
import static com.ehsaniara.multidatasource.DemoApplication.MODEL_PACKAGE;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@Configuration
@ConfigurationProperties("spring.datasource-write")
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryWrite",
transactionManagerRef = "transactionManagerWrite",
basePackages = {"com.ehsaniara.multidatasource.repository.writeRepository"}
)
public class DataSourceConfigWrite extends HikariConfig {
public final static String PERSISTENCE_UNIT_NAME = "write";
@Bean
public HikariDataSource dataSourceWrite() {
return new HikariDataSource(this);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryWrite(
final HikariDataSource dataSourceWrite) {
return new LocalContainerEntityManagerFactoryBean() {{
setDataSource(dataSourceWrite);
setPersistenceProviderClass(HibernatePersistenceProvider.class);
setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
setPackagesToScan(MODEL_PACKAGE);
setJpaProperties(JPA_PROPERTIES);
}};
}
@Bean
public PlatformTransactionManager transactionManagerWrite(EntityManagerFactory entityManagerFactoryWrite) {
return new JpaTransactionManager(entityManagerFactoryWrite);
}
}

View File

@@ -0,0 +1,35 @@
package com.ehsaniara.multidatasource.controller;
import com.ehsaniara.multidatasource.handler.ResourceNotFoundException;
import com.ehsaniara.multidatasource.model.Customer;
import com.ehsaniara.multidatasource.service.CustomerService;
import org.springframework.web.bind.annotation.*;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@RestController
public class CustomerControllerImpl {
private final CustomerService customerService;
public CustomerControllerImpl(CustomerService customerService) {
this.customerService = customerService;
}
@RequestMapping(path = "/customer/{id}", method = RequestMethod.GET)
public Customer getCustomer(@PathVariable("id") Long id) {
return customerService.getCustomer(id).orElseThrow(() -> new ResourceNotFoundException("Invalid Customer"));
}
@RequestMapping(path = "/customer", method = RequestMethod.POST)
public Customer createCustomer(@RequestBody Customer customer) {
return customerService.createCustomer(customer);
}
@RequestMapping(path = "/customer", method = RequestMethod.PUT)
public Customer updateCustomer(@RequestBody Customer customer) {
return customerService.updateCustomer(customer);
}
}

View File

@@ -0,0 +1,96 @@
package com.ehsaniara.multidatasource.handler;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.SQLGrammarException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.http.HttpServletRequest;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@Slf4j
@ControllerAdvice
public class ExceptionHandlerControllerAdvice {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ResponseBody
public ExceptionResponse handleResourceNotFound(final ResourceNotFoundException exception,
final HttpServletRequest request) {
log.error(exception.getMessage());
ExceptionResponse error = new ExceptionResponse();
error.setMessage(exception.getMessage());
error.setUrl(request.getRequestURI());
error.setStatus(HttpStatus.NOT_FOUND.value());
return error;
}
@ExceptionHandler(IllegalStateException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public ExceptionResponse handleIllegalStateException(final IllegalStateException exception,
final HttpServletRequest request) {
log.error(exception.getMessage());
ExceptionResponse error = new ExceptionResponse();
error.setMessage(exception.getMessage());
error.setUrl(request.getRequestURI());
error.setStatus(HttpStatus.BAD_REQUEST.value());
return error;
}
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public ExceptionResponse handleIllegalArgumentException(final IllegalArgumentException exception,
final HttpServletRequest request) {
log.error(exception.getMessage());
ExceptionResponse error = new ExceptionResponse();
error.setMessage(exception.getMessage());
error.setUrl(request.getRequestURI());
error.setStatus(HttpStatus.BAD_REQUEST.value());
return error;
}
@ExceptionHandler(SQLGrammarException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ExceptionResponse handleSQLGrammarException(final SQLGrammarException exception,
final HttpServletRequest request) {
log.error(exception.getMessage());
ExceptionResponse error = new ExceptionResponse();
error.setMessage("SQL Exception");
error.setUrl(request.getRequestURI());
error.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return error;
}
// @Order(Ordered.HIGHEST_PRECEDENCE)
// @ExceptionHandler(Exception.class)
// @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
// @ResponseBody
// public ExceptionResponse handleException(final Exception exception,
// final HttpServletRequest request) {
// log.error(exception.getMessage());
//
// ExceptionResponse error = new ExceptionResponse();
// error.setErrorMessage(exception.getMessage());
// error.setUrl(request.getRequestURI());
//
// return error;
// }
}

View File

@@ -0,0 +1,21 @@
package com.ehsaniara.multidatasource.handler;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@Setter
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ExceptionResponse {
private String message;
private String error;
private String url;
private long status;
}

View File

@@ -0,0 +1,14 @@
package com.ehsaniara.multidatasource.handler;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,27 @@
package com.ehsaniara.multidatasource.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@ToString
@Setter
@Getter
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}

View File

@@ -0,0 +1,10 @@
package com.ehsaniara.multidatasource.repository.readRepository;
import com.ehsaniara.multidatasource.model.Customer;
import org.springframework.data.repository.CrudRepository;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
public interface CustomerReadRepository extends CrudRepository<Customer, Long> {
}

View File

@@ -0,0 +1,10 @@
package com.ehsaniara.multidatasource.repository.writeRepository;
import com.ehsaniara.multidatasource.model.Customer;
import org.springframework.data.repository.CrudRepository;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
public interface CustomerWriteRepository extends CrudRepository<Customer, Long> {
}

View File

@@ -0,0 +1,17 @@
package com.ehsaniara.multidatasource.service;
import com.ehsaniara.multidatasource.model.Customer;
import java.util.Optional;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
public interface CustomerService {
Optional<Customer> getCustomer(Long id);
Customer createCustomer(Customer customer);
Customer updateCustomer(Customer customer);
}

View File

@@ -0,0 +1,45 @@
package com.ehsaniara.multidatasource.service;
import com.ehsaniara.multidatasource.model.Customer;
import com.ehsaniara.multidatasource.repository.readRepository.CustomerReadRepository;
import com.ehsaniara.multidatasource.repository.writeRepository.CustomerWriteRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.Optional;
/**
* @author Jay Ehsaniara, Dec 30 2019
*/
@Service
public class CustomerServiceImpl implements CustomerService {
private final CustomerReadRepository customerReadRepository;
private final CustomerWriteRepository customerWriteRepository;
public CustomerServiceImpl(CustomerReadRepository customerReadRepository, CustomerWriteRepository customerWriteRepository) {
this.customerReadRepository = customerReadRepository;
this.customerWriteRepository = customerWriteRepository;
}
public Optional<Customer> getCustomer(Long id) {
return customerReadRepository.findById(id);
}
public Customer createCustomer(Customer customer) {
Assert.notNull(customer, "Invalid customer");
Assert.isNull(customer.getId(), "customer id should be null");
Assert.notNull(customer.getName(), "Invalid customer name");
return customerWriteRepository.save(customer);
}
public Customer updateCustomer(Customer customer) {
Assert.notNull(customer, "Invalid customer");
Assert.notNull(customer.getId(), "Invalid customer id");
return customerWriteRepository.save(customer);
}
}

View File

@@ -0,0 +1,25 @@
spring:
datasource-write:
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5432/demo
username: 'postgres'
password: 'postgres_user_for_db_write'
platform: postgresql
hikari:
idle-timeout: 10000
maximum-pool-size: 10
minimum-idle: 5
pool-name: WriteHikariPool
datasource-read:
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5433/demo
username: 'postgres'
password: 'postgres_user_for_db_read'
platform: postgresql
hikari:
idle-timeout: 10000
maximum-pool-size: 10
minimum-idle: 5
pool-name: ReadHikariPool

View File

@@ -0,0 +1,13 @@
package com.ehsaniara.multidatasource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}