001: /**
002: * $RCSfile$
003: * $Revision: 9824 $
004: * $Date: 2008-01-24 07:04:20 -0800 (Thu, 24 Jan 2008) $
005: *
006: * Copyright (C) 2007 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.database;
011:
012: import org.jivesoftware.util.JiveGlobals;
013: import org.jivesoftware.util.Log;
014:
015: import java.sql.Connection;
016: import java.sql.SQLException;
017: import java.sql.DriverManager;
018: import java.util.Properties;
019:
020: /**
021: * Default Jive connection provider, which uses an internal connection pool.<p>
022: *
023: * @author Jive Software
024: */
025: public class DefaultConnectionProvider implements ConnectionProvider {
026:
027: private Properties settings;
028: private String driver;
029: private String serverURL;
030: private String proxoolURL;
031: private String username;
032: private String password;
033: private int minConnections = 3;
034: private int maxConnections = 10;
035: private String testSQL = "select 1";
036: private Boolean testBeforeUse = true;
037: private Boolean testAfterUse = true;
038:
039: /**
040: * Maximum time a connection can be open before it's reopened (in days)
041: */
042: private double connectionTimeout = 0.5;
043:
044: /**
045: * MySQL doesn't currently support Unicode. However, a workaround is
046: * implemented in the mm.mysql JDBC driver. Setting the Jive property
047: * database.mysql.useUnicode to true will turn this feature on.
048: */
049: private boolean mysqlUseUnicode;
050:
051: /**
052: * Creates a new DefaultConnectionProvider.
053: */
054: public DefaultConnectionProvider() {
055: loadProperties();
056:
057: System.setProperty("org.apache.commons.logging.LogFactory",
058: "org.jivesoftware.util.log.util.CommonsLogFactory");
059: }
060:
061: public boolean isPooled() {
062: return true;
063: }
064:
065: public Connection getConnection() throws SQLException {
066: Connection connection = null;
067: try {
068: Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
069: try {
070: connection = DriverManager.getConnection(proxoolURL,
071: settings);
072: } catch (SQLException e) {
073: Log
074: .error(
075: "DbConnectionProvider: Error while getting connection: ",
076: e);
077: }
078: } catch (ClassNotFoundException e) {
079: Log.error("DbConnectionProvider: Unable to find driver: ",
080: e);
081: }
082: return connection;
083: }
084:
085: public void start() {
086: proxoolURL = "proxool.openfire:" + getDriver() + ":"
087: + getServerURL();
088: settings = new Properties();
089: settings.setProperty("proxool.maximum-connection-count",
090: Integer.toString(getMaxConnections()));
091: settings.setProperty("proxool.minimum-connection-count",
092: Integer.toString(getMinConnections()));
093: settings
094: .setProperty(
095: "proxool.maximum-connection-lifetime",
096: Integer
097: .toString((int) (86400000 * getConnectionTimeout())));
098: settings.setProperty("proxool.test-before-use", testBeforeUse
099: .toString());
100: settings.setProperty("proxool.test-after-use", testAfterUse
101: .toString());
102: settings.setProperty("proxool.house-keeping-test-sql", testSQL);
103: settings.setProperty("user", getUsername());
104: settings.setProperty("password",
105: (getPassword() != null ? getPassword() : ""));
106: }
107:
108: public void restart() {
109: }
110:
111: public void destroy() {
112: settings = null;
113: }
114:
115: /**
116: * Returns the JDBC driver classname used to make database connections.
117: * For example: com.mysql.jdbc.Driver
118: *
119: * @return the JDBC driver classname.
120: */
121: public String getDriver() {
122: return driver;
123: }
124:
125: /**
126: * Sets the JDBC driver classname used to make database connections.
127: * For example: com.mysql.jdbc.Driver
128: *
129: * @param driver the fully qualified JDBC driver name.
130: */
131: public void setDriver(String driver) {
132: this .driver = driver;
133: saveProperties();
134: }
135:
136: /**
137: * Returns the JDBC connection URL used to make database connections.
138: *
139: * @return the JDBC connection URL.
140: */
141: public String getServerURL() {
142: return serverURL;
143: }
144:
145: /**
146: * Sets the JDBC connection URL used to make database connections.
147: *
148: * @param serverURL the JDBC connection URL.
149: */
150: public void setServerURL(String serverURL) {
151: this .serverURL = serverURL;
152: saveProperties();
153: }
154:
155: /**
156: * Returns the username used to connect to the database. In some cases,
157: * a username is not needed so this method will return null.
158: *
159: * @return the username used to connect to the datbase.
160: */
161: public String getUsername() {
162: return username;
163: }
164:
165: /**
166: * Sets the username used to connect to the database. In some cases, a
167: * username is not needed so null should be passed in.
168: *
169: * @param username the username used to connect to the database.
170: */
171: public void setUsername(String username) {
172: this .username = username;
173: saveProperties();
174: }
175:
176: /**
177: * Returns the password used to connect to the database. In some cases,
178: * a password is not needed so this method will return null.
179: *
180: * @return the password used to connect to the database.
181: */
182: public String getPassword() {
183: return password;
184: }
185:
186: /**
187: * Sets the password used to connect to the database. In some cases, a
188: * password is not needed so null should be passed in.
189: *
190: * @param password the password used to connect to the database.
191: */
192: public void setPassword(String password) {
193: this .password = password;
194: saveProperties();
195: }
196:
197: /**
198: * Returns the minimum number of connections that the pool will use. This
199: * should probably be at least three.
200: *
201: * @return the minimum number of connections in the pool.
202: */
203: public int getMinConnections() {
204: return minConnections;
205: }
206:
207: /**
208: * Sets the minimum number of connections that the pool will use. This
209: * should probably be at least three.
210: *
211: * @param minConnections the minimum number of connections in the pool.
212: */
213: public void setMinConnections(int minConnections) {
214: this .minConnections = minConnections;
215: saveProperties();
216: }
217:
218: /**
219: * Returns the maximum number of connections that the pool will use. The
220: * actual number of connections in the pool will vary between this value
221: * and the minimum based on the current load.
222: *
223: * @return the max possible number of connections in the pool.
224: */
225: public int getMaxConnections() {
226: return maxConnections;
227: }
228:
229: /**
230: * Sets the maximum number of connections that the pool will use. The
231: * actual number of connections in the pool will vary between this value
232: * and the minimum based on the current load.
233: *
234: * @param maxConnections the max possible number of connections in the pool.
235: */
236: public void setMaxConnections(int maxConnections) {
237: this .maxConnections = maxConnections;
238: saveProperties();
239: }
240:
241: /**
242: * Returns the amount of time between connection recycles in days. For
243: * example, a value of .5 would correspond to recycling the connections
244: * in the pool once every half day.
245: *
246: * @return the amount of time in days between connection recycles.
247: */
248: public double getConnectionTimeout() {
249: return connectionTimeout;
250: }
251:
252: /**
253: * Sets the amount of time between connection recycles in days. For
254: * example, a value of .5 would correspond to recycling the connections
255: * in the pool once every half day.
256: *
257: * @param connectionTimeout the amount of time in days between connection
258: * recycles.
259: */
260: public void setConnectionTimeout(double connectionTimeout) {
261: this .connectionTimeout = connectionTimeout;
262: saveProperties();
263: }
264:
265: /**
266: * Returns the SQL statement used to test if a connection is valid.
267: *
268: * @return the SQL statement that will be run to test a connection.
269: */
270: public String getTestSQL() {
271: return testSQL;
272: }
273:
274: /**
275: * Sets the SQL statement used to test if a connection is valid. House keeping
276: * and before/after connection tests make use of this. This
277: * should be something that causes the minimal amount of work by the database
278: * server and is as quick as possible.
279: *
280: * @param testSQL the SQL statement that will be run to test a connection.
281: */
282: public void setTestSQL(String testSQL) {
283: this .testSQL = testSQL;
284: }
285:
286: /**
287: * Returns whether returned connections will be tested before being handed over
288: * to be used.
289: *
290: * @return True if connections are tested before use.
291: */
292: public Boolean getTestBeforeUse() {
293: return testBeforeUse;
294: }
295:
296: /**
297: * Sets whether connections will be tested before being handed over to be used.
298: *
299: * @param testBeforeUse True or false if connections are to be tested before use.
300: */
301: public void setTestBeforeUse(Boolean testBeforeUse) {
302: this .testBeforeUse = testBeforeUse;
303: }
304:
305: /**
306: * Returns whether returned connections will be tested after being returned to
307: * the pool.
308: *
309: * @return True if connections are tested after use.
310: */
311: public Boolean getTestAfterUse() {
312: return testAfterUse;
313: }
314:
315: /**
316: * Sets whether connections will be tested after being returned to the pool.
317: *
318: * @param testAfterUse True or false if connections are to be tested after use.
319: */
320: public void setTestAfterUse(Boolean testAfterUse) {
321: this .testAfterUse = testAfterUse;
322: }
323:
324: public boolean isMysqlUseUnicode() {
325: return mysqlUseUnicode;
326: }
327:
328: /**
329: * Load properties that already exist from Jive properties.
330: */
331: private void loadProperties() {
332: driver = JiveGlobals
333: .getXMLProperty("database.defaultProvider.driver");
334: serverURL = JiveGlobals
335: .getXMLProperty("database.defaultProvider.serverURL");
336: username = JiveGlobals
337: .getXMLProperty("database.defaultProvider.username");
338: password = JiveGlobals
339: .getXMLProperty("database.defaultProvider.password");
340: String minCons = JiveGlobals
341: .getXMLProperty("database.defaultProvider.minConnections");
342: String maxCons = JiveGlobals
343: .getXMLProperty("database.defaultProvider.maxConnections");
344: String conTimeout = JiveGlobals
345: .getXMLProperty("database.defaultProvider.connectionTimeout");
346: testSQL = JiveGlobals.getXMLProperty(
347: "database.defaultProvider.testSQL", "select 1");
348: testBeforeUse = JiveGlobals.getXMLProperty(
349: "database.defaultProvider.testBeforeUse", true);
350: testAfterUse = JiveGlobals.getXMLProperty(
351: "database.defaultProvider.testAfterUse", true);
352:
353: // See if we should use Unicode under MySQL
354: mysqlUseUnicode = Boolean.valueOf(JiveGlobals
355: .getXMLProperty("database.mysql.useUnicode"));
356: try {
357: if (minCons != null) {
358: minConnections = Integer.parseInt(minCons);
359: }
360: if (maxCons != null) {
361: maxConnections = Integer.parseInt(maxCons);
362: }
363: if (conTimeout != null) {
364: connectionTimeout = Double.parseDouble(conTimeout);
365: }
366: } catch (Exception e) {
367: Log
368: .error(
369: "Error: could not parse default pool properties. "
370: + "Make sure the values exist and are correct.",
371: e);
372: }
373: }
374:
375: /**
376: * Save properties as Jive properties.
377: */
378: private void saveProperties() {
379:
380: JiveGlobals.setXMLProperty("database.defaultProvider.driver",
381: driver);
382: JiveGlobals.setXMLProperty(
383: "database.defaultProvider.serverURL", serverURL);
384: JiveGlobals.setXMLProperty("database.defaultProvider.username",
385: username);
386: JiveGlobals.setXMLProperty("database.defaultProvider.password",
387: password);
388: JiveGlobals.setXMLProperty("database.defaultProvider.testSQL",
389: testSQL);
390: JiveGlobals.setXMLProperty(
391: "database.defaultProvider.testBeforeUse", testBeforeUse
392: .toString());
393: JiveGlobals.setXMLProperty(
394: "database.defaultProvider.testAfterUse", testAfterUse
395: .toString());
396:
397: JiveGlobals.setXMLProperty(
398: "database.defaultProvider.minConnections", Integer
399: .toString(minConnections));
400: JiveGlobals.setXMLProperty(
401: "database.defaultProvider.maxConnections", Integer
402: .toString(maxConnections));
403: JiveGlobals.setXMLProperty(
404: "database.defaultProvider.connectionTimeout", Double
405: .toString(connectionTimeout));
406: }
407:
408: public String toString() {
409: return "Default Connection Provider";
410: }
411: }
|