1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2005-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.database;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import org.jivesoftware.util.JiveGlobals;
import org.logicalcobwebs.proxool.ConnectionPoolDefinitionIF;
import org.logicalcobwebs.proxool.ProxoolException;
import org.logicalcobwebs.proxool.ProxoolFacade;
import org.logicalcobwebs.proxool.admin.SnapshotIF;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Default Jive connection provider, which uses an internal connection pool.<p>
*
* @author Jive Software
*/
public class DefaultConnectionProvider implements ConnectionProvider {
private static final Logger Log = LoggerFactory.getLogger(DefaultConnectionProvider.class);
private Properties settings;
private String driver;
private String serverURL;
private String proxoolURL;
private String username;
private String password;
private int minConnections = 3;
private int maxConnections = 10;
private int activeTimeout = 900000; // 15 minutes in milliseconds
private String testSQL = "";
private Boolean testBeforeUse = true;
private Boolean testAfterUse = true;
/**
* Maximum time a connection can be open before it's reopened (in days)
*/
private double connectionTimeout = 0.5;
/**
* MySQL doesn't currently support Unicode. However, a workaround is
* implemented in the mm.mysql JDBC driver. Setting the Jive property
* database.mysql.useUnicode to true will turn this feature on.
*/
private boolean mysqlUseUnicode;
/**
* Creates a new DefaultConnectionProvider.
*/
public DefaultConnectionProvider() {
loadProperties();
System.setProperty("org.apache.commons.logging.LogFactory", "org.jivesoftware.util.log.util.CommonsLogFactory");
}
public boolean isPooled() {
return true;
}
public Connection getConnection() throws SQLException {
try {
Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
return DriverManager.getConnection(proxoolURL, settings);
}
catch (ClassNotFoundException e) {
throw new SQLException("DbConnectionProvider: Unable to find driver: "+e);
}
}
public void start() {
proxoolURL = "proxool.openfire:"+getDriver()+":"+getServerURL();
settings = new Properties();
settings.setProperty("proxool.maximum-activetime", Integer.toString(activeTimeout));
settings.setProperty("proxool.maximum-connection-count", Integer.toString(getMaxConnections()));
settings.setProperty("proxool.minimum-connection-count", Integer.toString(getMinConnections()));
settings.setProperty("proxool.maximum-connection-lifetime", Integer.toString((int)(86400000 * getConnectionTimeout())));
settings.setProperty("proxool.test-before-use", testBeforeUse.toString());
settings.setProperty("proxool.test-after-use", testAfterUse.toString());
settings.setProperty("proxool.house-keeping-test-sql", testSQL);
settings.setProperty("user", getUsername());
settings.setProperty("password", (getPassword() != null ? getPassword() : ""));
}
public void restart() {
}
public void destroy() {
settings = null;
}
/**
* Returns the JDBC driver classname used to make database connections.
* For example: com.mysql.jdbc.Driver
*
* @return the JDBC driver classname.
*/
public String getDriver() {
return driver;
}
/**
* Sets the JDBC driver classname used to make database connections.
* For example: com.mysql.jdbc.Driver
*
* @param driver the fully qualified JDBC driver name.
*/
public void setDriver(String driver) {
this.driver = driver;
saveProperties();
}
/**
* Returns the JDBC connection URL used to make database connections.
*
* @return the JDBC connection URL.
*/
public String getServerURL() {
return serverURL;
}
/**
* Sets the JDBC connection URL used to make database connections.
*
* @param serverURL the JDBC connection URL.
*/
public void setServerURL(String serverURL) {
this.serverURL = serverURL;
saveProperties();
}
/**
* Returns the username used to connect to the database. In some cases,
* a username is not needed so this method will return null.
*
* @return the username used to connect to the datbase.
*/
public String getUsername() {
return username;
}
/**
* Sets the username used to connect to the database. In some cases, a
* username is not needed so null should be passed in.
*
* @param username the username used to connect to the database.
*/
public void setUsername(String username) {
this.username = username;
saveProperties();
}
/**
* Returns the password used to connect to the database. In some cases,
* a password is not needed so this method will return null.
*
* @return the password used to connect to the database.
*/
public String getPassword() {
return password;
}
/**
* Sets the password used to connect to the database. In some cases, a
* password is not needed so null should be passed in.
*
* @param password the password used to connect to the database.
*/
public void setPassword(String password) {
this.password = password;
saveProperties();
}
/**
* Returns the minimum number of connections that the pool will use. This
* should probably be at least three.
*
* @return the minimum number of connections in the pool.
*/
public int getMinConnections() {
return minConnections;
}
/**
* Sets the minimum number of connections that the pool will use. This
* should probably be at least three.
*
* @param minConnections the minimum number of connections in the pool.
*/
public void setMinConnections(int minConnections) {
this.minConnections = minConnections;
saveProperties();
}
/**
* Returns the maximum number of connections that the pool will use. The
* actual number of connections in the pool will vary between this value
* and the minimum based on the current load.
*
* @return the max possible number of connections in the pool.
*/
public int getMaxConnections() {
return maxConnections;
}
/**
* Sets the maximum number of connections that the pool will use. The
* actual number of connections in the pool will vary between this value
* and the minimum based on the current load.
*
* @param maxConnections the max possible number of connections in the pool.
*/
public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
saveProperties();
}
/**
* Returns the amount of time between connection recycles in days. For
* example, a value of .5 would correspond to recycling the connections
* in the pool once every half day.
*
* @return the amount of time in days between connection recycles.
*/
public double getConnectionTimeout() {
return connectionTimeout;
}
/**
* Sets the amount of time between connection recycles in days. For
* example, a value of .5 would correspond to recycling the connections
* in the pool once every half day.
*
* @param connectionTimeout the amount of time in days between connection
* recycles.
*/
public void setConnectionTimeout(double connectionTimeout) {
this.connectionTimeout = connectionTimeout;
saveProperties();
}
/**
* Returns the SQL statement used to test if a connection is valid.
*
* @return the SQL statement that will be run to test a connection.
*/
public String getTestSQL() {
return testSQL;
}
/**
* Sets the SQL statement used to test if a connection is valid. House keeping
* and before/after connection tests make use of this. This
* should be something that causes the minimal amount of work by the database
* server and is as quick as possible.
*
* @param testSQL the SQL statement that will be run to test a connection.
*/
public void setTestSQL(String testSQL) {
this.testSQL = testSQL;
}
/**
* Returns whether returned connections will be tested before being handed over
* to be used.
*
* @return True if connections are tested before use.
*/
public Boolean getTestBeforeUse() {
return testBeforeUse;
}
/**
* Sets whether connections will be tested before being handed over to be used.
*
* @param testBeforeUse True or false if connections are to be tested before use.
*/
public void setTestBeforeUse(Boolean testBeforeUse) {
this.testBeforeUse = testBeforeUse;
}
/**
* Returns whether returned connections will be tested after being returned to
* the pool.
*
* @return True if connections are tested after use.
*/
public Boolean getTestAfterUse() {
return testAfterUse;
}
/**
* Sets whether connections will be tested after being returned to the pool.
*
* @param testAfterUse True or false if connections are to be tested after use.
*/
public void setTestAfterUse(Boolean testAfterUse) {
this.testAfterUse = testAfterUse;
}
public boolean isMysqlUseUnicode() {
return mysqlUseUnicode;
}
/**
* Load properties that already exist from Jive properties.
*/
private void loadProperties() {
driver = JiveGlobals.getXMLProperty("database.defaultProvider.driver");
serverURL = JiveGlobals.getXMLProperty("database.defaultProvider.serverURL");
username = JiveGlobals.getXMLProperty("database.defaultProvider.username");
password = JiveGlobals.getXMLProperty("database.defaultProvider.password");
String minCons = JiveGlobals.getXMLProperty("database.defaultProvider.minConnections");
String maxCons = JiveGlobals.getXMLProperty("database.defaultProvider.maxConnections");
String conTimeout = JiveGlobals.getXMLProperty("database.defaultProvider.connectionTimeout");
testSQL = JiveGlobals.getXMLProperty("database.defaultProvider.testSQL", DbConnectionManager.getTestSQL(driver));
testBeforeUse = JiveGlobals.getXMLProperty("database.defaultProvider.testBeforeUse", false);
testAfterUse = JiveGlobals.getXMLProperty("database.defaultProvider.testAfterUse", false);
// See if we should use Unicode under MySQL
mysqlUseUnicode = Boolean.valueOf(JiveGlobals.getXMLProperty("database.mysql.useUnicode"));
try {
if (minCons != null) {
minConnections = Integer.parseInt(minCons);
}
if (maxCons != null) {
maxConnections = Integer.parseInt(maxCons);
}
if (conTimeout != null) {
connectionTimeout = Double.parseDouble(conTimeout);
}
}
catch (Exception e) {
Log.error("Error: could not parse default pool properties. " +
"Make sure the values exist and are correct.", e);
}
}
/**
* Save properties as Jive properties.
*/
private void saveProperties() {
JiveGlobals.setXMLProperty("database.defaultProvider.driver", driver);
JiveGlobals.setXMLProperty("database.defaultProvider.serverURL", serverURL);
JiveGlobals.setXMLProperty("database.defaultProvider.username", username);
JiveGlobals.setXMLProperty("database.defaultProvider.password", password);
JiveGlobals.setXMLProperty("database.defaultProvider.testSQL", testSQL);
JiveGlobals.setXMLProperty("database.defaultProvider.testBeforeUse", testBeforeUse.toString());
JiveGlobals.setXMLProperty("database.defaultProvider.testAfterUse", testAfterUse.toString());
JiveGlobals.setXMLProperty("database.defaultProvider.minConnections",
Integer.toString(minConnections));
JiveGlobals.setXMLProperty("database.defaultProvider.maxConnections",
Integer.toString(maxConnections));
JiveGlobals.setXMLProperty("database.defaultProvider.connectionTimeout",
Double.toString(connectionTimeout));
}
@Override
public String toString() {
try {
ConnectionPoolDefinitionIF poolDef = ProxoolFacade.getConnectionPoolDefinition("openfire");
SnapshotIF poolStats = ProxoolFacade.getSnapshot("openfire", true);
return poolDef.getMinimumConnectionCount()+","+poolDef.getMaximumConnectionCount()+","
+poolStats.getAvailableConnectionCount()+","+poolStats.getActiveConnectionCount();
}
catch (ProxoolException e) {
return "Default Connection Provider";
}
}
}