1
16
17 package com.zaxxer.hikari;
18
19 import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
20 import com.zaxxer.hikari.pool.HikariPool;
21 import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import javax.sql.DataSource;
26 import java.io.Closeable;
27 import java.io.PrintWriter;
28 import java.sql.Connection;
29 import java.sql.SQLException;
30 import java.sql.SQLFeatureNotSupportedException;
31 import java.util.concurrent.atomic.AtomicBoolean;
32
33 import static com.zaxxer.hikari.pool.HikariPool.POOL_NORMAL;
34
35
40 public class HikariDataSource extends HikariConfig implements DataSource, Closeable
41 {
42 private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class);
43
44 private final AtomicBoolean isShutdown = new AtomicBoolean();
45
46 private final HikariPool fastPathPool;
47 private volatile HikariPool pool;
48
49
59 public HikariDataSource()
60 {
61 super();
62 fastPathPool = null;
63 }
64
65
75 public HikariDataSource(HikariConfig configuration)
76 {
77 configuration.validate();
78 configuration.copyStateTo(this);
79
80 LOGGER.info("{} - Starting...", configuration.getPoolName());
81 pool = fastPathPool = new HikariPool(this);
82 LOGGER.info("{} - Start completed.", configuration.getPoolName());
83
84 this.seal();
85 }
86
87
88
89
90
91
92 @Override
93 public Connection getConnection() throws SQLException
94 {
95 if (isClosed()) {
96 throw new SQLException("HikariDataSource " + this + " has been closed.");
97 }
98
99 if (fastPathPool != null) {
100 return fastPathPool.getConnection();
101 }
102
103
104 HikariPool result = pool;
105 if (result == null) {
106 synchronized (this) {
107 result = pool;
108 if (result == null) {
109 validate();
110 LOGGER.info("{} - Starting...", getPoolName());
111 try {
112 pool = result = new HikariPool(this);
113 this.seal();
114 }
115 catch (PoolInitializationException pie) {
116 if (pie.getCause() instanceof SQLException) {
117 throw (SQLException) pie.getCause();
118 }
119 else {
120 throw pie;
121 }
122 }
123 LOGGER.info("{} - Start completed.", getPoolName());
124 }
125 }
126 }
127
128 return result.getConnection();
129 }
130
131
132 @Override
133 public Connection getConnection(String username, String password) throws SQLException
134 {
135 throw new SQLFeatureNotSupportedException();
136 }
137
138
139 @Override
140 public PrintWriter getLogWriter() throws SQLException
141 {
142 HikariPool p = pool;
143 return (p != null ? p.getUnwrappedDataSource().getLogWriter() : null);
144 }
145
146
147 @Override
148 public void setLogWriter(PrintWriter out) throws SQLException
149 {
150 HikariPool p = pool;
151 if (p != null) {
152 p.getUnwrappedDataSource().setLogWriter(out);
153 }
154 }
155
156
157 @Override
158 public void setLoginTimeout(int seconds) throws SQLException
159 {
160 HikariPool p = pool;
161 if (p != null) {
162 p.getUnwrappedDataSource().setLoginTimeout(seconds);
163 }
164 }
165
166
167 @Override
168 public int getLoginTimeout() throws SQLException
169 {
170 HikariPool p = pool;
171 return (p != null ? p.getUnwrappedDataSource().getLoginTimeout() : 0);
172 }
173
174
175 @Override
176 public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
177 {
178 throw new SQLFeatureNotSupportedException();
179 }
180
181
182 @Override
183 @SuppressWarnings("unchecked")
184 public <T> T unwrap(Class<T> iface) throws SQLException
185 {
186 if (iface.isInstance(this)) {
187 return (T) this;
188 }
189
190 HikariPool p = pool;
191 if (p != null) {
192 final DataSource unwrappedDataSource = p.getUnwrappedDataSource();
193 if (iface.isInstance(unwrappedDataSource)) {
194 return (T) unwrappedDataSource;
195 }
196
197 if (unwrappedDataSource != null) {
198 return unwrappedDataSource.unwrap(iface);
199 }
200 }
201
202 throw new SQLException("Wrapped DataSource is not an instance of " + iface);
203 }
204
205
206 @Override
207 public boolean isWrapperFor(Class<?> iface) throws SQLException
208 {
209 if (iface.isInstance(this)) {
210 return true;
211 }
212
213 HikariPool p = pool;
214 if (p != null) {
215 final DataSource unwrappedDataSource = p.getUnwrappedDataSource();
216 if (iface.isInstance(unwrappedDataSource)) {
217 return true;
218 }
219
220 if (unwrappedDataSource != null) {
221 return unwrappedDataSource.isWrapperFor(iface);
222 }
223 }
224
225 return false;
226 }
227
228
229
230
231
232
233 @Override
234 public void setMetricRegistry(Object metricRegistry)
235 {
236 boolean isAlreadySet = getMetricRegistry() != null;
237 super.setMetricRegistry(metricRegistry);
238
239 HikariPool p = pool;
240 if (p != null) {
241 if (isAlreadySet) {
242 throw new IllegalStateException("MetricRegistry can only be set one time");
243 }
244 else {
245 p.setMetricRegistry(super.getMetricRegistry());
246 }
247 }
248 }
249
250
251 @Override
252 public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory)
253 {
254 boolean isAlreadySet = getMetricsTrackerFactory() != null;
255 super.setMetricsTrackerFactory(metricsTrackerFactory);
256
257 HikariPool p = pool;
258 if (p != null) {
259 if (isAlreadySet) {
260 throw new IllegalStateException("MetricsTrackerFactory can only be set one time");
261 }
262 else {
263 p.setMetricsTrackerFactory(super.getMetricsTrackerFactory());
264 }
265 }
266 }
267
268
269 @Override
270 public void setHealthCheckRegistry(Object healthCheckRegistry)
271 {
272 boolean isAlreadySet = getHealthCheckRegistry() != null;
273 super.setHealthCheckRegistry(healthCheckRegistry);
274
275 HikariPool p = pool;
276 if (p != null) {
277 if (isAlreadySet) {
278 throw new IllegalStateException("HealthCheckRegistry can only be set one time");
279 }
280 else {
281 p.setHealthCheckRegistry(super.getHealthCheckRegistry());
282 }
283 }
284 }
285
286
287
288
289
290
295 public boolean isRunning()
296 {
297 return pool != null && pool.poolState == POOL_NORMAL;
298 }
299
300
307 public HikariPoolMXBean getHikariPoolMXBean()
308 {
309 return pool;
310 }
311
312
317 public HikariConfigMXBean getHikariConfigMXBean()
318 {
319 return this;
320 }
321
322
329 public void evictConnection(Connection connection)
330 {
331 HikariPool p;
332 if (!isClosed() && (p = pool) != null && connection.getClass().getName().startsWith("com.zaxxer.hikari")) {
333 p.evictConnection(connection);
334 }
335 }
336
337
340 @Override
341 public void close()
342 {
343 if (isShutdown.getAndSet(true)) {
344 return;
345 }
346
347 HikariPool p = pool;
348 if (p != null) {
349 try {
350 LOGGER.info("{} - Shutdown initiated...", getPoolName());
351 p.shutdown();
352 LOGGER.info("{} - Shutdown completed.", getPoolName());
353 }
354 catch (InterruptedException e) {
355 LOGGER.warn("{} - Interrupted during closing", getPoolName(), e);
356 Thread.currentThread().interrupt();
357 }
358 }
359 }
360
361
366 public boolean isClosed()
367 {
368 return isShutdown.get();
369 }
370
371
372 @Override
373 public String toString()
374 {
375 return "HikariDataSource (" + pool + ")";
376 }
377 }
378