001: /*
002:
003: Derby - Class org.apache.derby.impl.tools.ij.util
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.tools.ij;
023:
024: import org.apache.derby.tools.JDBCDisplayUtil;
025: import org.apache.derby.iapi.tools.i18n.*;
026:
027: import java.io.BufferedInputStream;
028: import java.io.FileInputStream;
029: import java.io.FileNotFoundException;
030: import java.io.InputStream;
031: import java.io.IOException;
032: import java.lang.reflect.InvocationTargetException;
033:
034: import java.sql.Connection;
035: import java.sql.DriverManager;
036: import java.sql.SQLException;
037: import java.sql.SQLWarning;
038: import java.sql.Statement;
039: import java.sql.PreparedStatement;
040: import java.sql.ResultSet;
041: import java.sql.ResultSetMetaData;
042: import java.sql.Types;
043:
044: import java.util.Properties;
045: import java.util.Vector;
046: import java.util.Locale;
047:
048: /**
049: Methods used to control setup for apps as
050: well as display some internal ij structures.
051:
052: @see org.apache.derby.tools.JDBCDisplayUtil
053: @author ames
054: */
055: public final class util implements java.security.PrivilegedAction {
056:
057: private static boolean HAVE_BIG_DECIMAL;
058:
059: {
060: boolean haveBigDecimal;
061: try {
062: Class.forName("java.math.BigDecimal");
063: haveBigDecimal = true;
064: } catch (Throwable t) {
065: haveBigDecimal = false;
066: }
067: HAVE_BIG_DECIMAL = haveBigDecimal;
068: }
069:
070: private static final Class[] DS_GET_CONN_TYPES = { "".getClass(),
071: "".getClass() };
072:
073: private util() {
074: }
075:
076: //-----------------------------------------------------------------
077: // Methods for starting up JBMS
078:
079: /**
080: * Find the argument that follows the specified parameter.
081: *
082: * @param param the parameter (e.g. "-p")
083: * @param args the argument list to consider.
084: *
085: * @return the argument that follows the parameter, or null if not found
086: */
087: static public String getArg(String param, String[] args) {
088: int pLocn;
089: Properties p;
090:
091: if (args == null)
092: return null;
093:
094: for (pLocn = 0; pLocn < args.length; pLocn++) {
095: if (param.equals(args[pLocn]))
096: break;
097: }
098: if (pLocn >= (args.length - 1)) // not found or no file
099: return null;
100:
101: return args[pLocn + 1];
102: }
103:
104: /**
105: ij is started with "-p[r] file OtherArgs";
106: the file contains properties to control the driver and database
107: used to run ij, and can provide additional system properties.
108: <p>
109: getPropertyArg will look at the args and take out a "-p <file>" pair,
110: reading the file into the system properties.
111: <p>
112: If there was a -p without a following <file>, no action is taken.
113:
114: @exception IOException thrown if file not found
115:
116: @param args the argument list to consider.
117: @return true if a property item was found and loaded.
118: */
119: static public boolean getPropertyArg(String[] args)
120: throws IOException {
121: String n;
122: InputStream in1;
123: Properties p;
124:
125: if ((n = getArg("-p", args)) != null) {
126: in1 = new FileInputStream(n);
127: in1 = new BufferedInputStream(in1);
128: } else if ((n = getArg("-pr", args)) != null) {
129: in1 = getResourceAsStream(n);
130: if (in1 == null)
131: throw ijException.resourceNotFound();
132: } else
133: return false;
134:
135: p = System.getProperties();
136:
137: // Trim off excess whitespace in property file, if any, and
138: // then load those properties into 'p'.
139: util.loadWithTrimmedValues(in1, p);
140:
141: return true;
142: }
143:
144: /**
145: ij is started with "-ca[r] file OtherArgs";
146: the file contains connection attibute properties
147: to pass to getConnection
148: <p>
149: getConnAttributeArg will look at the args and take out a
150: "-ca[r] <file>" pair and returning the Properties
151: <p>
152:
153: @exception IOException thrown if file not found
154:
155: @param args the argument list to consider.
156: @return properties in the file
157: */
158: static public Properties getConnAttributeArg(String[] args)
159: throws IOException {
160: String n;
161: InputStream in1;
162: Properties p = new Properties();
163:
164: if ((n = getArg("-ca", args)) != null) {
165: in1 = new FileInputStream(n);
166: in1 = new BufferedInputStream(in1);
167: } else if ((n = getArg("-car", args)) != null) {
168: in1 = getResourceAsStream(n);
169: if (in1 == null)
170: throw ijException.resourceNotFound();
171: } else
172: return null;
173:
174: // Trim off excess whitespace in property file, if any, and
175: // then load those properties into 'p'.
176: util.loadWithTrimmedValues(in1, p);
177:
178: return p;
179: }
180:
181: /**
182: Convenience routine to qualify a resource name with "ij.defaultPackageName"
183: if it is not qualified (does not begin with a "/").
184:
185: @param absolute true means return null if the name is not absolute and false
186: means return partial names.
187: */
188: static String qualifyResourceName(String resourceName,
189: boolean absolute) {
190: resourceName = resourceName.trim();
191: if (resourceName.startsWith("/")) {
192: return resourceName;
193: } else {
194: String pName = util.getSystemProperty(
195: "ij.defaultResourcePackage").trim();
196: if (pName == null)
197: return null;
198: if ((pName).endsWith("/"))
199: resourceName = pName + resourceName;
200: else
201: resourceName = pName + "/" + resourceName;
202: if (absolute && !resourceName.startsWith("/"))
203: return null;
204: else
205: return resourceName;
206: }
207: }
208:
209: /**
210: Convenience routine to get a resource as a BufferedInputStream. If the
211: resourceName is not absolute (does not begin with a "/") this qualifies
212: the name with the "ij.defaultResourcePackage" name.
213:
214: @param resourceName the name of the resource
215: @return a buffered stream for the resource if it exists and null otherwise.
216: */
217: static public InputStream getResourceAsStream(String resourceName) {
218: Class c = util.class;
219: resourceName = qualifyResourceName(resourceName, true);
220: if (resourceName == null)
221: return null;
222: InputStream is = c.getResourceAsStream(resourceName);
223: if (is != null)
224: is = new BufferedInputStream(is, utilMain.BUFFEREDFILESIZE);
225: return is;
226: }
227:
228: /**
229: Return the name of the ij command file or null if none is
230: specified. The command file may be proceeded with -f flag on
231: the command line. Alternatively, the command file may be
232: specified without a -f flag. In this case we assume the first
233: unknown argument is the command file.
234:
235: <P>
236: This should only be called after calling invalidArgs.
237:
238: <p>
239: If there is no such argument, a null is returned.
240:
241: @param args the argument list to consider.
242: @return the name of the first argument not preceded by "-p",
243: null if none found.
244:
245: @exception IOException thrown if file not found
246: */
247: static public String getFileArg(String[] args) throws IOException {
248: String fileName;
249: int fLocn;
250: boolean foundP = false;
251:
252: if (args == null)
253: return null;
254: if ((fileName = getArg("-f", args)) != null)
255: return fileName;
256: //
257: //The first unknown arg is the file
258: for (int ix = 0; ix < args.length; ix++)
259: if (args[ix].equals("-f") || args[ix].equals("-fr")
260: || args[ix].equals("-ca")
261: || args[ix].equals("-car") || args[ix].equals("-p")
262: || args[ix].equals("-pr"))
263: ix++; //skip the parameter to these args
264: else
265: return args[ix];
266: return null;
267: }
268:
269: /**
270: Return the name of a resource containing input commands or
271: null iff none has been specified.
272: */
273: static public String getInputResourceNameArg(String[] args) {
274: return getArg("-fr", args);
275: }
276:
277: /**
278: Verify the ij line arguments command arguments. Also used to detect --help.
279: @return true if the args are invalid
280: <UL>
281: <LI>Only legal argument provided.
282: <LI>Only specify a quantity once.
283: </UL>
284: */
285: static public boolean invalidArgs(String[] args) {
286: int countSupported = 0;
287: boolean haveInput = false;
288: for (int ix = 0; ix < args.length; ix++) {
289: //
290: //If the arguemnt is a supported flag skip the flags argument
291: if (!haveInput
292: && (args[ix].equals("-f") || args[ix].equals("-fr"))) {
293: haveInput = true;
294: ix++;
295: if (ix >= args.length)
296: return true;
297: }
298:
299: else if ((args[ix].equals("-p") || args[ix].equals("-pr")
300: || args[ix].equals("-ca") || args[ix]
301: .equals("-car"))) {
302: // next arg is the file/resource name
303: ix++;
304: if (ix >= args.length)
305: return true;
306: } else if (args[ix].equals("--help")) {
307: return true;
308: }
309:
310: //
311: //Assume the first unknown arg is a file name.
312: else if (!haveInput) {
313: haveInput = true;
314: }
315:
316: else {
317: return true;
318: }
319: }
320: return false;
321: }
322:
323: /**
324: * print a usage message for invocations of main().
325: */
326: static void Usage(LocalizedOutput out) {
327: out.println(LocalizedResource
328: .getMessage("IJ_UsageJavaComCloudToolsIjPPropeInput"));
329: out.flush();
330: }
331:
332: private static final Class[] STRING_P = { "".getClass() };
333: private static final Class[] INT_P = { Integer.TYPE };
334:
335: /**
336: * Sets up a data source with values specified in ij.dataSource.* properties or
337: * passed as parameters of this method
338: *
339: * @param ds DataSource object
340: * @param dbName Database Name
341: * @param firstTime If firstTime is false, ij.dataSource.createDatabase and ij.dataSource.databaseName
342: * properties will not be used. The value in parameter dbName will be used instead of
343: * ij.dataSource.databaseName.
344: *
345: * @throws Exception
346: */
347: static public void setupDataSource(Object ds, String dbName,
348: boolean firstTime) throws Exception {
349: // Loop over set methods on Datasource object, if there is a property
350: // then call the method with corresponding value. Call setCreateDatabase based on
351: //parameter create.
352: java.lang.reflect.Method[] methods = ds.getClass().getMethods();
353: for (int i = 0; i < methods.length; i++) {
354: java.lang.reflect.Method m = methods[i];
355: String name = m.getName();
356:
357: if (name.startsWith("set")
358: && (name.length() > "set".length())) {
359: //Check if setCreateDatabase has to be called based on create parameter
360: if (name.equals("setCreateDatabase") && !firstTime)
361: continue;
362:
363: String property = name.substring("set".length()); // setXyyyZwww
364: property = "ij.dataSource."
365: + property.substring(0, 1).toLowerCase(
366: java.util.Locale.ENGLISH)
367: + property.substring(1); // xyyyZwww
368: String value = util.getSystemProperty(property);
369: if (name.equals("setDatabaseName") && !firstTime)
370: value = dbName;
371: if (value != null) {
372: try {
373: // call string method
374: m.invoke(ds, new Object[] { value });
375: } catch (Throwable ignore) {
376: // failed, assume it's an integer parameter
377: m.invoke(ds, new Object[] { Integer
378: .valueOf(value) });
379: }
380: }
381: }
382: }
383: }
384:
385: /**
386: * Returns a connection obtained using the DataSource. This method will be called when ij.dataSource
387: * property is set. It uses ij.dataSource.* properties to get details for the connection.
388: *
389: * @param dsName Data Source name
390: * @param user User name
391: * @param password Password
392: * @param dbName Database Name
393: * @param firstTime Indicates if the method is called first time. This is passed to setupDataSource
394: * method.
395: *
396: * @throws SQLException
397: */
398: public static Connection getDataSourceConnection(String dsName,
399: String user, String password, String dbName,
400: boolean firstTime) throws SQLException {
401: // Get a new proxied connection through DataSource
402: Object ds = null; // really javax.sql.DataSource
403: try {
404:
405: Class dc = Class.forName(dsName);
406: ds = dc.newInstance();
407:
408: // set datasource properties
409: setupDataSource(ds, dbName, firstTime);
410:
411: // Java method call "by hand" { con = ds.getConnection(); }
412: // or con = ds.getConnection(user, password)
413:
414: java.lang.reflect.Method m = user == null ? dc.getMethod(
415: "getConnection", null) : dc.getMethod(
416: "getConnection", DS_GET_CONN_TYPES);
417:
418: return (java.sql.Connection) m.invoke(ds,
419: user == null ? null
420: : new String[] { user, password });
421: } catch (InvocationTargetException ite) {
422: if (ite.getTargetException() instanceof SQLException)
423: throw (SQLException) ite.getTargetException();
424: ite.printStackTrace(System.out);
425: } catch (Exception e) {
426: e.printStackTrace(System.out);
427: }
428: return null;
429: }
430:
431: /**
432: This will look for the System properties "ij.driver" and "ij.database"
433: and return a java.sql.Connection if it successfully connects.
434: The deprecated driver and database properties are examined first.
435: <p>
436: If no connection was possible, it will return a null.
437: <p>
438: Failure to load the driver class is quietly ignored.
439:
440: @param defaultDriver the driver to use if no property value found
441: @param defaultURL the database URL to use if no property value found
442: @param connInfo Connection attributes to pass to getConnection
443: @return a connection to the defaultURL if possible; null if not.
444: @exception SQLException on failure to connect.
445: @exception ClassNotFoundException on failure to load driver.
446: @exception InstantiationException on failure to load driver.
447: @exception IllegalAccessException on failure to load driver.
448: */
449: static public Connection startJBMS(String defaultDriver,
450: String defaultURL, Properties connInfo)
451: throws SQLException, ClassNotFoundException,
452: InstantiationException, IllegalAccessException {
453: Connection con = null;
454: String driverName;
455: String databaseURL;
456:
457: // deprecate the non-ij prefix. actually, we should defer to jdbc.drivers...
458: driverName = util.getSystemProperty("driver");
459: if (driverName == null)
460: driverName = util.getSystemProperty("ij.driver");
461: if (driverName == null || driverName.length() == 0)
462: driverName = defaultDriver;
463: if (driverName != null) {
464: util.loadDriver(driverName);
465: }
466:
467: String jdbcProtocol = util.getSystemProperty("ij.protocol");
468: if (jdbcProtocol != null)
469: util.loadDriverIfKnown(jdbcProtocol);
470:
471: String user = util.getSystemProperty("ij.user");
472: String password = util.getSystemProperty("ij.password");
473:
474: // deprecate the non-ij prefix name
475: databaseURL = util.getSystemProperty("database");
476: if (databaseURL == null)
477: databaseURL = util.getSystemProperty("ij.database");
478: if (databaseURL == null || databaseURL.length() == 0)
479: databaseURL = defaultURL;
480: if (databaseURL != null) {
481: // add protocol if might help find driver.
482: // if have full URL, load driver for it
483: if (databaseURL.startsWith("jdbc:"))
484: util.loadDriverIfKnown(databaseURL);
485: if (!databaseURL.startsWith("jdbc:")
486: && jdbcProtocol != null)
487: databaseURL = jdbcProtocol + databaseURL;
488:
489: // Update connInfo for ij system properties and
490: // framework network server
491:
492: connInfo = updateConnInfo(user, password, connInfo);
493:
494: // JDBC driver
495: String driver = util.getSystemProperty("driver");
496: if (driver == null) {
497: driver = "org.apache.derby.jdbc.EmbeddedDriver";
498: }
499:
500: loadDriver(driver);
501: con = DriverManager.getConnection(databaseURL, connInfo);
502: return con;
503: }
504:
505: // handle datasource property
506: String dsName = util.getSystemProperty("ij.dataSource");
507: if (dsName == null)
508: return null;
509:
510: //First connection - pass firstTime=true, dbName=null. For database name,
511: //value in ij.dataSource.databaseName will be used.
512: con = getDataSourceConnection(dsName, user, password, null,
513: true);
514: return con;
515: }
516:
517: public static Properties updateConnInfo(String user,
518: String password, Properties connInfo) {
519: String ijGetMessages = util
520: .getSystemProperty("ij.retrieveMessagesFromServerOnGetMessage");
521: boolean retrieveMessages = false;
522:
523: // For JCC make sure we set it to retrieve messages
524: if (isJCCFramework())
525: retrieveMessages = true;
526:
527: if (ijGetMessages != null) {
528: if (ijGetMessages.equals("false"))
529: retrieveMessages = false;
530: else
531: retrieveMessages = true;
532:
533: }
534:
535: if (connInfo == null)
536: connInfo = new Properties();
537:
538: if (retrieveMessages == true) {
539: connInfo.put("retrieveMessagesFromServerOnGetMessage",
540: "true");
541: }
542: if (user != null)
543: connInfo.put("user", user);
544: if (password != null)
545: connInfo.put("password", password);
546:
547: return connInfo;
548: }
549:
550: /**
551: Utility interface that defaults driver and database to null.
552:
553: @return a connection to the defaultURL if possible; null if not.
554: @exception SQLException on failure to connect.
555: @exception ClassNotFoundException on failure to load driver.
556: @exception InstantiationException on failure to load driver.
557: @exception IllegalAccessException on failure to load driver.
558: */
559: static public Connection startJBMS() throws SQLException,
560: ClassNotFoundException, InstantiationException,
561: IllegalAccessException {
562: return startJBMS(null, null);
563: }
564:
565: /**
566: Utility interface that defaults connInfo to null
567: <p>
568:
569:
570: @param defaultDriver the driver to use if no property value found
571: @param defaultURL the database URL to use if no property value found
572: @return a connection to the defaultURL if possible; null if not.
573: @exception SQLException on failure to connect.
574: @exception ClassNotFoundException on failure to load driver.
575: @exception InstantiationException on failure to load driver.
576: @exception IllegalAccessException on failure to load driver.
577: */
578: static public Connection startJBMS(String defaultDriver,
579: String defaultURL) throws SQLException,
580: ClassNotFoundException, InstantiationException,
581: IllegalAccessException {
582: return startJBMS(defaultDriver, defaultURL, null);
583:
584: }
585:
586: //-----------------------------------------------------------------
587: // Methods for displaying and checking results
588: // See org.apache.derby.tools.JDBCDisplayUtil for more general displays.
589:
590: /**
591: Display a vector of strings to the out stream.
592: */
593: public static void DisplayVector(LocalizedOutput out, Vector v) {
594: int l = v.size();
595: for (int i = 0; i < l; i++)
596: out.println(v.elementAt(i));
597: }
598:
599: /**
600: Display a vector of statements to the out stream.
601: public static void DisplayVector(AppStreamWriter out, Vector v, Connection conn) throws SQLException {
602: int l = v.size();
603: AppUI.out.println("SIZE="+l);
604: for (int i=0;i<l;i++) {
605: Object o = v.elementAt(i);
606: if (o instanceof Integer) { // update count
607: JDBCDisplayUtil.DisplayUpdateCount(out,((Integer)o).intValue());
608: } else { // o instanceof ResultSet
609: JDBCDisplayUtil.DisplayResults(out,(ResultSet)o,conn);
610: ((ResultSet)o).close(); // release the result set
611: }
612: }
613: }
614: */
615:
616: /**
617: Display a statement that takes parameters by
618: stuffing it with rows from the result set and
619: displaying each result each time through.
620: Deal with autocommit behavior along the way.
621:
622: @exception SQLException thrown on db error
623: @exception ijException thrown on ij error
624: */
625: public static void DisplayMulti(LocalizedOutput out,
626: PreparedStatement ps, ResultSet rs, Connection conn)
627: throws SQLException, ijException {
628:
629: boolean autoCommited = false; // mark if autocommit in place
630: boolean exec = false; // mark the first time through
631: boolean anotherUsingRow = false; // remember if there's another row
632: // from using.
633: ResultSetMetaData rsmd = rs.getMetaData();
634: int numCols = rsmd.getColumnCount();
635:
636: /* NOTE: We need to close the USING RS first
637: * so that RunTimeStatistic gets info from
638: * the user query.
639: */
640: anotherUsingRow = rs.next();
641:
642: while (!autoCommited && anotherUsingRow) {
643: // note the first time through
644: if (!exec) {
645: exec = true;
646:
647: // send a warning if additional results may be lost
648: if (conn.getAutoCommit()) {
649: out
650: .println(LocalizedResource
651: .getMessage("IJ_IjWarniAutocMayCloseUsingResulSet"));
652: autoCommited = true;
653: }
654: }
655:
656: // We need to make sure we pass along the scale, because
657: // setObject assumes a scale of zero (beetle 4365)
658: for (int c = 1; c <= numCols; c++) {
659: int sqlType = rsmd.getColumnType(c);
660:
661: if (sqlType == Types.DECIMAL) {
662: if (util.HAVE_BIG_DECIMAL) {
663: ps.setObject(c, rs.getObject(c), sqlType, rsmd
664: .getScale(c));
665: } else {
666: // In J2ME there is no object that represents
667: // a DECIMAL value. By default use String to
668: // pass values around, but for integral types
669: // first convert to a integral type from the DECIMAL
670: // because strings like 3.4 are not convertible to
671: // an integral type.
672: switch (ps.getMetaData().getColumnType(c)) {
673: case Types.BIGINT:
674: ps.setLong(c, rs.getLong(c));
675: break;
676: case Types.INTEGER:
677: case Types.SMALLINT:
678: case Types.TINYINT:
679: ps.setInt(c, rs.getInt(c));
680: break;
681: default:
682: ps.setString(c, rs.getString(c));
683: break;
684: }
685: }
686:
687: } else {
688: ps.setObject(c, rs.getObject(c), sqlType);
689: }
690:
691: }
692:
693: // Advance in the USING RS
694: anotherUsingRow = rs.next();
695: // Close the USING RS when exhausted and appropriate
696: // NOTE: Close before the user query
697: if (!anotherUsingRow || conn.getAutoCommit()) //if no more rows or if auto commit is on, close the resultset
698: {
699: rs.close();
700: }
701:
702: /*
703: 4. execute the statement against those parameters
704: */
705:
706: ps.execute();
707: JDBCDisplayUtil.DisplayResults(out, ps, conn);
708:
709: /*
710: 5. clear the parameters
711: */
712: ps.clearParameters();
713: }
714: if (!exec) {
715: rs.close(); //this means, using clause didn't qualify any rows. Just close the resultset associated with using clause
716: throw ijException.noUsingResults();
717: }
718: // REMIND: any way to look for more rsUsing rows if autoCommit?
719: // perhaps just document the behavior...
720: }
721:
722: static final String getSystemProperty(String propertyName) {
723: try {
724: if (propertyName.startsWith("ij.")
725: || propertyName.startsWith("derby.")) {
726: util u = new util();
727: u.key = propertyName;
728: return (String) java.security.AccessController
729: .doPrivileged(u);
730: } else {
731: return System.getProperty(propertyName);
732: }
733: } catch (SecurityException se) {
734: return null;
735: }
736: }
737:
738: private String key;
739:
740: public final Object run() {
741: return System.getProperty(key);
742: }
743:
744: /**
745: * Read a set of properties from the received input stream, strip
746: * off any excess white space that exists in those property values,
747: * and then add those newly-read properties to the received
748: * Properties object; not explicitly removing the whitespace here can
749: * lead to problems.
750: *
751: * This method exists because of the manner in which the jvm reads
752: * properties from file--extra spaces are ignored after a _key_, but
753: * if they exist at the _end_ of a property decl line (i.e. as part
754: * of a _value_), they are preserved, as outlined in the Java API:
755: *
756: * "Any whitespace after the key is skipped; if the first non-
757: * whitespace character after the key is = or :, then it is ignored
758: * and any whitespace characters after it are also skipped. All
759: * remaining characters on the line become part of the associated
760: * element string."
761: *
762: * Creates final properties set consisting of 'prop' plus all
763: * properties loaded from 'iStr' (with the extra whitespace (if any)
764: * removed from all values), will be returned via the parameter.
765: *
766: * @param iStr An input stream from which the new properties are to be
767: * loaded (should already be initialized).
768: * @param prop A set of properties to which the properties from
769: * iStr will be added (should already be initialized).
770: *
771: * Copied here to avoid dependency on an engine class.
772: **/
773: private static void loadWithTrimmedValues(InputStream iStr,
774: Properties prop) throws IOException {
775:
776: // load the properties from the received input stream.
777: Properties p = new Properties();
778: p.load(iStr);
779:
780: // Now, trim off any excess whitespace, if any, and then
781: // add the properties from file to the received Properties
782: // set.
783: for (java.util.Enumeration propKeys = p.propertyNames(); propKeys
784: .hasMoreElements();) {
785: // get the value, trim off the whitespace, then store it
786: // in the received properties object.
787: String tmpKey = (String) propKeys.nextElement();
788: String tmpValue = p.getProperty(tmpKey);
789: tmpValue = tmpValue.trim();
790: prop.put(tmpKey, tmpValue);
791: }
792:
793: return;
794:
795: }
796:
797: private static final String[][] protocolDrivers = {
798: { "jdbc:derby:net:", "com.ibm.db2.jcc.DB2Driver" },
799: { "jdbc:derby://", "org.apache.derby.jdbc.ClientDriver" },
800:
801: { "jdbc:derby:", "org.apache.derby.jdbc.EmbeddedDriver" }, };
802:
803: /**
804: Find the appropriate driver and load it, given a JDBC URL.
805: No action if no driver known for a given URL.
806:
807: @param jdbcProtocol the protocol to try.
808:
809: @exception ClassNotFoundException if unable to
810: locate class for driver.
811: @exception InstantiationException if unable to
812: create an instance.
813: @exception IllegalAccessException if driver class constructor not visible.
814: */
815: public static void loadDriverIfKnown(String jdbcProtocol)
816: throws ClassNotFoundException, InstantiationException,
817: IllegalAccessException {
818: for (int i = 0; i < protocolDrivers.length; i++) {
819: if (jdbcProtocol.startsWith(protocolDrivers[i][0])) {
820: loadDriver(protocolDrivers[i][1]);
821: break; // only want the first one
822: }
823: }
824: }
825:
826: /**
827: Load a driver given a class name.
828:
829: @exception ClassNotFoundException if unable to
830: locate class for driver.
831: @exception InstantiationException if unable to
832: create an instance.
833: @exception IllegalAccessException if driver class constructor not visible.
834: */
835: public static void loadDriver(String driverClass)
836: throws ClassNotFoundException, InstantiationException,
837: IllegalAccessException {
838: Class.forName(driverClass).newInstance();
839: }
840:
841: /**
842: * Used to determine if this is a JCC testing framework
843: * So that retrieveMessages can be sent. The plan is to have
844: * ij will retrieve messages by default and not look at the testing
845: * frameworks. So, ulitmately this function will look at the driver
846: * rather than the framework.
847: *
848: * @return true if the framework contains Net or JCC.
849: */
850: private static boolean isJCCFramework() {
851: String framework = util.getSystemProperty("framework");
852: return ((framework != null) && ((framework
853: .toUpperCase(Locale.ENGLISH).equals("DERBYNET")) || (framework
854: .toUpperCase(Locale.ENGLISH).indexOf("JCC") != -1)));
855: }
856:
857: /**
858: * Selects the current schema from the given connection.
859: *
860: * As there are no way of getting current schema supported by
861: * all major DBMS-es, this method may return null.
862: *
863: * @param theConnection Connection to get current schema for
864: * @return the current schema of the connection, or null if error.
865: */
866: public static String getSelectedSchema(Connection theConnection)
867: throws SQLException {
868: String schema = null;
869: if (theConnection == null)
870: return null;
871: Statement st = theConnection.createStatement();
872: try {
873: if (!st.execute("VALUES CURRENT SCHEMA"))
874: return null;
875:
876: ResultSet rs = st.getResultSet();
877: if (rs == null || !rs.next())
878: return null;
879: schema = rs.getString(1);
880: } catch (SQLException e) {
881: // There are no standard way of getting schema.
882: // Getting default schema may fail.
883: } finally {
884: st.close();
885: }
886: return schema;
887: }
888: }
|