1 /*
2 Copyright 2002-2007 MySQL AB, 2008 Sun Microsystems
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of version 2 of the GNU General Public License as
6 published by the Free Software Foundation.
7
8 There are special exceptions to the terms and conditions of the GPL
9 as it is applied to this software. View the full text of the
10 exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
11 software distribution.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22
23
24 */
25 package com.mysql.jdbc;
26
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.UnsupportedEncodingException;
30 import java.net.URLDecoder;
31 import java.sql.DriverPropertyInfo;
32 import java.sql.SQLException;
33 import java.util.ArrayList;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Properties;
37 import java.util.StringTokenizer;
38 /**
39 * The Java SQL framework allows for multiple database drivers. Each driver
40 * should supply a class that implements the Driver interface
41 *
42 * <p>
43 * The DriverManager will try to load as many drivers as it can find and then
44 * for any given connection request, it will ask each driver in turn to try to
45 * connect to the target URL.
46 * </p>
47 *
48 * <p>
49 * It is strongly recommended that each Driver class should be small and
50 * standalone so that the Driver class can be loaded and queried without
51 * bringing in vast quantities of supporting code.
52 * </p>
53 *
54 * <p>
55 * When a Driver class is loaded, it should create an instance of itself and
56 * register it with the DriverManager. This means that a user can load and
57 * register a driver by doing Class.forName("foo.bah.Driver")
58 * </p>
59 *
60 * @author Mark Matthews
61 * @version $Id: NonRegisteringDriver.java,v 1.1.2.1 2005/05/13 18:58:38
62 * mmatthews Exp $
63 *
64 * @see org.gjt.mm.mysql.Connection
65 * @see java.sql.Driver
66 */
67 public class NonRegisteringDriver implements java.sql.Driver {
68 private static final String REPLICATION_URL_PREFIX = "jdbc:mysql:replication://";
69
70 private static final String URL_PREFIX = "jdbc:mysql://";
71
72 private static final String MXJ_URL_PREFIX = "jdbc:mysql:mxj://";
73
74 private static final String LOADBALANCE_URL_PREFIX = "jdbc:mysql:loadbalance://";
75
76 /**
77 * Key used to retreive the database value from the properties instance
78 * passed to the driver.
79 */
80 public static final String DBNAME_PROPERTY_KEY = "DBNAME";
81
82 /** Should the driver generate debugging output? */
83 public static final boolean DEBUG = false;
84
85 /** Index for hostname coming out of parseHostPortPair(). */
86 public final static int HOST_NAME_INDEX = 0;
87
88 /**
89 * Key used to retreive the hostname value from the properties instance
90 * passed to the driver.
91 */
92 public static final String HOST_PROPERTY_KEY = "HOST";
93
94 public static final String NUM_HOSTS_PROPERTY_KEY = "NUM_HOSTS";
95
96 /**
97 * Key used to retreive the password value from the properties instance
98 * passed to the driver.
99 */
100 public static final String PASSWORD_PROPERTY_KEY = "password";
101
102 /** Index for port # coming out of parseHostPortPair(). */
103 public final static int PORT_NUMBER_INDEX = 1;
104
105 /**
106 * Key used to retreive the port number value from the properties instance
107 * passed to the driver.
108 */
109 public static final String PORT_PROPERTY_KEY = "PORT";
110
111 public static final String PROPERTIES_TRANSFORM_KEY = "propertiesTransform";
112
113 /** Should the driver generate method-call traces? */
114 public static final boolean TRACE = false;
115
116 public static final String USE_CONFIG_PROPERTY_KEY = "useConfigs";
117
118 /**
119 * Key used to retreive the username value from the properties instance
120 * passed to the driver.
121 */
122 public static final String USER_PROPERTY_KEY = "user";
123
124 /**
125 * Gets the drivers major version number
126 *
127 * @return the drivers major version number
128 */
129 static int getMajorVersionInternal() {
130 return safeIntParse("@MYSQL_CJ_MAJOR_VERSION@"); //$NON-NLS-1$
131 }
132
133 /**
134 * Get the drivers minor version number
135 *
136 * @return the drivers minor version number
137 */
138 static int getMinorVersionInternal() {
139 return safeIntParse("@MYSQL_CJ_MINOR_VERSION@"); //$NON-NLS-1$
140 }
141
142 /**
143 * Parses hostPortPair in the form of [host][:port] into an array, with the
144 * element of index HOST_NAME_INDEX being the host (or null if not
145 * specified), and the element of index PORT_NUMBER_INDEX being the port (or
146 * null if not specified).
147 *
148 * @param hostPortPair
149 * host and port in form of of [host][:port]
150 *
151 * @return array containing host and port as Strings
152 *
153 * @throws SQLException
154 * if a parse error occurs
155 */
156 protected static String[] parseHostPortPair(String hostPortPair)
157 throws SQLException {
158 int portIndex = hostPortPair.indexOf(":"); //$NON-NLS-1$
159
160 String[] splitValues = new String[2];
161
162 String hostname = null;
163
164 if (portIndex != -1) {
165 if ((portIndex + 1) < hostPortPair.length()) {
166 String portAsString = hostPortPair.substring(portIndex + 1);
167 hostname = hostPortPair.substring(0, portIndex);
168
169 splitValues[HOST_NAME_INDEX] = hostname;
170
171 splitValues[PORT_NUMBER_INDEX] = portAsString;
172 } else {
173 throw SQLError.createSQLException(Messages
174 .getString("NonRegisteringDriver.37"), //$NON-NLS-1$
175 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
176 }
177 } else {
178 splitValues[HOST_NAME_INDEX] = hostPortPair;
179 splitValues[PORT_NUMBER_INDEX] = null;
180 }
181
182 return splitValues;
183 }
184
185 private static int safeIntParse(String intAsString) {
186 try {
187 return Integer.parseInt(intAsString);
188 } catch (NumberFormatException nfe) {
189 return 0;
190 }
191 }
192
193 /**
194 * Construct a new driver and register it with DriverManager
195 *
196 * @throws SQLException
197 * if a database error occurs.
198 */
199 public NonRegisteringDriver() throws SQLException {
200 // Required for Class.forName().newInstance()
201 }
202
203 /**
204 * Typically, drivers will return true if they understand the subprotocol
205 * specified in the URL and false if they don't. This driver's protocols
206 * start with jdbc:mysql:
207 *
208 * @param url
209 * the URL of the driver
210 *
211 * @return true if this driver accepts the given URL
212 *
213 * @exception SQLException
214 * if a database-access error occurs
215 *
216 * @see java.sql.Driver#acceptsURL
217 */
218 public boolean acceptsURL(String url) throws SQLException {
219 return (parseURL(url, null) != null);
220 }
221
222 //
223 // return the database name property
224 //
225
226 /**
227 * Try to make a database connection to the given URL. The driver should
228 * return "null" if it realizes it is the wrong kind of driver to connect to
229 * the given URL. This will be common, as when the JDBC driverManager is
230 * asked to connect to a given URL, it passes the URL to each loaded driver
231 * in turn.
232 *
233 * <p>
234 * The driver should raise an SQLException if it is the right driver to
235 * connect to the given URL, but has trouble connecting to the database.
236 * </p>
237 *
238 * <p>
239 * The java.util.Properties argument can be used to pass arbitrary string
240 * tag/value pairs as connection arguments.
241 * </p>
242 *
243 * <p>
244 * My protocol takes the form:
245 *
246 * <PRE>
247 *
248 * jdbc:mysql://host:port/database
249 *
250 * </PRE>
251 *
252 * </p>
253 *
254 * @param url
255 * the URL of the database to connect to
256 * @param info
257 * a list of arbitrary tag/value pairs as connection arguments
258 *
259 * @return a connection to the URL or null if it isnt us
260 *
261 * @exception SQLException
262 * if a database access error occurs
263 *
264 * @see java.sql.Driver#connect
265 */
266 public java.sql.Connection connect(String url, Properties info)
267 throws SQLException {
268 if (url != null) {
269 if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {
270 return connectLoadBalanced(url, info);
271 } else if (StringUtils.startsWithIgnoreCase(url,
272 REPLICATION_URL_PREFIX)) {
273 return connectReplicationConnection(url, info);
274 }
275 }
276
277 Properties props = null;
278
279 if ((props = parseURL(url, info)) == null) {
280 return null;
281 }
282
283 try {
284 Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(
285 host(props), port(props), props, database(props), url);
286
287 return newConn;
288 } catch (SQLException sqlEx) {
289 // Don't wrap SQLExceptions, throw
290 // them un-changed.
291 throw sqlEx;
292 } catch (Exception ex) {
293 SQLException sqlEx = SQLError.createSQLException(Messages
294 .getString("NonRegisteringDriver.17") //$NON-NLS-1$
295 + ex.toString()
296 + Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$
297 SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE, null);
298
299 sqlEx.initCause(ex);
300
301 throw sqlEx;
302 }
303 }
304
305 private java.sql.Connection connectLoadBalanced(String url, Properties info)
306 throws SQLException {
307 Properties parsedProps = parseURL(url, info);
308
309 // People tend to drop this in, it doesn't make sense
310 parsedProps.remove("roundRobinLoadBalance");
311
312 if (parsedProps == null) {
313 return null;
314 }
315
316 int numHosts = Integer.parseInt(parsedProps.getProperty(NUM_HOSTS_PROPERTY_KEY));
317
318 List hostList = new ArrayList();
319
320 for (int i = 0; i < numHosts; i++) {
321 int index = i + 1;
322
323 hostList.add(parsedProps.getProperty(HOST_PROPERTY_KEY + "." + index) + ":"
324 + parsedProps.getProperty(PORT_PROPERTY_KEY + "." + index));
325 }
326
327 LoadBalancingConnectionProxy proxyBal = new LoadBalancingConnectionProxy(
328 hostList, parsedProps);
329
330 return (java.sql.Connection) java.lang.reflect.Proxy.newProxyInstance(this
331 .getClass().getClassLoader(),
332 new Class[] { com.mysql.jdbc.Connection.class }, proxyBal);
333 }
334
335 protected java.sql.Connection connectReplicationConnection(String url, Properties info)
336 throws SQLException {
337 Properties parsedProps = parseURL(url, info);
338
339 if (parsedProps == null) {
340 return null;
341 }
342
343 Properties masterProps = (Properties) parsedProps.clone();
344 Properties slavesProps = (Properties) parsedProps.clone();
345
346 // Marker used for further testing later on, also when
347 // debugging
348 slavesProps.setProperty("com.mysql.jdbc.ReplicationConnection.isSlave",
349 "true");
350
351 int numHosts = Integer.parseInt(parsedProps.getProperty(NUM_HOSTS_PROPERTY_KEY));
352
353 if (numHosts < 2) {
354 throw SQLError
355 .createSQLException(
356 "Must specify at least one slave host to connect to for master/slave replication load-balancing functionality",
357 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
358 }
359
360 for (int i = 1; i < numHosts; i++) {
361 int index = i + 1;
362
363 masterProps.remove(HOST_PROPERTY_KEY + "." + index);
364 masterProps.remove(PORT_PROPERTY_KEY + "." + index);
365
366 slavesProps.setProperty(HOST_PROPERTY_KEY + "." + i, parsedProps.getProperty(HOST_PROPERTY_KEY + "." + index));
367 slavesProps.setProperty(PORT_PROPERTY_KEY + "." + i, parsedProps.getProperty(PORT_PROPERTY_KEY + "." + index));
368 }
369
370 masterProps.setProperty(NUM_HOSTS_PROPERTY_KEY, "1");
371 slavesProps.remove(HOST_PROPERTY_KEY + "." + numHosts);
372 slavesProps.remove(PORT_PROPERTY_KEY + "." + numHosts);
373 slavesProps.setProperty(NUM_HOSTS_PROPERTY_KEY, String.valueOf(numHosts - 1));
374 slavesProps.setProperty(HOST_PROPERTY_KEY, slavesProps.getProperty(HOST_PROPERTY_KEY + ".1"));
375 slavesProps.setProperty(PORT_PROPERTY_KEY, slavesProps.getProperty(PORT_PROPERTY_KEY + ".1"));
376
377 return new ReplicationConnection(masterProps, slavesProps);
378 }
379
380 /**
381 * Returns the database property from <code>props</code>
382 *
383 * @param props
384 * the Properties to look for the database property.
385 *
386 * @return the database name.
387 */
388 public String database(Properties props) {
389 return props.getProperty(DBNAME_PROPERTY_KEY); //$NON-NLS-1$
390 }
391
392 /**
393 * Gets the drivers major version number
394 *
395 * @return the drivers major version number
396 */
397 public int getMajorVersion() {
398 return getMajorVersionInternal();
399 }
400
401 /**
402 * Get the drivers minor version number
403 *
404 * @return the drivers minor version number
405 */
406 public int getMinorVersion() {
407 return getMinorVersionInternal();
408 }
409
410 /**
411 * The getPropertyInfo method is intended to allow a generic GUI tool to
412 * discover what properties it should prompt a human for in order to get
413 * enough information to connect to a database.
414 *
415 * <p>
416 * Note that depending on the values the human has supplied so far,
417 * additional values may become necessary, so it may be necessary to iterate
418 * through several calls to getPropertyInfo
419 * </p>
420 *
421 * @param url
422 * the Url of the database to connect to
423 * @param info
424 * a proposed list of tag/value pairs that will be sent on
425 * connect open.
426 *
427 * @return An array of DriverPropertyInfo objects describing possible
428 * properties. This array may be an empty array if no properties are
429 * required
430 *
431 * @exception SQLException
432 * if a database-access error occurs
433 *
434 * @see java.sql.Driver#getPropertyInfo
435 */
436 public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
437 throws SQLException {
438 if (info == null) {
439 info = new Properties();
440 }
441
442 if ((url != null) && url.startsWith(URL_PREFIX)) { //$NON-NLS-1$
443 info = parseURL(url, info);
444 }
445
446 DriverPropertyInfo hostProp = new DriverPropertyInfo(HOST_PROPERTY_KEY, //$NON-NLS-1$
447 info.getProperty(HOST_PROPERTY_KEY)); //$NON-NLS-1$
448 hostProp.required = true;
449 hostProp.description = Messages.getString("NonRegisteringDriver.3"); //$NON-NLS-1$
450
451 DriverPropertyInfo portProp = new DriverPropertyInfo(PORT_PROPERTY_KEY, //$NON-NLS-1$
452 info.getProperty(PORT_PROPERTY_KEY, "3306")); //$NON-NLS-1$ //$NON-NLS-2$
453 portProp.required = false;
454 portProp.description = Messages.getString("NonRegisteringDriver.7"); //$NON-NLS-1$
455
456 DriverPropertyInfo dbProp = new DriverPropertyInfo(DBNAME_PROPERTY_KEY, //$NON-NLS-1$
457 info.getProperty(DBNAME_PROPERTY_KEY)); //$NON-NLS-1$
458 dbProp.required = false;
459 dbProp.description = "Database name"; //$NON-NLS-1$
460
461 DriverPropertyInfo userProp = new DriverPropertyInfo(USER_PROPERTY_KEY, //$NON-NLS-1$
462 info.getProperty(USER_PROPERTY_KEY)); //$NON-NLS-1$
463 userProp.required = true;
464 userProp.description = Messages.getString("NonRegisteringDriver.13"); //$NON-NLS-1$
465
466 DriverPropertyInfo passwordProp = new DriverPropertyInfo(
467 PASSWORD_PROPERTY_KEY, //$NON-NLS-1$
468 info.getProperty(PASSWORD_PROPERTY_KEY)); //$NON-NLS-1$
469 passwordProp.required = true;
470 passwordProp.description = Messages
471 .getString("NonRegisteringDriver.16"); //$NON-NLS-1$
472
473 DriverPropertyInfo[] dpi = ConnectionPropertiesImpl
474 .exposeAsDriverPropertyInfo(info, 5);
475
476 dpi[0] = hostProp;
477 dpi[1] = portProp;
478 dpi[2] = dbProp;
479 dpi[3] = userProp;
480 dpi[4] = passwordProp;
481
482 return dpi;
483 }
484
485 //
486 // return the value of any property this driver knows about
487 //
488
489 /**
490 * Returns the hostname property
491 *
492 * @param props
493 * the java.util.Properties instance to retrieve the hostname
494 * from.
495 *
496 * @return the hostname
497 */
498 public String host(Properties props) {
499 return props.getProperty(HOST_PROPERTY_KEY, "localhost"); //$NON-NLS-1$ //$NON-NLS-2$
500 }
501
502 /**
503 * Report whether the driver is a genuine JDBC compliant driver. A driver
504 * may only report "true" here if it passes the JDBC compliance tests,
505 * otherwise it is required to return false. JDBC compliance requires full
506 * support for the JDBC API and full support for SQL 92 Entry Level.
507 *
508 * <p>
509 * MySQL is not SQL92 compliant
510 * </p>
511 *
512 * @return is this driver JDBC compliant?
513 */
514 public boolean jdbcCompliant() {
515 return false;
516 }
517
518 public Properties parseURL(String url, Properties defaults)
519 throws java.sql.SQLException {
520 Properties urlProps = (defaults != null) ? new Properties(defaults)
521 : new Properties();
522
523 if (url == null) {
524 return null;
525 }
526
527 if (!StringUtils.startsWithIgnoreCase(url, URL_PREFIX)
528 && !StringUtils.startsWithIgnoreCase(url, MXJ_URL_PREFIX)
529 && !StringUtils.startsWithIgnoreCase(url,
530 LOADBALANCE_URL_PREFIX)
531 && !StringUtils.startsWithIgnoreCase(url,
532 REPLICATION_URL_PREFIX)) { //$NON-NLS-1$
533
534 return null;
535 }
536
537 int beginningOfSlashes = url.indexOf("//");
538
539 if (StringUtils.startsWithIgnoreCase(url, MXJ_URL_PREFIX)) {
540
541 urlProps
542 .setProperty("socketFactory",
543 "com.mysql.management.driverlaunched.ServerLauncherSocketFactory");
544 }
545
546 /*
547 * Parse parameters after the ? in the URL and remove them from the
548 * original URL.
549 */
550 int index = url.indexOf("?"); //$NON-NLS-1$
551
552 if (index != -1) {
553 String paramString = url.substring(index + 1, url.length());
554 url = url.substring(0, index);
555
556 StringTokenizer queryParams = new StringTokenizer(paramString, "&"); //$NON-NLS-1$
557
558 while (queryParams.hasMoreTokens()) {
559 String parameterValuePair = queryParams.nextToken();
560
561 int indexOfEquals = StringUtils.indexOfIgnoreCase(0,
562 parameterValuePair, "=");
563
564 String parameter = null;
565 String value = null;
566
567 if (indexOfEquals != -1) {
568 parameter = parameterValuePair.substring(0, indexOfEquals);
569
570 if (indexOfEquals + 1 < parameterValuePair.length()) {
571 value = parameterValuePair.substring(indexOfEquals + 1);
572 }
573 }
574
575 if ((value != null && value.length() > 0)
576 && (parameter != null && parameter.length() > 0)) {
577 try {
578 urlProps.put(parameter, URLDecoder.decode(value,
579 "UTF-8"));
580 } catch (UnsupportedEncodingException badEncoding) {
581 // punt
582 urlProps.put(parameter, URLDecoder.decode(value));
583 } catch (NoSuchMethodError nsme) {
584 // punt again
585 urlProps.put(parameter, URLDecoder.decode(value));
586 }
587 }
588 }
589 }
590
591 url = url.substring(beginningOfSlashes + 2);
592
593 String hostStuff = null;
594
595 int slashIndex = url.indexOf("/"); //$NON-NLS-1$
596
597 if (slashIndex != -1) {
598 hostStuff = url.substring(0, slashIndex);
599
600 if ((slashIndex + 1) < url.length()) {
601 urlProps.put(DBNAME_PROPERTY_KEY, //$NON-NLS-1$
602 url.substring((slashIndex + 1), url.length()));
603 }
604 } else {
605 hostStuff = url;
606 }
607
608 int numHosts = 0;
609
610 if ((hostStuff != null) && (hostStuff.trim().length() > 0)) {
611 StringTokenizer st = new StringTokenizer(hostStuff, ",");
612
613 while (st.hasMoreTokens()) {
614 numHosts++;
615
616 String[] hostPortPair = parseHostPortPair(st.nextToken());
617
618 if (hostPortPair[HOST_NAME_INDEX] != null && hostPortPair[HOST_NAME_INDEX].trim().length() > 0) {
619 urlProps.setProperty(HOST_PROPERTY_KEY + "." + numHosts, hostPortPair[HOST_NAME_INDEX]);
620 } else {
621 urlProps.setProperty(HOST_PROPERTY_KEY + "." + numHosts, "localhost");
622 }
623
624 if (hostPortPair[PORT_NUMBER_INDEX] != null) {
625 urlProps.setProperty(PORT_PROPERTY_KEY + "." + numHosts, hostPortPair[PORT_NUMBER_INDEX]);
626 } else {
627 urlProps.setProperty(PORT_PROPERTY_KEY + "." + numHosts, "3306");
628 }
629 }
630 } else {
631 numHosts = 1;
632 urlProps.setProperty(HOST_PROPERTY_KEY + ".1", "localhost");
633 urlProps.setProperty(PORT_PROPERTY_KEY + ".1", "3306");
634 }
635
636 urlProps.setProperty(NUM_HOSTS_PROPERTY_KEY, String.valueOf(numHosts));
637 urlProps.setProperty(HOST_PROPERTY_KEY, urlProps.getProperty(HOST_PROPERTY_KEY + ".1"));
638 urlProps.setProperty(PORT_PROPERTY_KEY, urlProps.getProperty(PORT_PROPERTY_KEY + ".1"));
639
640 String propertiesTransformClassName = urlProps
641 .getProperty(PROPERTIES_TRANSFORM_KEY);
642
643 if (propertiesTransformClassName != null) {
644 try {
645 ConnectionPropertiesTransform propTransformer = (ConnectionPropertiesTransform) Class
646 .forName(propertiesTransformClassName).newInstance();
647
648 urlProps = propTransformer.transformProperties(urlProps);
649 } catch (InstantiationException e) {
650 throw SQLError.createSQLException(
651 "Unable to create properties transform instance '"
652 + propertiesTransformClassName
653 + "' due to underlying exception: "
654 + e.toString(),
655 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
656 } catch (IllegalAccessException e) {
657 throw SQLError.createSQLException(
658 "Unable to create properties transform instance '"
659 + propertiesTransformClassName
660 + "' due to underlying exception: "
661 + e.toString(),
662 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
663 } catch (ClassNotFoundException e) {
664 throw SQLError.createSQLException(
665 "Unable to create properties transform instance '"
666 + propertiesTransformClassName
667 + "' due to underlying exception: "
668 + e.toString(),
669 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
670 }
671 }
672
673 if (Util.isColdFusion() &&
674 urlProps.getProperty("autoConfigureForColdFusion", "true").equalsIgnoreCase("true")) {
675 String configs = urlProps.getProperty(USE_CONFIG_PROPERTY_KEY);
676
677 StringBuffer newConfigs = new StringBuffer();
678
679 if (configs != null) {
680 newConfigs.append(configs);
681 newConfigs.append(",");
682 }
683
684 newConfigs.append("coldFusion");
685
686 urlProps.setProperty(USE_CONFIG_PROPERTY_KEY, newConfigs.toString());
687 }
688
689 // If we use a config, it actually should get overridden by anything in
690 // the URL or passed-in properties
691
692 String configNames = null;
693
694 if (defaults != null) {
695 configNames = defaults.getProperty(USE_CONFIG_PROPERTY_KEY);
696 }
697
698 if (configNames == null) {
699 configNames = urlProps.getProperty(USE_CONFIG_PROPERTY_KEY);
700 }
701
702 if (configNames != null) {
703 List splitNames = StringUtils.split(configNames, ",", true);
704
705 Properties configProps = new Properties();
706
707 Iterator namesIter = splitNames.iterator();
708
709 while (namesIter.hasNext()) {
710 String configName = (String) namesIter.next();
711
712 try {
713 InputStream configAsStream = getClass()
714 .getResourceAsStream(
715 "configs/" + configName + ".properties");
716
717 if (configAsStream == null) {
718 throw SQLError
719 .createSQLException(
720 "Can't find configuration template named '"
721 + configName + "'",
722 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
723 }
724 configProps.load(configAsStream);
725 } catch (IOException ioEx) {
726 SQLException sqlEx = SQLError.createSQLException(
727 "Unable to load configuration template '"
728 + configName
729 + "' due to underlying IOException: "
730 + ioEx,
731 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
732 sqlEx.initCause(ioEx);
733
734 throw sqlEx;
735 }
736 }
737
738 Iterator propsIter = urlProps.keySet().iterator();
739
740 while (propsIter.hasNext()) {
741 String key = propsIter.next().toString();
742 String property = urlProps.getProperty(key);
743 configProps.setProperty(key, property);
744 }
745
746 urlProps = configProps;
747 }
748
749 // Properties passed in should override ones in URL
750
751 if (defaults != null) {
752 Iterator propsIter = defaults.keySet().iterator();
753
754 while (propsIter.hasNext()) {
755 String key = propsIter.next().toString();
756 if (!key.equals(NUM_HOSTS_PROPERTY_KEY)) {
757 String property = defaults.getProperty(key);
758 urlProps.setProperty(key, property);
759 }
760 }
761 }
762
763 return urlProps;
764 }
765
766 /**
767 * Returns the port number property
768 *
769 * @param props
770 * the properties to get the port number from
771 *
772 * @return the port number
773 */
774 public int port(Properties props) {
775 return Integer.parseInt(props.getProperty(PORT_PROPERTY_KEY, "3306")); //$NON-NLS-1$ //$NON-NLS-2$
776 }
777
778 /**
779 * Returns the given property from <code>props</code>
780 *
781 * @param name
782 * the property name
783 * @param props
784 * the property instance to look in
785 *
786 * @return the property value, or null if not found.
787 */
788 public String property(String name, Properties props) {
789 return props.getProperty(name);
790 }
791 }