Public Member Functions | |
Driver () | |
java.sql.Connection | connect (String url, Properties info) throws SQLException |
synchronized boolean | acceptsURL (String url) throws SQLException |
DriverPropertyInfo[] | getPropertyInfo (String url, Properties info) throws SQLException |
int | getMajorVersion () |
int | getMinorVersion () |
boolean | jdbcCompliant () |
Static Public Attributes | |
final int | MAJOR_VERSION |
final int | MINOR_VERSION |
Protected Member Functions | |
ArrayList | getControllerConfig () |
String | getUrlFromProperties (Hashtable props) |
Protected Attributes | |
ArrayList | pendingConnectionClosing = new ArrayList() |
boolean | connectionClosingThreadisAlive = false |
Static Protected Attributes | |
final String | DATABASE_PROPERTY = "DATABASE" |
final String | USER_PROPERTY = "user" |
final String | PASSWORD_PROPERTY = "password" |
final String | PARAMETER_PROPERTY = "parameter" |
final String | BOOLEAN_TRUE_PROPERTY = "booleanTrue" |
final String | BOOLEAN_FALSE_PROPERTY = "booleanFalse" |
final String | ESCAPE_BACKSLASH_PROPERTY = "escapeBackslash" |
final String | ESCAPE_SINGLE_QUOTE_PROPERTY = "escapeSingleQuote" |
final String | ESCAPE_CHARACTER_PROPERTY = "escapeCharacter" |
final String | DRIVER_PROCESSED_PROPERTY = "driverProcessed" |
Package Functions | |
synchronized Hashtable | parseURL (String url) throws SQLException |
Static Package Functions | |
[static initializer] |
The C-JDBC driver can be loaded from the client with: Class.forName("org.objectweb.cjdbc.driver.Driver");
The URL expected for the use with C-JDBC is: jdbc:cjdbc://host1:port1,host2:port2/database
.
At least one host must be specified. If several hosts are given, one is picked up randomly from the list. If the currently selected controller fails, another one is automatically picked up from the list.
Default port number is 25322 if omitted.
Those 2 examples are equivalent:
DriverManager.getConnection("jdbc:cjdbc://localhost:/tpcw"); DriverManager.getConnection("jdbc:cjdbc://localhost:25322/tpcw");
Examples using 2 controllers for fault tolerance:
DriverManager .getConnection("jdbc:cjdbc://cluster1.objectweb.org:25322,cluster2.objectweb.org:25322/tpcw"); DriverManager .getConnection("jdbc:cjdbc://localhost:25322,remote.objectweb.org:25322/tpcw"); DriverManager .getConnection("jdbc:cjdbc://smpnode.com:25322,smpnode.com:1098/tpcw");
This code has been inspired from the PostgreSQL JDBC driver by Peter T. Mount <peter@retep.org.uk>and the MM MySQL JDBC Drivers from Mark Matthews <mmatthew@worldserver.com>.
Definition at line 105 of file Driver.java.
|
Creates a new Definition at line 195 of file Driver.java. 00196 { 00197 // Required for Class.forName().newInstance() 00198 random = new Random(System.currentTimeMillis()); 00199 }
|
|
Tests if the URL is understood by the driver. Calls the
Definition at line 446 of file Driver.java. References org.objectweb.cjdbc.driver.Driver.parseURL(). 00447 { 00448 try 00449 { 00450 parseURL(url); 00451 return true; 00452 } 00453 catch (SQLException e) 00454 { 00455 return false; 00456 } 00457 }
|
|
Asks the C-JDBC controller if the requested database can be accessed with the provided user name and password. If the C-JDBC controller can't access the requested database, an
We cannot raise a SQLException as the driver manager tries to connect to all registered drivers. So if the CJDBC_URL_HEADER is not found we should probably pass... and return Definition at line 215 of file Driver.java. References org.objectweb.cjdbc.common.stream.CJDBCOutputStream.flush(), org.objectweb.cjdbc.common.sql.filters.AbstractBlobFilter.getBlobFilterInstance(), org.objectweb.cjdbc.common.net.SSLConfiguration.getDefaultConfig(), org.objectweb.cjdbc.driver.Driver.ControllerInfo.getHostname(), org.objectweb.cjdbc.driver.Connection.getPassword(), org.objectweb.cjdbc.driver.Driver.ControllerInfo.getPort(), org.objectweb.cjdbc.driver.Connection.getURL(), org.objectweb.cjdbc.driver.Connection.getUserName(), org.objectweb.cjdbc.driver.Connection.isClosed, org.objectweb.cjdbc.driver.Driver.parseURL(), org.objectweb.cjdbc.driver.Driver.pendingConnectionClosing, org.objectweb.cjdbc.common.stream.CJDBCInputStream.readObject(), org.objectweb.cjdbc.common.stream.CJDBCInputStream.readUTF(), org.objectweb.cjdbc.common.stream.CJDBCOutputStream.writeInt(), and org.objectweb.cjdbc.common.stream.CJDBCOutputStream.writeUTF(). Referenced by org.objectweb.cjdbc.driver.DataSource.getConnection(). 00217 { 00218 if (url == null) 00219 throw new SQLException("Invalid null URL in connect"); 00220 00221 /** 00222 * We cannot raise a SQLException as the driver manager tries to connect to 00223 * all registered drivers. So if the CJDBC_URL_HEADER is not found we should 00224 * probably pass... and return <code>null</code> 00225 */ 00226 if (!url.toLowerCase().startsWith(CJDBC_URL_HEADER)) 00227 return null; 00228 00229 String user = null; 00230 if (info != null) 00231 user = info.getProperty(USER_PROPERTY); 00232 else 00233 { 00234 info = new Properties(); 00235 } 00236 00237 // Parse url to get parameters 00238 Hashtable props = this.parseUrlParams(url); 00239 if (props != null) 00240 info.putAll(props); 00241 00242 if (user == null || user.equals("")) 00243 { 00244 if ((user = info.getProperty(USER_PROPERTY)) == null) 00245 throw new SQLException("Invalid null user name in connect"); 00246 } 00247 00248 String password = info.getProperty(PASSWORD_PROPERTY); 00249 if (password == null) 00250 { 00251 password = ""; 00252 } 00253 00254 // SSL enabled ? 00255 SSLConfiguration ssl = null; 00256 if ("true".equals(System.getProperty("cjdbc.ssl.enabled"))) 00257 { 00258 ssl = SSLConfiguration.getDefaultConfig(); 00259 } 00260 00261 // Check if there is a connection that is about to be closed that could 00262 // be reused. We take the bet that if a connection has been released by 00263 // a client, in the general case, it will reuse the same connection. 00264 // As we need to keep the work in the synchronized block as minimal as 00265 // possible, we have to extract the string comparison (url,name,password) 00266 // from the sync block. This way, we cannot just read/compare/take the 00267 // connection without synchronizing the whole thing. A solution is to 00268 // systematically extract the first available connection in the sync block, 00269 // and do the checkings outside the block. If we fail, we re-sync to put 00270 // the connection back but in practice it is almost always a success and 00271 // we don't really care to pay this extra cost once in a while. 00272 try 00273 { 00274 Connection c; 00275 synchronized (pendingConnectionClosing) 00276 { 00277 // Take the last one to prevent shifting all elements 00278 c = (Connection) pendingConnectionClosing 00279 .remove(pendingConnectionClosing.size() - 1); 00280 } 00281 if (url.equals(c.getURL()) && user.equals(c.getUserName()) 00282 && password.equals(c.getPassword())) 00283 { // Great! Take this one. 00284 c.isClosed = false; 00285 return setParametersOnConnection(info, c); 00286 } 00287 else 00288 // Put this connection back, it is not good for us 00289 synchronized (pendingConnectionClosing) 00290 { 00291 pendingConnectionClosing.add(c); 00292 } 00293 } 00294 catch (IndexOutOfBoundsException ignore) 00295 { 00296 // No connection available 00297 } 00298 00299 int retry = 2; 00300 int picked; 00301 while (retry > 0) 00302 { 00303 // Check if the last url used was the same, if yes we re-use the 00304 // same controller and connection point. 00305 synchronized (this) 00306 { 00307 if (!url.equals(currentControllerURL) 00308 || (connectionRequestSinceControllerFailure >= RETRY_CONTROLLER_AFTER_FAILURE) 00309 || ((controllerConfig != null) && (controllerConfig.size() == 0))) 00310 { // Too bad, all caches missed 00311 ControllerInfo[] controllerConfigArray = (ControllerInfo[]) controllerCache 00312 .get(url); 00313 if (controllerConfigArray == null) // Not in the cache 00314 { 00315 parseURL(url); 00316 controllerConfigArray = (ControllerInfo[]) controllerCache.get(url); 00317 } 00318 controllerConfig = new ArrayList(); 00319 controllerConfigArraySize = controllerConfigArray.length; 00320 for (int i = 0; i < controllerConfigArraySize; i++) 00321 controllerConfig.add(controllerConfigArray[i]); 00322 00323 currentControllerURL = url; 00324 currentDatabase = (String) dbNameCache.get(url); 00325 if (currentDatabase == null) 00326 throw new SQLException("Database name cache failure"); 00327 00328 // Give all controllers a chance 00329 retry = controllerConfig.size(); 00330 connectionRequestSinceControllerFailure = 0; 00331 } 00332 } 00333 00334 int size = controllerConfig.size(); 00335 if (size < controllerConfigArraySize) 00336 connectionRequestSinceControllerFailure++; 00337 00338 // Pick one controller randomly among the controllers that have not been 00339 // tried yet. 00340 picked = random.nextInt(size); 00341 currentControllerConfig = (ControllerInfo) controllerConfig.get(picked); 00342 00343 boolean sentVdbName = false; 00344 boolean sentUserInfo = false; 00345 try 00346 { 00347 // Connect to the controller 00348 Socket socket = null; 00349 if (ssl == null) 00350 { 00351 // no ssl - we use ordinary socket 00352 socket = new Socket(currentControllerConfig.getHostname(), 00353 currentControllerConfig.getPort()); 00354 } 00355 else 00356 { 00357 SocketFactory sslFact = SocketFactoryFactory.createFactory(ssl); 00358 socket = sslFact.createSocket(currentControllerConfig.getHostname(), 00359 currentControllerConfig.getPort()); 00360 } 00361 00362 // Disable Nagle algorithm else small messages are not sent 00363 // (at least under Linux) even if we flush the output stream. 00364 socket.setTcpNoDelay(true); 00365 00366 CJDBCOutputStream out = new CJDBCOutputStream(socket); 00367 // Send protocol version and database name 00368 out.writeInt(Commands.ProtocolVersion); 00369 out.writeUTF(currentDatabase); 00370 out.flush(); 00371 sentVdbName = true; 00372 00373 // Send user information 00374 out.writeUTF(user); 00375 out.writeUTF(password); 00376 out.flush(); 00377 sentUserInfo = true; 00378 00379 CJDBCInputStream in; 00380 boolean needSkeleton; 00381 AbstractBlobFilter filter = null; 00382 try 00383 { 00384 // Create input stream only here else it will block 00385 in = new CJDBCInputStream(socket); 00386 00387 Object response = in.readObject(); 00388 if (response instanceof Boolean) 00389 { 00390 needSkeleton = ((Boolean) response).booleanValue(); 00391 String sfilter = in.readUTF(); 00392 filter = AbstractBlobFilter.getBlobFilterInstance(sfilter); 00393 } 00394 else if (response instanceof SQLException) 00395 throw (SQLException) response; 00396 else 00397 throw new SQLException("Error during connection (received " 00398 + response + ")"); 00399 } 00400 catch (IOException e) 00401 { 00402 currentControllerURL = null; 00403 throw new SQLException("Authentication failed"); 00404 } 00405 return setParametersOnConnection(info, new Connection(this, socket, in, 00406 out, url, user, password, needSkeleton, filter)); 00407 } 00408 catch (Exception re) 00409 { 00410 controllerConfig.remove(picked); 00411 retry--; 00412 if (retry == 0) 00413 { 00414 if (!sentVdbName) 00415 throw new SQLException("Unable to connect to controller on " 00416 + currentControllerConfig.getHostname() + ":" 00417 + currentControllerConfig.getPort() + " (" + re + ")"); 00418 else if (!sentUserInfo) 00419 throw new SQLException( 00420 "Unable to connect to the virtual database (virtual database name is probably not correct)"); 00421 else 00422 throw new SQLException( 00423 "Unable to connect to the virtual database (" + re + ")"); 00424 } 00425 else 00426 { // Reset if no more controllers in the list 00427 if (controllerConfig.isEmpty()) 00428 currentControllerURL = null; 00429 } 00430 } 00431 } 00432 throw new SQLException( 00433 "Unable to connect to the virtual database - Unexpected error."); 00434 }
|
|
Returns the controllerConfig value containing the list of available controllers.
Definition at line 609 of file Driver.java. Referenced by org.objectweb.cjdbc.driver.Connection.execReadRequest(). 00610 {
00611 return controllerConfig;
00612 }
|
|
Gets the river's major version number
Definition at line 848 of file Driver.java. Referenced by org.objectweb.cjdbc.driver.DataSource.getDescription(). 00849 {
00850 return MAJOR_VERSION;
00851 }
|
|
Gets the driver's minor version number
Definition at line 858 of file Driver.java. Referenced by org.objectweb.cjdbc.driver.DataSource.getDescription(). 00859 {
00860 return MINOR_VERSION;
00861 }
|
|
This method is intended to allow a generic GUI tool to discover what properties it should prompt a human for in order to get enough information to connect to a database. The only properties supported by C-JDBC are:
Definition at line 778 of file Driver.java. 00780 { 00781 DriverPropertyInfo hostProp = new DriverPropertyInfo(HOST_PROPERTY, info 00782 .getProperty(HOST_PROPERTY)); 00783 hostProp.required = true; 00784 hostProp.description = HOST_PROPERTY_DESCRIPTION; 00785 00786 DriverPropertyInfo portProp = new DriverPropertyInfo(PORT_PROPERTY, info 00787 .getProperty(PORT_PROPERTY, Integer 00788 .toString(ControllerConstants.DEFAULT_PORT))); 00789 portProp.required = false; 00790 portProp.description = PORT_PROPERTY_DESCRIPTION; 00791 00792 DriverPropertyInfo databaseProp = new DriverPropertyInfo(DATABASE_PROPERTY, 00793 info.getProperty(DATABASE_PROPERTY)); 00794 databaseProp.required = true; 00795 databaseProp.description = DATABASE_PROPERTY_DESCRIPTION; 00796 00797 DriverPropertyInfo userProp = new DriverPropertyInfo(USER_PROPERTY, info 00798 .getProperty(USER_PROPERTY)); 00799 userProp.required = true; 00800 userProp.description = USER_PROPERTY_DESCRIPTION; 00801 00802 DriverPropertyInfo passwordProp = new DriverPropertyInfo(PASSWORD_PROPERTY, 00803 info.getProperty(PASSWORD_PROPERTY)); 00804 passwordProp.required = true; 00805 passwordProp.description = PASSWORD_PROPERTY_DESCRIPTION; 00806 00807 DriverPropertyInfo escapeCharProp = new DriverPropertyInfo( 00808 ESCAPE_CHARACTER_PROPERTY, info.getProperty(ESCAPE_CHARACTER_PROPERTY)); 00809 escapeCharProp.required = false; 00810 escapeCharProp.description = ESCAPE_CHARACTER_PROPERTY_DESCRIPTION; 00811 00812 DriverPropertyInfo escapeBackProp = new DriverPropertyInfo( 00813 ESCAPE_BACKSLASH_PROPERTY, info.getProperty(ESCAPE_BACKSLASH_PROPERTY)); 00814 escapeBackProp.required = false; 00815 escapeBackProp.description = ESCAPE_BACKSLASH_PROPERTY_DESCRIPTION; 00816 00817 DriverPropertyInfo escapeSingleProp = new DriverPropertyInfo( 00818 ESCAPE_SINGLE_QUOTE_PROPERTY, info 00819 .getProperty(ESCAPE_SINGLE_QUOTE_PROPERTY)); 00820 escapeSingleProp.required = false; 00821 escapeSingleProp.description = ESCAPE_SINGLE_QUOTE_PROPERTY_DESCRIPTION; 00822 00823 DriverPropertyInfo booleanFalseProp = new DriverPropertyInfo( 00824 BOOLEAN_FALSE_PROPERTY, info.getProperty(BOOLEAN_FALSE_PROPERTY)); 00825 booleanFalseProp.required = false; 00826 booleanFalseProp.description = BOOLEAN_FALSE_PROPERTY_DESCRIPTION; 00827 00828 DriverPropertyInfo booleanTrueProp = new DriverPropertyInfo( 00829 BOOLEAN_TRUE_PROPERTY, info.getProperty(BOOLEAN_TRUE_PROPERTY)); 00830 booleanTrueProp.required = false; 00831 booleanTrueProp.description = BOOLEAN_TRUE_PROPERTY_DESCRIPTION; 00832 00833 DriverPropertyInfo parseQueryProp = new DriverPropertyInfo( 00834 DRIVER_PROCESSED_PROPERTY, info.getProperty(DRIVER_PROCESSED_PROPERTY)); 00835 escapeSingleProp.required = false; 00836 escapeSingleProp.description = DRIVER_PROCESSED_PROPERTY_DESCRIPTION; 00837 00838 return new DriverPropertyInfo[]{hostProp, portProp, databaseProp, userProp, 00839 passwordProp, escapeCharProp, escapeBackProp, escapeSingleProp, 00840 booleanFalseProp, booleanTrueProp, parseQueryProp}; 00841 }
|
|
Feed in a set of properties and get the url as a
Definition at line 620 of file Driver.java. References org.objectweb.cjdbc.driver.Driver.ControllerInfo.toString(). Referenced by org.objectweb.cjdbc.driver.Connection.setCatalog(). 00621 { 00622 StringBuffer sb = new StringBuffer(); 00623 sb.append(CJDBC_URL_HEADER); 00624 ControllerInfo[] controllerList = (ControllerInfo[]) props 00625 .get(CONTROLLER_PROPERTY); 00626 for (int i = 0; i < controllerList.length; i++) 00627 { 00628 if (i == 0) 00629 sb.append(controllerList[i].toString()); 00630 else 00631 sb.append("," + controllerList[i].toString()); 00632 } 00633 sb.append("/" + props.get(DATABASE_PROPERTY)); 00634 Hashtable params = (Hashtable) props.get(PARAMETER_PROPERTY); 00635 if (params != null) 00636 { 00637 Enumeration paramsKeys = params.keys(); 00638 String element = null; 00639 while (paramsKeys.hasMoreElements()) 00640 { 00641 if (element == null) 00642 sb.append("?"); 00643 else 00644 sb.append("&"); 00645 element = (String) paramsKeys.nextElement(); 00646 sb.append(element + "=" + params.get(paramsKeys)); 00647 } 00648 } 00649 return sb.toString(); 00650 }
|
|
Reports whether the driver is a genuine JDBC compliant driver. A driver may only report
Definition at line 873 of file Driver.java. 00874 { 00875 return false; 00876 }
|
|
Checks for URL correctness and adds controllers list and database name to the cache.
Definition at line 466 of file Driver.java. Referenced by org.objectweb.cjdbc.driver.Driver.acceptsURL(), org.objectweb.cjdbc.driver.Driver.connect(), and org.objectweb.cjdbc.driver.Connection.setCatalog(). 00467 { 00468 // Find the hostname and check for URL correctness 00469 if (url == null) 00470 { 00471 throw new IllegalArgumentException( 00472 "Illegal null URL in parseURL(String) method"); 00473 } 00474 00475 if (!url.toLowerCase().startsWith(CJDBC_URL_HEADER)) 00476 throw new SQLException("Malformed header from URL '" + url 00477 + "' (expected '" + CJDBC_URL_HEADER + "')"); 00478 else 00479 { 00480 // Initialize return 00481 Hashtable result = new Hashtable(); 00482 00483 // Get the controllers list 00484 int nextSlash = url.indexOf('/', CJDBC_URL_HEADER_LENGTH); 00485 if (nextSlash == -1) 00486 // Missing '/' between hostname and database name. 00487 throw new SQLException("Malformed URL '" + url + "' (expected '" 00488 + CJDBC_URL_HEADER + "<hostname>/<database>')"); 00489 00490 // Found end of database name 00491 int questionMark = url.indexOf('?', nextSlash); 00492 questionMark = (questionMark == -1) 00493 ? url.indexOf(';', nextSlash) 00494 : questionMark; 00495 00496 String controllerURLs = url.substring(CJDBC_URL_HEADER_LENGTH, nextSlash); 00497 // Check the validity of each controller in the list 00498 StringTokenizer controllers = new StringTokenizer(controllerURLs, ",", 00499 true); 00500 int tokenNumber = controllers.countTokens(); 00501 ArrayList list = new ArrayList(); 00502 00503 int i = 0; 00504 String s; 00505 boolean lastTokenWasComma = false; 00506 while (controllers.hasMoreTokens()) 00507 { 00508 s = controllers.nextToken().trim(); 00509 if (s.equals(",")) 00510 { 00511 if (lastTokenWasComma || (i == 0) || (i == tokenNumber - 1)) 00512 // ',' cannot be the first or the last token 00513 // another ',' cannot follow a ',' 00514 throw new SQLException("Syntax error in controller list '" 00515 + controllerURLs + "' from URL '" + url + "'"); 00516 else 00517 { 00518 lastTokenWasComma = true; 00519 continue; 00520 } 00521 } 00522 lastTokenWasComma = false; 00523 list.add(parseController(s)); 00524 i++; 00525 } 00526 00527 ControllerInfo[] controllerList = new ControllerInfo[i]; 00528 for (int j = 0; j < i; j++) 00529 { 00530 controllerList[j] = (ControllerInfo) (list.get(j)); 00531 } 00532 // Add controller list to the result 00533 result.put(CONTROLLER_PROPERTY, controllerList); 00534 00535 // Check database name validity 00536 String databaseName = (questionMark == -1) ? url.substring(nextSlash + 1, 00537 url.length()) : url.substring(nextSlash + 1, questionMark); 00538 Character c = validDatabaseName(databaseName); 00539 if (c != null) 00540 throw new SQLException( 00541 "Unable to validate database name (unacceptable character '" + c 00542 + "' in database '" + databaseName + "' from URL '" + url 00543 + "')"); 00544 00545 // Add database name to result 00546 result.put(DATABASE_PROPERTY, databaseName); 00547 00548 // Finally, add the controllers list and database name to the caches 00549 controllerCache.put(url, controllerList); 00550 dbNameCache.put(url, databaseName); 00551 00552 // Get the parameters from the url 00553 Hashtable params = parseUrlParams(url); 00554 if (params != null) 00555 result.put(PARAMETER_PROPERTY, params); 00556 return result; 00557 } 00558 }
|
|
Initial value: Constants .getMajorVersion() Definition at line 108 of file Driver.java. |
|
Initial value: Constants .getMinorVersion() Definition at line 112 of file Driver.java. |
|
List of connections that are ready to be closed. Definition at line 160 of file Driver.java. Referenced by org.objectweb.cjdbc.driver.Connection.close(), org.objectweb.cjdbc.driver.Driver.connect(), and org.objectweb.cjdbc.driver.ConnectionClosingThread.ConnectionClosingThread(). |