Skip to content

Commit 7292498

Browse files
authored
Merge pull request #139 from Ryszard-Trojnacki/feature/extra-connection-initialize
DataSourcePoolNewConnectionListener for listening of new connections
2 parents 8f8aa2b + e5bfa99 commit 7292498

File tree

5 files changed

+169
-0
lines changed

5 files changed

+169
-0
lines changed

ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceBuilder.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,11 @@ default DataSourceBuilder listener(DataSourcePoolListener listener) {
379379
@Deprecated(forRemoval = true)
380380
DataSourceBuilder setListener(DataSourcePoolListener listener);
381381

382+
/**
383+
* Set the connection initializer to use.
384+
*/
385+
DataSourceBuilder connectionInitializer(NewConnectionInitializer connectionListener);
386+
382387
/**
383388
* Set a SQL statement used to test the database is accessible.
384389
* <p>
@@ -933,6 +938,11 @@ default String driverClassName() {
933938
*/
934939
DataSourcePoolListener getListener();
935940

941+
/**
942+
* Return the new connection listener to use.
943+
*/
944+
NewConnectionInitializer getConnectionInitializer();
945+
936946
/**
937947
* Return a SQL statement used to test the database is accessible.
938948
* <p>

ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceConfig.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public class DataSourceConfig implements DataSourceBuilder.Settings {
8484
private List<String> initSql;
8585
private DataSourceAlert alert;
8686
private DataSourcePoolListener listener;
87+
private NewConnectionInitializer connectionInitializer;
8788
private Properties clientInfo;
8889
private String applicationName;
8990
private boolean shutdownOnJvmExit;
@@ -477,6 +478,17 @@ public DataSourceConfig setListener(DataSourcePoolListener listener) {
477478
return this;
478479
}
479480

481+
@Override
482+
public NewConnectionInitializer getConnectionInitializer() {
483+
return connectionInitializer;
484+
}
485+
486+
@Override
487+
public DataSourceBuilder connectionInitializer(NewConnectionInitializer connectionInitializer) {
488+
this.connectionInitializer = connectionInitializer;
489+
return this;
490+
}
491+
480492
@Override
481493
public String getHeartbeatSql() {
482494
return heartbeatSql;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.ebean.datasource;
2+
3+
import java.sql.Connection;
4+
5+
/**
6+
* A {@link DataSourcePool} listener which allows you to hook on the create connections process of the pool.
7+
*/
8+
public interface NewConnectionInitializer {
9+
10+
/**
11+
* Called after a connection has been created, before any initialization.
12+
*
13+
* @param connection the created connection
14+
*/
15+
default void preInitialize(Connection connection) {
16+
}
17+
18+
/**
19+
* Called after a connection has been initialized (after onCreatedConnection) and all settings applied.
20+
*
21+
* @param connection the created connection
22+
*/
23+
default void postInitialize(Connection connection) {
24+
}
25+
26+
}

ebean-datasource/src/main/java/io/ebean/datasource/pool/ConnectionPool.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ interface Heartbeat {
4646
*/
4747
private final DataSourceAlert notify;
4848
private final DataSourcePoolListener poolListener;
49+
private final NewConnectionInitializer connectionInitializer;
4950
private final List<String> initSql;
5051
private final String user;
5152
private final String schema;
@@ -109,6 +110,7 @@ interface Heartbeat {
109110
this.name = name;
110111
this.notify = params.getAlert();
111112
this.poolListener = params.getListener();
113+
this.connectionInitializer = params.getConnectionInitializer();
112114
this.autoCommit = params.isAutoCommit();
113115
this.readOnly = params.isReadOnly();
114116
this.failOnStart = params.isFailOnStart();
@@ -434,6 +436,9 @@ private void testConnection() {
434436
* Initializes the connection we got from the driver.
435437
*/
436438
private Connection initConnection(Connection conn) throws SQLException {
439+
if (connectionInitializer != null) {
440+
connectionInitializer.preInitialize(conn);
441+
}
437442
conn.setAutoCommit(autoCommit);
438443
// isolation level is set globally for all connections (at least for H2) and
439444
// you will need admin rights - so we do not change it, if it already matches.
@@ -470,6 +475,9 @@ private Connection initConnection(Connection conn) throws SQLException {
470475
}
471476
}
472477
}
478+
if (connectionInitializer != null) {
479+
connectionInitializer.postInitialize(conn);
480+
}
473481
return conn;
474482
}
475483

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.ebean.datasource.pool;
2+
3+
import io.ebean.datasource.DataSourceConfig;
4+
import io.ebean.datasource.NewConnectionInitializer;
5+
import org.junit.jupiter.api.AfterEach;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.sql.Connection;
9+
import java.util.HashMap;
10+
import static org.junit.jupiter.api.Assertions.*;
11+
12+
class ConnectionPoolNewConnectionListenerTest {
13+
14+
private ConnectionPool pool;
15+
16+
private final HashMap<Connection, Integer> createdConnections = new HashMap<>();
17+
private final HashMap<Connection, Integer> afterConnections = new HashMap<>();
18+
19+
ConnectionPoolNewConnectionListenerTest() {
20+
pool = createPool();
21+
}
22+
23+
24+
private ConnectionPool createPool() {
25+
26+
DataSourceConfig config = new DataSourceConfig();
27+
config.setDriver("org.h2.Driver");
28+
config.setUrl("jdbc:h2:mem:tests");
29+
config.setUsername("sa");
30+
config.setPassword("");
31+
config.setMinConnections(1);
32+
config.setMaxConnections(5);
33+
config.connectionInitializer(new NewConnectionInitializer() {
34+
@Override
35+
public void preInitialize(Connection connection) {
36+
synchronized (createdConnections) {
37+
createdConnections.put(connection, 1 + createdConnections.getOrDefault(connection, 0));
38+
createdConnections.notifyAll();
39+
}
40+
}
41+
42+
@Override
43+
public void postInitialize(Connection connection) {
44+
synchronized (afterConnections) {
45+
afterConnections.put(connection, 1 + afterConnections.getOrDefault(connection, 0));
46+
afterConnections.notifyAll();
47+
}
48+
}
49+
});
50+
51+
return new ConnectionPool("initialize", config);
52+
}
53+
54+
@AfterEach
55+
public void after() {
56+
pool.shutdown();
57+
}
58+
59+
@Test
60+
public void initializeNewConnectionTest() {
61+
// Min connections is 1 so one should be created on pool initialization
62+
synchronized (createdConnections) {
63+
assertEquals(1, createdConnections.size());
64+
assertEquals(1, afterConnections.size());
65+
}
66+
67+
try (Connection connection = pool.getConnection()) {
68+
assertNotNull(connection);
69+
synchronized (createdConnections) {
70+
assertEquals(1, createdConnections.size());
71+
}
72+
synchronized (afterConnections) {
73+
assertEquals(1, afterConnections.size());
74+
}
75+
} catch (Exception e) {
76+
fail(e.getMessage());
77+
}
78+
79+
try (Connection connection = pool.getConnection()) {
80+
assertNotNull(connection);
81+
synchronized (createdConnections) {
82+
assertEquals(1, createdConnections.size());
83+
}
84+
synchronized (afterConnections) {
85+
assertEquals(1, afterConnections.size());
86+
}
87+
88+
try (Connection connection2 = pool.getConnection()) {
89+
assertNotNull(connection2);
90+
synchronized (createdConnections) {
91+
assertEquals(2, createdConnections.size());
92+
}
93+
synchronized (afterConnections) {
94+
assertEquals(2, afterConnections.size());
95+
}
96+
}
97+
} catch (Exception e) {
98+
fail(e.getMessage());
99+
}
100+
synchronized (createdConnections) {
101+
for (var entry : createdConnections.entrySet()) {
102+
// It should be always 1
103+
assertEquals(1, entry.getValue());
104+
}
105+
}
106+
synchronized (afterConnections) {
107+
for (var entry : afterConnections.entrySet()) {
108+
// It should be always 1
109+
assertEquals(1, entry.getValue());
110+
}
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)