1 package com.atlassian.plugin.refimpl.db;
2
3 import com.atlassian.refapp.api.ConnectionProvider;
4 import org.h2.tools.Server;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7 import org.vibur.dbcp.ViburDBCPDataSource;
8
9 import javax.sql.DataSource;
10 import java.net.InetAddress;
11 import java.sql.Connection;
12 import java.sql.SQLException;
13 import java.util.Optional;
14
15 public class ConnectionProviderImpl implements ConnectionProvider {
16 private static final Logger log = LoggerFactory.getLogger(ConnectionProviderImpl.class);
17
18 private static final String DB_DIR = System.getProperty("refapp.home", System.getProperty("java.io.tmpdir"));
19 private static final String LOCAL_HOST = InetAddress.getLoopbackAddress().getHostAddress();
20
21 private static final String SYS_PROP_EXTERNAL = "refapp.jdbc.external";
22 private static final String SYS_PROP_DRIVER_CLASS = "refapp.jdbc.driver.class.name";
23 private static final String SYS_PROP_URL = "refapp.jdbc.app.url";
24 private static final String SYS_PROP_SCHEMA = "refapp.jdbc.app.schema";
25 private static final String SYS_PROP_USER = "refapp.jdbc.app.user";
26 private static final String SYS_PROP_PASSWORD = "refapp.jdbc.app.pass";
27 private static final String SYS_PROP_VAL_QUERY = "refapp.jdbc.validation.query";
28
29 private static final String EMBEDDED_DRIVER_CLASS = "org.h2.Driver";
30 private static final String EMBEDDED_URL_PREFIX = "jdbc:h2:tcp://" + LOCAL_HOST + ":";
31 private static final String EMBEDDED_URL_SUFFIX = "/" + DB_DIR + "/h2db";
32 private static final Optional<String> EMBEDDED_SCHEMA = Optional.of("PUBLIC");
33 private static final String EMBEDDED_USER = "sa";
34 private static final String EMBEDDED_PASSWORD = "";
35 private static final Optional<String> EMBEDDED_VAL_QUERY = Optional.empty();
36
37 private final String driverClassName;
38 private final Optional<String> schema;
39
40 private final ViburDBCPDataSource dataSource;
41
42
43
44
45
46
47 public ConnectionProviderImpl() throws SQLException {
48
49
50 final boolean externalDb = Boolean.getBoolean(SYS_PROP_EXTERNAL);
51
52 final String url;
53 final String user;
54 final String password;
55 final Optional<String> validationQuery;
56 if (externalDb) {
57
58
59 this.driverClassName = mandatoryPropertyValue(SYS_PROP_DRIVER_CLASS);
60 url = mandatoryPropertyValue(SYS_PROP_URL);
61 this.schema = Optional.ofNullable(System.getProperty(SYS_PROP_SCHEMA));
62 user = mandatoryPropertyValue(SYS_PROP_USER);
63 password = mandatoryPropertyValue(SYS_PROP_PASSWORD);
64 validationQuery = Optional.ofNullable(System.getProperty(SYS_PROP_VAL_QUERY));
65 } else {
66
67
68 this.driverClassName = EMBEDDED_DRIVER_CLASS;
69 url = embeddedUrl();
70 this.schema = EMBEDDED_SCHEMA;
71 user = EMBEDDED_USER;
72 password = EMBEDDED_PASSWORD;
73 validationQuery = EMBEDDED_VAL_QUERY;
74 }
75
76 log.info("starting database driverClassName='{}' url='{}' schema='{}' user='{}' password='{}' validationQuery='{}'",
77 driverClassName, url, schema, user, password, validationQuery);
78
79
80 final ViburDBCPDataSource viburDS = new ViburDBCPDataSource();
81 viburDS.setDriverClassName(driverClassName);
82 viburDS.setJdbcUrl(url);
83 viburDS.setUsername(user);
84 viburDS.setPassword(password);
85 validationQuery.ifPresent(q -> viburDS.setTestConnectionQuery(q));
86 viburDS.setCloseConnectionHook(rawConnection -> {
87 boolean autocommit = rawConnection.getAutoCommit();
88 if (!autocommit) {
89 rawConnection.commit();
90 }
91 });
92 viburDS.start();
93
94 this.dataSource = viburDS;
95 }
96
97 public void terminate() {
98 dataSource.terminate();
99 }
100
101 @Override
102 public Connection connection() throws SQLException {
103 return dataSource.getConnection();
104 }
105
106 @Override
107 public DataSource dataSource() {
108 return dataSource;
109 }
110
111 @Override
112 public String driverClassName() {
113 return driverClassName;
114 }
115
116 @Override
117 public Optional<String> schema() {
118 return schema;
119 }
120
121
122
123
124
125
126
127 private String embeddedUrl() throws SQLException {
128
129
130 final Server server = Server.createTcpServer();
131 System.setProperty("h2.bindAddress", LOCAL_HOST);
132 server.start();
133
134
135 return EMBEDDED_URL_PREFIX + server.getPort() + EMBEDDED_URL_SUFFIX;
136 }
137
138
139
140
141
142
143
144
145 private String mandatoryPropertyValue(final String key) {
146 final String value = System.getProperty(key, null);
147 if (value == null) {
148 throw new RuntimeException("Mandatory java system property '" + key + "' not specified. See com.atlassian.refapp.api.ConnectionProvider for more information.");
149 }
150 return value;
151 }
152 }