Skip to content

Commit fca9564

Browse files
author
zeroual
committed
configure data source for heroku
1 parent f5f98a7 commit fca9564

13 files changed

+201
-39
lines changed

Procfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#Procfile tells to Heroku how to run otchi.
22

3-
web: java -Dserver.port=$PORT -jar -Dspring.profiles.active=prod target/otchi-0.0.1-SNAPSHOT.jar
3+
web: java -jar target/otchi-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod --server.port=$PORT

pom.xml

+16
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,22 @@
123123
<artifactId>mockito-all</artifactId>
124124
<version>${mockito.version}</version>
125125
</dependency>
126+
<!-- HikariCP is a "zero-overhead" production ready JDBC connection pool. At roughly 90Kb, the library is very light.-->
127+
<dependency>
128+
<groupId>com.zaxxer</groupId>
129+
<artifactId>HikariCP</artifactId>
130+
<exclusions>
131+
<exclusion>
132+
<artifactId>tools</artifactId>
133+
<groupId>com.sun</groupId>
134+
</exclusion>
135+
</exclusions>
136+
</dependency>
137+
138+
<dependency>
139+
<groupId>mysql</groupId>
140+
<artifactId>mysql-connector-java</artifactId>
141+
</dependency>
126142

127143
</dependencies>
128144

src/main/java/com/otchi/infrastructure/boot/OtchiApplicationStarter.java

+27-3
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
import com.otchi.infrastructure.config.Constants;
55
import org.slf4j.Logger;
66
import org.slf4j.LoggerFactory;
7+
import org.springframework.beans.factory.annotation.Autowired;
78
import org.springframework.boot.SpringApplication;
89
import org.springframework.boot.autoconfigure.SpringBootApplication;
910
import org.springframework.context.annotation.Configuration;
1011
import org.springframework.context.annotation.Import;
1112
import org.springframework.core.env.Environment;
1213
import org.springframework.core.env.SimpleCommandLinePropertySource;
1314

15+
import javax.annotation.PostConstruct;
16+
import java.io.IOException;
1417
import java.net.InetAddress;
1518
import java.net.UnknownHostException;
19+
import java.util.Arrays;
20+
import java.util.Collection;
1621

1722
@SpringBootApplication
1823
@Configuration
@@ -21,11 +26,12 @@ public class OtchiApplicationStarter {
2126

2227
private static final Logger log = LoggerFactory.getLogger(OtchiApplicationStarter.class);
2328

29+
@Autowired
30+
private Environment env;
31+
2432
/**
25-
* Initializes the App.
26-
* Spring profiles can be configured with a program arguments --spring.profiles.active= active-profile
33+
* Main method, used to run the application.
2734
*/
28-
2935
public static void main(String[] args) throws UnknownHostException {
3036
SpringApplication app = new SpringApplication(OtchiApplicationStarter.class);
3137
SimpleCommandLinePropertySource source = new SimpleCommandLinePropertySource(args);
@@ -50,4 +56,22 @@ private static void setDefaultProfile(SpringApplication app, SimpleCommandLinePr
5056
}
5157
}
5258

59+
/**
60+
* Initializes the App.
61+
* Spring profiles can be configured with a program arguments --spring.profiles.active= active-profile
62+
*/
63+
64+
@PostConstruct
65+
public void initApplication() throws IOException {
66+
if (env.getActiveProfiles().length == 0) {
67+
log.warn("No Spring profile configured, running with default configuration");
68+
} else {
69+
log.info("Running with Spring profile(s) : {}", Arrays.toString(env.getActiveProfiles()));
70+
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
71+
if (activeProfiles.contains("dev") && activeProfiles.contains("prod")) {
72+
log.error("You have misconfigured your application! " +
73+
"It should not run with both the 'dev' and 'prod' profiles at the same time.");
74+
}
75+
}
76+
}
5377
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package com.otchi.infrastructure.config;
22

3-
import org.h2.tools.Server;
3+
import com.otchi.infrastructure.config.database.H2DatabaseConfig;
4+
import com.otchi.infrastructure.config.database.HerokuDatabaseConfig;
45
import org.springframework.context.annotation.Bean;
56
import org.springframework.context.annotation.Configuration;
67
import org.springframework.context.annotation.EnableAspectJAutoProxy;
7-
import org.springframework.context.annotation.Profile;
8+
import org.springframework.context.annotation.Import;
89
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
9-
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
10-
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
1110
import org.springframework.orm.jpa.JpaTransactionManager;
1211
import org.springframework.orm.jpa.JpaVendorAdapter;
1312
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -16,29 +15,15 @@
1615
import org.springframework.transaction.annotation.EnableTransactionManagement;
1716

1817
import javax.sql.DataSource;
19-
import java.sql.SQLException;
20-
21-
import static com.otchi.infrastructure.config.Constants.SPRING_PROFILE_DEVELOPMENT;
2218

2319

2420
@Configuration
2521
@EnableJpaRepositories("com.otchi.domain")
2622
@EnableAspectJAutoProxy(proxyTargetClass = true)
2723
@EnableTransactionManagement
24+
@Import({HerokuDatabaseConfig.class, H2DatabaseConfig.class})
2825
public class DatabaseConfig {
2926

30-
private final String H2_SERVE_PORT = "8082";
31-
32-
@Bean
33-
public DataSource dataSource() {
34-
return new EmbeddedDatabaseBuilder()
35-
.setType(EmbeddedDatabaseType.H2)
36-
.addScript("database/schema.sql")
37-
.addScript("database/social-users-connections.sql")
38-
.addScript("database/data.sql")
39-
.build();
40-
}
41-
4227
@Bean
4328
public JpaTransactionManager transactionManager() {
4429
return new JpaTransactionManager();
@@ -62,17 +47,4 @@ public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource da
6247
return emf;
6348
}
6449

65-
@Bean
66-
@Profile(SPRING_PROFILE_DEVELOPMENT)
67-
public Server serverH2() throws SQLException {
68-
// start a Web server : either before or after opening the database
69-
System.out.println("\n>>>>> serverH2 : démarre ..............\n" +
70-
" URL : http://localhost:" + H2_SERVE_PORT + "/ \n" +
71-
" URL JDBC : jdbc:h2:mem:testdb \n" +
72-
" USER : sa \n" +
73-
" PASSWORD : \n" +
74-
" \n");
75-
return Server.createWebServer("-webAllowOthers", "-webPort", H2_SERVE_PORT).start();
76-
}
77-
7850
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.otchi.infrastructure.config.database;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.annotation.Profile;
6+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
7+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
8+
9+
import javax.sql.DataSource;
10+
11+
import static com.otchi.infrastructure.config.Constants.SPRING_PROFILE_DEVELOPMENT;
12+
13+
@Configuration
14+
@Profile(SPRING_PROFILE_DEVELOPMENT)
15+
public class H2DatabaseConfig {
16+
17+
// private final String H2_SERVE_PORT = "8082";
18+
19+
@Bean
20+
@Profile(SPRING_PROFILE_DEVELOPMENT)
21+
public DataSource dataSource() {
22+
return new EmbeddedDatabaseBuilder()
23+
.setType(EmbeddedDatabaseType.H2)
24+
.addScript("database/schema.sql")
25+
.addScript("database/social-users-connections.sql")
26+
.addScript("database/data.sql")
27+
.build();
28+
}
29+
30+
/*
31+
@Bean
32+
@Profile(SPRING_PROFILE_DEVELOPMENT)
33+
public Server serverH2() throws SQLException {
34+
// start a Web server : either before or after opening the database
35+
System.out.println("\n>>>>> serverH2 : démarre ..............\n" +
36+
" URL : http://localhost:" + H2_SERVE_PORT + "/ \n" +
37+
" URL JDBC : jdbc:h2:mem:testdb \n" +
38+
" USER : sa \n" +
39+
" PASSWORD : \n" +
40+
" \n");
41+
return Server.createWebServer("-webAllowOthers", "-webPort", H2_SERVE_PORT).start();
42+
}
43+
*/
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.otchi.infrastructure.config.database;
2+
3+
import com.zaxxer.hikari.HikariConfig;
4+
import com.zaxxer.hikari.HikariDataSource;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.springframework.beans.factory.annotation.Value;
8+
import org.springframework.context.ApplicationContextException;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.Configuration;
11+
import org.springframework.context.annotation.Profile;
12+
import org.springframework.core.io.ClassPathResource;
13+
import org.springframework.core.io.Resource;
14+
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
15+
16+
import javax.sql.DataSource;
17+
18+
import static com.otchi.infrastructure.config.Constants.SPRING_PROFILE_PRODUCTION;
19+
20+
@Configuration
21+
@Profile(SPRING_PROFILE_PRODUCTION)
22+
public class HerokuDatabaseConfig {
23+
24+
private final Logger log = LoggerFactory.getLogger(HerokuDatabaseConfig.class);
25+
26+
@Value("${spring.datasource.cachePrepStmts:true}")
27+
private boolean cachePrepStmts;
28+
29+
@Value("${spring.datasource.prepStmtCacheSize:250}")
30+
private int prepStmtCacheSize;
31+
32+
@Value("${spring.datasource.prepStmtCacheSqlLimit:2048}")
33+
private int prepStmtCacheSqlLimit;
34+
35+
@Value("${spring.datasource.dataSourceClassName}")
36+
private String dataSourceClassName;
37+
38+
@Bean
39+
public DataSource dataSource() {
40+
log.debug("Configuring Heroku Datasource");
41+
String herokuUrl = System.getenv("JDBC_DATABASE_URL");
42+
if (herokuUrl != null) {
43+
HikariConfig config = new HikariConfig();
44+
45+
//MySQL optimizations, see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
46+
if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals(dataSourceClassName)) {
47+
config.addDataSourceProperty("cachePrepStmts", cachePrepStmts);
48+
config.addDataSourceProperty("prepStmtCacheSize", prepStmtCacheSize);
49+
config.addDataSourceProperty("prepStmtCacheSqlLimit", prepStmtCacheSqlLimit);
50+
}
51+
52+
config.setDataSourceClassName(dataSourceClassName);
53+
config.addDataSourceProperty("url", herokuUrl);
54+
HikariDataSource hikariDataSource = new HikariDataSource(config);
55+
executeScript(hikariDataSource, "database/schema.sql");
56+
executeScript(hikariDataSource, "database/social-users-connections.sql");
57+
executeScript(hikariDataSource, "database/data.sql");
58+
return hikariDataSource;
59+
} else {
60+
throw new ApplicationContextException("Heroku database URL is not configured, you must set $JDBC_DATABASE_URL");
61+
}
62+
}
63+
64+
public void executeScript(DataSource dataSource, String script) {
65+
Resource resource = new ClassPathResource(script);
66+
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(resource);
67+
databasePopulator.execute(dataSource);
68+
}
69+
}

src/main/resources/application-prod.yml

+22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
spring:
2+
profiles:
3+
active: prod
24
social:
35
# see https://developers.google.com/+/web/signin/server-side-flow#step_1_create_a_client_id_and_client_secret
46
google:
@@ -14,3 +16,23 @@ spring:
1416
twitter:
1517
clientId: X1S2BH04CdYXYtHfTG6gGa5C7
1618
clientSecret: 3FOSZfivHHQL9OAjV3ybU5ErLZkftV5BL4xbbeoCP1GjmvSP2D
19+
datasource:
20+
dataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlDataSource
21+
cachePrepStmts: true
22+
prepStmtCacheSize: 250
23+
prepStmtCacheSqlLimit: 2048
24+
useServerPrepStmts: true
25+
26+
jpa:
27+
database-platform: org.hibernate.dialect.MySQLInnoDBDialect
28+
database: MYSQL
29+
openInView: false
30+
show_sql: false
31+
generate-ddl: false
32+
hibernate:
33+
ddl-auto: none
34+
naming-strategy: org.hibernate.cfg.EJB3NamingStrategy
35+
properties:
36+
hibernate.cache.use_second_level_cache: false
37+
hibernate.cache.use_query_cache: false
38+
hibernate.generate_statistics: false

src/main/resources/application.properties

-1
This file was deleted.

src/main/resources/application.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
spring:
2+
social:
3+
redirectAfterSignInUrl: "/#/feed"

src/main/resources/database/social-users-connections.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
-- connection in. It is, however, not to be assumed to be production-ready, all-purpose SQL. It is merely representative
33
-- of the kind of table that JdbcUsersConnectionRepository works with. The table and column names, as well as the general
44
-- column types, are what is important. Specific column types and sizes that work may vary across database vendors and
5-
-- the required sizes may vary across API providers.
5+
-- the required sizes may vary across API providers.
66
DROP TABLE IF EXISTS UserConnection;
77

88
create table UserConnection (userId varchar(255) not null,

src/test/java/com/otchi/infrastructure/security/AuthenticationTest.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
import com.github.springtestdbunit.DbUnitTestExecutionListener;
44
import com.github.springtestdbunit.annotation.DatabaseSetup;
5-
import com.otchi.infrastructure.config.*;
5+
import com.otchi.infrastructure.config.ApplicationConfig;
6+
import com.otchi.infrastructure.config.ResourcesPath;
67
import org.junit.Before;
78
import org.junit.Test;
89
import org.junit.runner.RunWith;
910
import org.springframework.beans.factory.annotation.Autowired;
1011
import org.springframework.boot.test.IntegrationTest;
1112
import org.springframework.security.test.context.support.WithMockUser;
1213
import org.springframework.test.annotation.DirtiesContext;
14+
import org.springframework.test.context.ActiveProfiles;
1315
import org.springframework.test.context.ContextConfiguration;
1416
import org.springframework.test.context.TestExecutionListeners;
1517
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -23,6 +25,7 @@
2325

2426
import javax.servlet.Filter;
2527

28+
import static com.otchi.infrastructure.config.Constants.SPRING_PROFILE_DEVELOPMENT;
2629
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
2730
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
2831
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -38,6 +41,7 @@
3841
DirtiesContextTestExecutionListener.class,
3942
TransactionalTestExecutionListener.class,
4043
DbUnitTestExecutionListener.class})
44+
@ActiveProfiles(SPRING_PROFILE_DEVELOPMENT)
4145
public class AuthenticationTest {
4246

4347
private MockMvc mockMvc;

src/test/java/com/otchi/utils/AbstractControllerTest.java

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
1212
import org.springframework.mock.http.MockHttpOutputMessage;
1313
import org.springframework.test.annotation.DirtiesContext;
14+
import org.springframework.test.context.ActiveProfiles;
1415
import org.springframework.test.context.ContextConfiguration;
1516
import org.springframework.test.context.TestExecutionListeners;
1617
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -26,6 +27,8 @@
2627
import java.io.IOException;
2728
import java.nio.charset.Charset;
2829

30+
import static com.otchi.infrastructure.config.Constants.SPRING_PROFILE_DEVELOPMENT;
31+
2932

3033
@RunWith(SpringJUnit4ClassRunner.class)
3134
@ContextConfiguration(classes = {ApplicationConfig.class})
@@ -36,6 +39,8 @@
3639
DirtiesContextTestExecutionListener.class,
3740
TransactionalTestExecutionListener.class,
3841
DbUnitTestExecutionListener.class})
42+
@ActiveProfiles(SPRING_PROFILE_DEVELOPMENT)
43+
3944
public class AbstractControllerTest {
4045

4146
protected MockMvc mockMvc;

0 commit comments

Comments
 (0)