001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.module.database;
011:
012: import java.util.*;
013: import java.sql.*;
014:
015: import org.mmbase.util.*;
016: import org.mmbase.module.*;
017:
018: import org.mmbase.util.logging.*;
019:
020: /**
021: * JDBC Module.
022: * The module that provides you access to the loaded JDBC interfaces.
023: * We use this as the base to get multiplexes/pooled JDBC connects.
024: *
025: * @deprecation-used drop reference to {@link JDBCInterface}
026: * @author vpro
027: * @version $Id: JDBC.java,v 1.58 2008/02/20 10:34:22 michiel Exp $
028: */
029: public class JDBC extends ProcessorModule implements JDBCInterface {
030:
031: private static final Logger log = Logging
032: .getLoggerInstance(JDBC.class);
033:
034: private Class classdriver;
035: private Driver driver;
036: private String jdbcDriver;
037: private String jdbcHost;
038: private int jdbcPort = -1;
039: private int maxConnections;
040: private int maxQueries;
041: private String jdbcDatabase;
042: private String databaseSupportClass;
043: private DatabaseSupport databaseSupport;
044: private MultiPoolHandler poolHandler;
045: private JDBCProbe probe = null;
046: private String jdbcName;
047: private String jdbcPassword;
048: private long probeTime;
049: private long maxLifeTime = 120000;
050:
051: {
052: addFunction(new GetNodeListFunction("POOLS", PARAMS_PAGEINFO));
053: addFunction(new GetNodeListFunction("CONNECTIONS",
054: PARAMS_PAGEINFO));
055: }
056:
057: public JDBC(String name) {
058: super (name);
059: }
060:
061: public void onload() {
062: getProps();
063: getDriver();
064: loadSupport();
065: poolHandler = new MultiPoolHandler(databaseSupport,
066: maxConnections, maxQueries);
067: poolHandler.setMaxLifeTime(maxLifeTime);
068: }
069:
070: /*
071: * Initialize the properties and get the driver used
072: */
073: public void init() {
074: // This is now called in onload(), which is called before init()
075: // getProps();
076: probe = new JDBCProbe(this , probeTime);
077: log.info("Module JDBC started (" + this + ")");
078:
079: }
080:
081: /**
082: * {@inheritDoc}
083: * Reload the properties and driver
084: */
085: public void reload() {
086: getProps();
087:
088: /* This doesn't work, have to figure out why
089: try {
090: DriverManager.deregisterDriver(driver);
091: } catch (SQLException e) {
092: debug("reload(): JDBC Module: Can't deregister driver");
093: }
094: */
095: loadSupport();
096: getDriver();
097: }
098:
099: public void unload() {
100: }
101:
102: protected void shutdown() {
103: poolHandler.shutdown();
104: }
105:
106: /**
107: * Get the driver as specified in our properties
108: */
109: private void getDriver() {
110:
111: driver = null;
112: try {
113: classdriver = Class.forName(jdbcDriver);
114:
115: // marmaa@vpro.nl:
116: // This is how McKoi's JDBC drivers wants itself
117: // to be registered; should have no effect on other drivers
118: Driver d = (Driver) Class.forName(jdbcDriver).newInstance();
119: log.service("Loaded JDBC driver: " + jdbcDriver + " "
120: + d.getMajorVersion() + "." + d.getMinorVersion());
121:
122: } catch (Exception e) {
123: log.fatal("JDBC driver not found: " + jdbcDriver, e);
124: }
125:
126: if (log.isDebugEnabled()) {
127: log.debug("makeUrl(): " + makeUrl());
128: }
129:
130: /* Also get the instance to unload it later */
131: for (Enumeration e = DriverManager.getDrivers(); e
132: .hasMoreElements();) {
133: Driver d = (Driver) e.nextElement();
134: if (log.isDebugEnabled()) {
135: log.debug("Driver " + d);
136: }
137: if (classdriver == d.getClass()) {
138: driver = d;
139: break;
140: }
141: }
142: if (driver == null) {
143: log
144: .warn("getDriver(): the jdbc driver specified in jdbc.xml '"
145: + jdbcDriver
146: + "' does not match any actually loaded drivers "
147: + Collections.list(DriverManager
148: .getDrivers()));
149: }
150: }
151:
152: /**
153: * Get the driver as specified in our properties
154: */
155: private void loadSupport() {
156: try {
157: Class cl = Class.forName(databaseSupportClass);
158: databaseSupport = (DatabaseSupport) cl.newInstance();
159: databaseSupport.init();
160: log.debug("Loaded load class : " + databaseSupportClass);
161: } catch (Exception e) {
162: log.error("Can't load class : " + databaseSupportClass
163: + " " + e.getMessage(), e);
164: }
165: }
166:
167: /**
168: * @since MMBase-1.8.5
169: */
170: public DatabaseSupport getSupport() {
171: return databaseSupport;
172: }
173:
174: /**
175: * Get the properties
176: */
177: private void getProps() {
178:
179: jdbcDriver = getInitParameter("driver");
180: jdbcHost = getInitParameter("host");
181: jdbcName = getInitParameter("user");
182: if (jdbcName == null) {
183: jdbcName = "wwwtech";
184: log.warn("Name was not set, using default: '" + jdbcName
185: + "'");
186: }
187:
188: jdbcPassword = getInitParameter("password");
189:
190: databaseSupportClass = getInitParameter("supportclass");
191: probeTime = 30000;
192: String tmp = getInitParameter("probetime");
193: if (tmp != null) {
194: try {
195: probeTime = Float.valueOf(tmp).longValue() * 1000;
196: log.info("Set jdbc-probeTime to " + probeTime + " ms");
197: } catch (NumberFormatException e) {
198: log.warn("Specified probetime is not a invalid float :"
199: + e + "(using default " + (probeTime / 1000)
200: + " s)");
201: }
202: }
203:
204: tmp = getInitParameter("maxlifetime");
205: if (tmp != null) {
206: try {
207: maxLifeTime = (long) (Float.parseFloat(tmp) * 1000f);
208: log.service("Set jdbc max life time to " + maxLifeTime
209: + " ms");
210: } catch (NumberFormatException e) {
211: log
212: .warn("Specified max life time is not a invalid float :"
213: + e
214: + "(using default "
215: + (maxLifeTime / 1000) + " s)");
216: }
217: }
218:
219: tmp = getInitParameter("port");
220: if (tmp != null) {
221: try {
222: jdbcPort = Integer.parseInt(getInitParameter("port"));
223: } catch (NumberFormatException e) {
224: jdbcPort = 0;
225: log
226: .warn("portnumber was not set or a invalid integer :"
227: + e
228: + "(using default "
229: + jdbcPort
230: + ")");
231: }
232: }
233: try {
234: maxConnections = Integer
235: .parseInt(getInitParameter("connections"));
236: } catch (Exception e) {
237: maxConnections = 8;
238: log.warn("connections was not set or a invalid integer :"
239: + e + "(using default " + maxConnections + ")");
240: }
241: try {
242: maxQueries = Integer.parseInt(getInitParameter("queries"));
243: } catch (Exception f) {
244: try {
245: maxQueries = Integer
246: .parseInt(getInitParameter("querys")); //fall back backward compatible
247: } catch (Exception e) {
248: maxQueries = 500;
249: log.warn("queries was not set or a invalid integer :"
250: + e + "(using default " + maxQueries + ")");
251: }
252: }
253: jdbcDatabase = getInitParameter("database");
254: if (databaseSupportClass == null
255: || databaseSupportClass.length() == 0) {
256: databaseSupportClass = "org.mmbase.module.database.DatabaseSupportShim";
257: log
258: .debug("database supportclass was not known, using default: "
259: + databaseSupportClass);
260: }
261: }
262:
263: /**
264: * Routine build the url to give to the DriverManager
265: * to open the connection. This way a servlet/module
266: * doesn't need to care about what database it talks to.
267: * @see java.sql.DriverManager#getConnection(java.lang.String)
268: */
269: public String makeUrl() {
270: return makeUrl(jdbcHost, jdbcPort, jdbcDatabase);
271: }
272:
273: /**
274: * Routine build the url to give to the DriverManager
275: * to open the connection. This way a servlet/module
276: * doesn't need to care about what database it talks to.
277: * @see java.sql.DriverManager#getConnection(java.lang.String)
278: */
279: public String makeUrl(String dbm) {
280: return makeUrl(jdbcHost, jdbcPort, dbm);
281: }
282:
283: /**
284: * Routine build the url to give to the DriverManager
285: * to open the connection. This way a servlet/module
286: * doesn't need to care about what database it talks to.
287: * @see java.sql.DriverManager#getConnection(java.lang.String)
288: */
289: public String makeUrl(String host, String dbm) {
290: return makeUrl(host, jdbcPort, dbm);
291: }
292:
293: /**
294: * Routine build the url to give to the DriverManager
295: * to open the connection. This way a servlet/module
296: * doesn't need to care about what database it talks to.
297: * @see java.sql.DriverManager#getConnection(java.lang.String)
298: */
299: public String makeUrl(String host, int port, String dbm) {
300: String url = getInitParameter("url");
301: // $HOST $DBM $PORT
302: if (dbm == null)
303: dbm = "mmbase";
304: url = url.replaceAll("\\$DBM", dbm);
305: if (host == null)
306: host = "localhost";
307: url = url.replaceAll("\\$HOST", host);
308: url = url.replaceAll("\\$PORT", "" + port);
309:
310: return url;
311: }
312:
313: /**
314: * @javadoc
315: */
316: public MultiConnection getConnection(String url, String name,
317: String password) throws SQLException {
318: return poolHandler.getConnection(url, name, password);
319: }
320:
321: /**
322: * @javadoc
323: */
324: public MultiConnection getConnection(String url)
325: throws SQLException {
326: return poolHandler.getConnection(url, jdbcName, jdbcPassword);
327: }
328:
329: /**
330: * @javadoc
331: */
332: public Connection getDirectConnection(String url, String name,
333: String password) throws SQLException {
334: return DriverManager.getConnection(url, name, password);
335: }
336:
337: /**
338: * @javadoc
339: */
340: public Connection getDirectConnection(String url)
341: throws SQLException {
342: return DriverManager.getConnection(url, jdbcName, jdbcPassword);
343: }
344:
345: /**
346: * @javadoc
347: */
348: public synchronized void checkTime() {
349: try {
350: if (poolHandler != null)
351: poolHandler.checkTime();
352: } catch (Exception e) {
353: log.error("could not check the time: " + e, e);
354: }
355: }
356:
357: /**
358: * User interface stuff
359: * @javadoc
360: */
361: public Vector getList(PageInfo sp, StringTagger tagger, String value) {
362: String line = Strip.DoubleQuote(value, Strip.BOTH);
363: StringTokenizer tok = new StringTokenizer(line, "-\n\r");
364: if (tok.hasMoreTokens()) {
365: String cmd = tok.nextToken();
366: if (cmd.equals("POOLS"))
367: return listPools(tagger);
368: if (cmd.equals("CONNECTIONS"))
369: return listConnections(tagger);
370: }
371: return null;
372: }
373:
374: // Strips senssitive info (such as password and username) from the
375: // database name
376: private String stripSensistive(String name) {
377: // strip either after the first '?', or the first ',',
378: // whichever comes first
379: int i = name.indexOf('?');
380: int j = name.indexOf(',');
381: if ((i > j) && (j != -1))
382: i = j;
383: if (i != -1) {
384: return name.substring(0, i);
385: } else {
386: return name;
387: }
388: }
389:
390: /**
391: * @javadoc
392: */
393: public Vector listPools(StringTagger tagger) {
394: Vector results = new Vector();
395: for (Object element : poolHandler.keySet()) {
396: String name = (String) element;
397: MultiPool pool = poolHandler.get(name);
398: results.addElement(stripSensistive(name));
399: results.addElement("" + pool.getSize());
400: results.addElement("" + pool.getTotalConnectionsCreated());
401: }
402: tagger.setValue("ITEMS", "3");
403: return results;
404: }
405:
406: /**
407: * @javadoc
408: */
409: public Vector listConnections(StringTagger tagger) {
410: Vector results = new Vector();
411: for (Object element : poolHandler.keySet()) {
412: String name = (String) element;
413: MultiPool pool = poolHandler.get(name);
414: for (Iterator f = pool.getBusyPool(); f.hasNext();) {
415: MultiConnection realcon = (MultiConnection) f.next();
416: results.addElement(stripSensistive(name.substring(name
417: .lastIndexOf('/') + 1)));
418: results.addElement(realcon.getStateString());
419: results.addElement("" + realcon.getLastSQL());
420: results.addElement("" + realcon.getUsage());
421: //results.addElement(""+pool.getStatementsCreated(realcon));
422: }
423: for (Iterator f = pool.getPool(); f.hasNext();) {
424: MultiConnection realcon = (MultiConnection) f.next();
425: results.addElement(stripSensistive(name.substring(name
426: .lastIndexOf('/') + 1)));
427: results.addElement(realcon.getStateString());
428: results.addElement("" + realcon.getLastSQL());
429: results.addElement("" + realcon.getUsage());
430: //results.addElement(""+pool.getStatementsCreated(realcon));
431: }
432: }
433: tagger.setValue("ITEMS", "4");
434: return results;
435: }
436:
437: /**
438: * @javadoc
439: */
440: public String getUser() {
441: return jdbcName;
442: }
443:
444: /**
445: * @javadoc
446: */
447: public String getPassword() {
448: return jdbcPassword;
449: }
450:
451: /**
452: * @javadoc
453: */
454: public String getDatabaseName() {
455: return getInitParameter("database");
456: }
457:
458: /**
459: * Give some info about the jdbc connection
460: * @return a <code>String</code> whith some information about the connection
461: */
462: public String toString() {
463: return "host: '"
464: + jdbcHost
465: + "' port: '"
466: + jdbcPort
467: + "' database: '"
468: + jdbcDatabase
469: + "' user: '"
470: + jdbcName
471: + "'"
472: + (driver != null ? " driver: "
473: + driver.getClass().getName() + "'" : "")
474: + " max life time: " + maxLifeTime
475: + " ms probe time: " + probeTime + " ms";
476: }
477: }
|