1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.db.jdbc;
18
19 import java.sql.DriverManager;
20 import java.sql.SQLException;
21 import java.util.Arrays;
22 import java.util.concurrent.TimeUnit;
23
24 import org.apache.commons.dbcp2.ConnectionFactory;
25 import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
26 import org.apache.commons.dbcp2.PoolableConnection;
27 import org.apache.commons.dbcp2.PoolableConnectionFactory;
28 import org.apache.commons.dbcp2.PoolingDriver;
29 import org.apache.commons.pool2.ObjectPool;
30 import org.apache.commons.pool2.impl.GenericObjectPool;
31 import org.apache.logging.log4j.core.Core;
32 import org.apache.logging.log4j.core.config.Property;
33 import org.apache.logging.log4j.core.config.plugins.Plugin;
34 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
35 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
36 import org.apache.logging.log4j.core.config.plugins.PluginElement;
37
38
39
40
41
42
43 @Plugin(name = "PoolingDriver", category = Core.CATEGORY_NAME, elementType = "connectionSource", printObject = true)
44 public final class PoolingDriverConnectionSource extends AbstractDriverManagerConnectionSource {
45
46
47
48
49
50
51
52 public static class Builder<B extends Builder<B>> extends AbstractDriverManagerConnectionSource.Builder<B>
53 implements org.apache.logging.log4j.core.util.Builder<PoolingDriverConnectionSource> {
54
55 public static final String DEFAULT_POOL_NAME = "example";
56
57 @PluginElement("PoolableConnectionFactoryConfig")
58 private PoolableConnectionFactoryConfig poolableConnectionFactoryConfig;
59
60 @PluginBuilderAttribute
61 private String poolName = DEFAULT_POOL_NAME;
62
63 @Override
64 public PoolingDriverConnectionSource build() {
65 try {
66 return new PoolingDriverConnectionSource(getDriverClassName(), getConnectionString(), getUserName(),
67 getPassword(), getProperties(), poolName, poolableConnectionFactoryConfig);
68 } catch (final SQLException e) {
69 getLogger().error("Exception constructing {} to '{}' with {}", PoolingDriverConnectionSource.class,
70 getConnectionString(), this, e);
71 return null;
72 }
73 }
74
75 public B setPoolableConnectionFactoryConfig(final PoolableConnectionFactoryConfig poolableConnectionFactoryConfig) {
76 this.poolableConnectionFactoryConfig = poolableConnectionFactoryConfig;
77 return asBuilder();
78 }
79
80 public B setPoolName(final String poolName) {
81 this.poolName = poolName;
82 return asBuilder();
83 }
84
85 @Override
86 public String toString() {
87 return "Builder [poolName=" + poolName + ", connectionString=" + connectionString + ", driverClassName="
88 + driverClassName + ", properties=" + Arrays.toString(properties) + ", userName="
89 + Arrays.toString(userName) + "]";
90 }
91 }
92
93 public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
94
95
96 @PluginBuilderFactory
97 public static <B extends Builder<B>> B newPoolingDriverConnectionSourceBuilder() {
98 return new Builder<B>().asBuilder();
99 }
100
101 private final String poolingDriverClassName = "org.apache.commons.dbcp2.PoolingDriver";
102
103 private final String poolName;
104
105
106
107
108 @Deprecated
109 public PoolingDriverConnectionSource(final String driverClassName, final String connectionString,
110 final char[] userName, final char[] password, final Property[] properties, final String poolName)
111 throws SQLException {
112 super(driverClassName, connectionString, URL_PREFIX + poolName, userName, password, properties);
113 this.poolName = poolName;
114 setupDriver(connectionString, null);
115 }
116
117 private PoolingDriverConnectionSource(final String driverClassName, final String connectionString,
118 final char[] userName, final char[] password, final Property[] properties, final String poolName,
119 final PoolableConnectionFactoryConfig poolableConnectionFactoryConfig)
120 throws SQLException {
121 super(driverClassName, connectionString, URL_PREFIX + poolName, userName, password, properties);
122 this.poolName = poolName;
123 setupDriver(connectionString, poolableConnectionFactoryConfig);
124 }
125
126 @Override
127 public String getActualConnectionString() {
128
129 return super.getActualConnectionString();
130 }
131
132 private PoolingDriver getPoolingDriver() throws SQLException {
133 final PoolingDriver driver = (PoolingDriver) DriverManager.getDriver(URL_PREFIX);
134 if (driver == null) {
135 getLogger().error("No JDBC driver for '{}'", URL_PREFIX);
136 }
137 return driver;
138 }
139
140 private void setupDriver(final String connectionString,
141 final PoolableConnectionFactoryConfig poolableConnectionFactoryConfig) throws SQLException {
142
143
144
145
146
147
148
149 final Property[] properties = getProperties();
150 final char[] userName = getUserName();
151 final char[] password = getPassword();
152 final ConnectionFactory connectionFactory;
153 if (properties != null && properties.length > 0) {
154 if (userName != null || password != null) {
155 throw new SQLException("Either set the userName and password, or set the Properties, but not both.");
156 }
157 connectionFactory = new DriverManagerConnectionFactory(connectionString, toProperties(properties));
158 } else {
159 connectionFactory = new DriverManagerConnectionFactory(connectionString, toString(userName), toString(password));
160 }
161
162
163
164
165
166
167 final PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
168 null);
169 if (poolableConnectionFactoryConfig != null) {
170 poolableConnectionFactoryConfig.init(poolableConnectionFactory);
171 }
172
173
174
175
176
177
178
179
180 @SuppressWarnings("resource")
181
182 final ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory);
183
184
185 poolableConnectionFactory.setPool(connectionPool);
186
187 loadDriver(poolingDriverClassName);
188 final PoolingDriver driver = getPoolingDriver();
189 if (driver != null) {
190 getLogger().debug("Registering DBCP pool '{}' with pooling driver {}: {}", poolName, driver, connectionPool);
191 driver.registerPool(poolName, connectionPool);
192 }
193
194
195
196
197 }
198
199 @Override
200 public boolean stop(final long timeout, final TimeUnit timeUnit) {
201 try {
202 final PoolingDriver driver = getPoolingDriver();
203 if (driver != null) {
204 getLogger().debug("Driver {} closing DBCP pool '{}'", driver, poolName);
205 driver.closePool(poolName);
206 }
207 return true;
208 } catch (final Exception e) {
209 getLogger().error("Exception stopping connection source for '{}' → '{}'", getConnectionString(),
210 getActualConnectionString(), e);
211 return false;
212 }
213 }
214 }