001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb.util;
032:
033: import java.io.BufferedReader;
034: import java.io.File;
035: import java.io.FileReader;
036: import java.io.IOException;
037: import java.net.MalformedURLException;
038: import java.sql.Connection;
039: import java.sql.DriverManager;
040: import java.sql.SQLException;
041: import java.util.Properties;
042: import java.util.StringTokenizer;
043:
044: /* $Id: RCData.java,v 1.17 2007/05/13 15:27:37 fredt Exp $ */
045:
046: /**
047: * All the info we need to connect up to a database.
048: *
049: * @author Blaine Simpson unsaved@users
050: */
051: public class RCData {
052:
053: public static final String DEFAULT_JDBC_DRIVER = "org.hsqldb.jdbcDriver";
054: private String defaultJdbcDriverName = DEFAULT_JDBC_DRIVER;
055:
056: public void setDefaultJdbcDriver(String defaultJdbcDriverName) {
057: this .defaultJdbcDriverName = defaultJdbcDriverName;
058: }
059:
060: public String getDefaultJdbcDriverName() {
061: return defaultJdbcDriverName;
062: }
063:
064: /**
065: * Just for testing and debugging.
066: *
067: * N.b. this echoes passwords!
068: */
069: public void report() {
070: System.err
071: .println("urlid: " + id + ", url: " + url
072: + ", username: " + username + ", password: "
073: + password);
074: }
075:
076: /**
077: * Creates a RCDataObject by looking up the given key in the
078: * given authentication file.
079: *
080: * @param dbKey Key to look up in the file.
081: * @param file File containing the authentication information.
082: */
083: public RCData(File file, String dbKey) throws Exception {
084:
085: if (file == null) {
086: throw new IllegalArgumentException(
087: "RC file name not specified");
088: }
089:
090: if (!file.canRead()) {
091: throw new IOException("Please set up authentication file '"
092: + file + "'");
093: }
094:
095: // System.err.println("Using RC file '" + file + "'");
096: StringTokenizer tokenizer = null;
097: boolean this one = false;
098: String s;
099: String keyword, value;
100: int linenum = 0;
101: BufferedReader br = new BufferedReader(new FileReader(file));
102:
103: while ((s = br.readLine()) != null) {
104: ++linenum;
105:
106: s = s.trim();
107:
108: if (s.length() == 0) {
109: continue;
110: }
111:
112: if (s.charAt(0) == '#') {
113: continue;
114: }
115:
116: tokenizer = new StringTokenizer(s);
117:
118: if (tokenizer.countTokens() == 1) {
119: keyword = tokenizer.nextToken();
120: value = "";
121: } else if (tokenizer.countTokens() > 1) {
122: keyword = tokenizer.nextToken();
123: value = tokenizer.nextToken("").trim();
124: } else {
125: try {
126: br.close();
127: } catch (IOException e) {
128: }
129:
130: throw new Exception("Corrupt line " + linenum + " in '"
131: + file + "': " + s);
132: }
133:
134: if (dbKey == null) {
135: if (keyword.equals("urlid")) {
136: System.out.println(value);
137: }
138:
139: continue;
140: }
141:
142: if (keyword.equals("urlid")) {
143: if (value.equals(dbKey)) {
144: if (id == null) {
145: id = dbKey;
146: this one = true;
147: } else {
148: try {
149: br.close();
150: } catch (IOException e) {
151: }
152:
153: throw new Exception("Key '" + dbKey
154: + " redefined at" + " line " + linenum
155: + " in '" + file);
156: }
157: } else {
158: this one = false;
159: }
160:
161: continue;
162: }
163:
164: if (this one) {
165: if (keyword.equals("url")) {
166: url = value;
167: } else if (keyword.equals("username")) {
168: username = value;
169: } else if (keyword.equals("driver")) {
170: driver = value;
171: } else if (keyword.equals("charset")) {
172: charset = value;
173: } else if (keyword.equals("truststore")) {
174: truststore = value;
175: } else if (keyword.equals("password")) {
176: password = value;
177: } else if (keyword.equals("libpath")) {
178: libpath = value;
179: } else {
180: try {
181: br.close();
182: } catch (IOException e) {
183: }
184:
185: throw new Exception("Bad line " + linenum + " in '"
186: + file + "': " + s);
187: }
188: }
189: }
190:
191: try {
192: br.close();
193: } catch (IOException e) {
194: }
195:
196: if (dbKey == null) {
197: return;
198: }
199:
200: if (url == null || username == null || password == null) {
201: throw new Exception("url or username or password not set "
202: + "for '" + dbKey + "' in file '" + file + "'");
203: }
204:
205: if (libpath != null) {
206: throw new IllegalArgumentException(
207: "Sorry, 'libpath' not supported yet");
208: }
209: }
210:
211: /**
212: * Convenience constructor for backward compatibility.
213: *
214: * @see #RCData(String,String,String,String,String,String,String,String)
215: */
216: public RCData(String id, String url, String username,
217: String password, String driver, String charset,
218: String truststore) throws Exception {
219: this (id, url, username, password, driver, charset, truststore,
220: null);
221: }
222:
223: /**
224: * <p>Creates a new <code>RCData</code> object.
225: *
226: * <p>The parameters driver, charset, truststore, and libpath are optional.
227: * Setting these parameters to <code>NULL</code> will set them to their
228: * default values.
229: *
230: * @param id The identifier for these connection settings
231: * @param url The URL of the database to connect to
232: * @param username The username to log in as
233: * @param password The password of the username
234: * @param driver The JDBC driver to use
235: * @param charset The character set to use
236: * @param truststore The trust store to use
237: * @param libpath The JDBC library to add to CLASSPATH
238: * @throws Exception if the a non-optional parameter is set to <code>NULL</code>
239: */
240: public RCData(String id, String url, String username,
241: String password, String driver, String charset,
242: String truststore, String libpath) throws Exception {
243:
244: this .id = id;
245: this .url = url;
246: this .username = username;
247: this .password = password;
248: this .driver = driver;
249: this .charset = charset;
250: this .truststore = truststore;
251: this .libpath = libpath;
252:
253: if (libpath != null) {
254: throw new IllegalArgumentException(
255: "Sorry, 'libpath' not supported yet");
256: }
257:
258: if (id == null || url == null || username == null
259: || password == null) {
260: throw new Exception(
261: "id, url, username, or password was not set");
262: }
263: }
264:
265: String id = null;
266: String url = null;
267: String username = null;
268: String password = null;
269: String driver = null;
270: String charset = null;
271: String truststore = null;
272: String libpath = null;
273:
274: /**
275: * Gets a JDBC Connection using the data of this RCData object.
276: *
277: * @return New JDBC Connection
278: */
279: public Connection getConnection() throws ClassNotFoundException,
280: InstantiationException, IllegalAccessException,
281: SQLException, MalformedURLException {
282: return getConnection(null, null, null);
283: }
284:
285: /**
286: * Gets a JDBC Connection using the data of this RCData object with
287: * specified override elements
288: *
289: * @return New JDBC Connection
290: */
291: public Connection getConnection(String curDriver,
292: String curCharset, String curTrustStore)
293: throws ClassNotFoundException, InstantiationException,
294: IllegalAccessException, MalformedURLException, SQLException {
295:
296: Properties sysProps = System.getProperties();
297:
298: if (curDriver == null) {
299:
300: // If explicit driver not specified
301: curDriver = ((driver == null) ? DEFAULT_JDBC_DRIVER
302: : driver);
303: }
304:
305: if (curCharset == null && charset != null) {
306: curCharset = charset;
307: }
308:
309: if (curTrustStore == null && truststore != null) {
310: curTrustStore = truststore;
311: }
312:
313: if (curCharset == null) {
314: sysProps.remove("sqlfile.charset");
315: } else {
316: sysProps.put("sqlfile.charset", curCharset);
317: }
318:
319: if (curTrustStore == null) {
320: sysProps.remove("javax.net.ssl.trustStore");
321: } else {
322: sysProps.put("javax.net.ssl.trustStore", curTrustStore);
323: }
324:
325: String urlString = null;
326:
327: try {
328: urlString = expandSysPropVars(url);
329: } catch (IllegalArgumentException iae) {
330: throw new MalformedURLException(iae.getMessage()
331: + " for URL '" + url + "'");
332: }
333:
334: String userString = null;
335:
336: try {
337: userString = expandSysPropVars(username);
338: } catch (IllegalArgumentException iae) {
339: throw new MalformedURLException(iae.getMessage()
340: + " for user name '" + username + "'");
341: }
342:
343: String passwordString = null;
344:
345: try {
346: passwordString = expandSysPropVars(password);
347: } catch (IllegalArgumentException iae) {
348: throw new MalformedURLException(iae.getMessage()
349: + " for password");
350: }
351:
352: // As described in the JDBC FAQ:
353: // http://java.sun.com/products/jdbc/jdbc-frequent.html;
354: // Why doesn't calling class.forName() load my JDBC driver?
355: // There is a bug in the JDK 1.1.x that can cause Class.forName()
356: // to fail. // new org.hsqldb.jdbcDriver();
357: /* This does register the new driver instance, as can be shown by
358: * DriverManager.getDrivers(), but somehow the registered driver
359: * does not pick up the URL, and the result is always:
360: * No suitable driver
361: DriverManager.registerDriver((Driver)
362: ((libpath == null) ? Class.forName(curDriver)
363: : (new URLClassLoader(new URL[] {
364: new URL("file:///" + libpath)
365: })).loadClass(curDriver)).newInstance());
366: */
367: Class.forName(curDriver);
368:
369: return DriverManager.getConnection(urlString, userString,
370: passwordString);
371: }
372:
373: static public String expandSysPropVars(String inString) {
374:
375: String outString = new String(inString);
376: int varOffset, varEnd;
377: String varVal, varName;
378:
379: while (true) {
380:
381: // Recursive substitution for ${x} variables.
382: varOffset = outString.indexOf("${");
383:
384: if (varOffset < 0) {
385: break;
386: }
387:
388: varEnd = outString.indexOf('}', varOffset + 2);
389:
390: if (varEnd < 0) {
391: break;
392: }
393:
394: varName = outString.substring(varOffset + 2, varEnd);
395:
396: if (varName.length() < 1) {
397: throw new IllegalArgumentException(
398: "Bad variable setting");
399: }
400:
401: varVal = System.getProperty(varName);
402:
403: if (varVal == null) {
404: throw new IllegalArgumentException(
405: "No Java system property with name '" + varName
406: + "'");
407: }
408:
409: outString = outString.substring(0, varOffset) + varVal
410: + outString.substring(varEnd + 1);
411: }
412:
413: return outString;
414: }
415: }
|