001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.dataconnectivity.sql;
042:
043: import java.io.PrintWriter;
044: import java.net.URL;
045: import java.net.URLClassLoader;
046: import java.sql.SQLException;
047: import java.sql.Connection;
048: import java.sql.DatabaseMetaData;
049: import java.sql.Driver;
050: import java.sql.ResultSet;
051: import java.sql.Statement;
052: import java.text.MessageFormat;
053: import java.util.ArrayList;
054: import java.util.Collection;
055: import java.util.Iterator;
056: import java.util.Locale;
057:
058: import java.util.Properties;
059: import java.util.ResourceBundle;
060: import java.util.SortedSet;
061: import java.util.StringTokenizer;
062: import java.util.TreeSet;
063: import javax.crypto.Cipher;
064: import javax.crypto.SecretKey;
065: import javax.crypto.spec.SecretKeySpec;
066: import javax.naming.NamingException;
067: import javax.sql.DataSource;
068:
069: import org.netbeans.modules.visualweb.dataconnectivity.naming.ContextPersistance;
070: import org.netbeans.modules.visualweb.dataconnectivity.naming.ObjectChangeListener;
071: import org.netbeans.modules.visualweb.dataconnectivity.naming.ObjectChangeEvent;
072:
073: import org.netbeans.api.db.explorer.ConnectionManager;
074: import org.netbeans.api.db.explorer.DatabaseConnection;
075:
076: import org.netbeans.api.db.explorer.JDBCDriver;
077: import org.netbeans.api.db.sql.support.SQLIdentifiers;
078: import org.netbeans.modules.visualweb.dataconnectivity.datasource.DataSourceResolver;
079: import org.openide.util.RequestProcessor;
080:
081: /**
082: * DataSource adapter for java.sql.Driver classes. Used at designtime for all datasources.
083: * Implements necesary interfaces to persist in Creator's naming context.
084: *
085: * @author John Kline
086: */
087: public class DesignTimeDataSource implements DataSource,
088: ContextPersistance, Runnable {
089:
090: protected static ResourceBundle rb = ResourceBundle
091: .getBundle(
092: "org.netbeans.modules.visualweb.dataconnectivity.sql.Bundle", //NOI18N
093: Locale.getDefault());
094:
095: private boolean schemasInitialized;
096: private SortedSet schemas; // empty set == display all schemas
097: private String driverClassName;
098: private String url;
099: private String username;
100: private String password;
101: private String validationQuery;
102: private PrintWriter logWriter;
103: private int loginTimeout;
104: private SQLException testSQLException;
105: private boolean testConnectionSucceeded;
106: private int testSQLRowsReturned;
107: private ArrayList objectChangeListeners;
108: private Driver driver;
109: private Connection designtimeConnection;
110: private static boolean isConnectionAttempted = false;
111: private DatabaseConnection dbConn;
112: private static URL[] urls;
113: private RequestProcessor.Task task = null;
114: private final RequestProcessor CONNECT_RP = new RequestProcessor(
115: "DataSourceResolver.WAIT_FOR_MODELING_RP"); //NOI18N
116:
117: private static final String alphabet = "abcdefghijklmnopqrstuvwxyz"; // NOI18N
118: private static final String DRIVER_CLASS_NET = "org.apache.derby.jdbc.ClientDriver"; // NOI18N
119: private static final String SELECT_PHRASE = "select * from ";
120: private static final String SELECT_PHRASE_APPSERVER8 = "select count(*) from ";
121: public static final int SQL_NOT_RUN = -1;
122:
123: static private SecretKey secretKey = null;
124:
125: static final private char[] secretKeyHex = { 'D', '6', '0', '7',
126: '5', 'E', '2', '9', '8', 'A', '4', '9', '6', '2', '5', '1' };
127:
128: private static SecretKey getSecretKey() {
129: if (secretKey == null) {
130: byte[] encodedKey = new byte[secretKeyHex.length / 2];
131: for (int i = 0; i < encodedKey.length; i++) {
132: encodedKey[i] = hexToByte(secretKeyHex[i * 2],
133: secretKeyHex[i * 2 + 1]);
134: }
135: secretKey = new SecretKeySpec(encodedKey, "DES"); // NOI18N
136: }
137:
138: return secretKey;
139: }
140:
141: public DesignTimeDataSource() {
142: this (null, false, null, null, null, null, null);
143: }
144:
145: /*
146: * The first argument signals whether or not the password is encrypted and should be
147: * decrypted.
148: */
149: public DesignTimeDataSource(Boolean isEncrypted,
150: String driverClassName, String url, String validationQuery,
151: String username, String password) {
152:
153: this (null, isEncrypted, driverClassName, url, validationQuery,
154: username, password);
155: }
156:
157: public DesignTimeDataSource(String schemas, Boolean isEncrypted,
158: String driverClassName, String url, String validationQuery,
159: String username, String password) {
160:
161: this (false, schemas, (isEncrypted == null) ? false
162: : isEncrypted.booleanValue(), driverClassName, url,
163: validationQuery, username, password);
164: }
165:
166: public DesignTimeDataSource(Boolean schemasInitialized,
167: String schemas, Boolean isEncrypted,
168: String driverClassName, String url, String validationQuery,
169: String username, String password) {
170:
171: this ((schemasInitialized == null) ? false : schemasInitialized
172: .booleanValue(), schemas, (isEncrypted == null) ? false
173: : isEncrypted.booleanValue(), driverClassName, url,
174: validationQuery, username, password);
175: }
176:
177: public DesignTimeDataSource(String schemas, boolean isEncrypted,
178: String driverClassName, String url, String validationQuery,
179: String username, String password) {
180: this (false, schemas, isEncrypted, driverClassName, url,
181: validationQuery, username, password);
182: }
183:
184: /*
185: * The first argument is used to tell if we have initalized the schemas by calling
186: * initSchemas.
187: * The second argument is used to limit the schemas to be used in the datasource.
188: * schemas == null signals all schemas
189: * The third argument signals whether or not the password is encrypted and should therefore
190: * be decrypted.
191: */
192: public DesignTimeDataSource(boolean schemasInitialized,
193: String schemas, boolean isEncrypted,
194: String driverClassName, String url, String validationQuery,
195: String username, String password) {
196:
197: this .schemasInitialized = schemasInitialized;
198: this .schemas = parseSchemas(schemas);
199: this .driverClassName = driverClassName;
200: this .url = url;
201: this .username = username;
202: this .password = null;
203: if (password != null) {
204: this .password = isEncrypted ? decryptPassword(password)
205: : password;
206: }
207: logWriter = null;
208: loginTimeout = 0;
209: this .validationQuery = validationQuery;
210: testSQLException = null;
211: testConnectionSucceeded = false;
212: testSQLRowsReturned = SQL_NOT_RUN;
213: objectChangeListeners = new ArrayList();
214: driver = null;
215:
216: }
217:
218: /* props for handling last connection failures. If a connect fails,
219: * save the time and the failure SQLException.
220: * When asked for another connection, don't even try if the last try failed
221: * _and_ the last connection try was less than XXXX milliseconds ago.
222: */
223:
224: private String enableFastConnectFail = System.getProperty(
225: "rave.fastConnectFail", "true");
226: private boolean lastConnectFail = false;
227: private long lastConnectFailTime = 0;
228: private static long CONNECT_RETRY_MS = 2690; // milliseconds before a retry.
229: private SQLException failException = null;
230:
231: public void clearConnectFailFlag() {
232: lastConnectFail = false;
233: }
234:
235: private void setLastConnectFail(SQLException newException) {
236: lastConnectFail = true;
237: lastConnectFailTime = System.currentTimeMillis();
238: if (newException != null)
239: failException = newException;
240: }
241:
242: private void checkLastConnectFail() throws SQLException {
243: if (lastConnectFail) {
244: if ((System.currentTimeMillis() - lastConnectFailTime) < CONNECT_RETRY_MS) {
245: setLastConnectFail(null);
246: SQLException ee = new SQLException(
247: "Connect Retry recent failure: "
248: + failException.getLocalizedMessage());
249: ee.setNextException(failException);
250: if (enableFastConnectFail.equalsIgnoreCase("console")) {
251: System.out
252: .println("DesignTimeDataSource connect retry auto-failure for "
253: + getUrl());
254: }
255: throw ee;
256: }
257: lastConnectFail = false; // retry the next time too.
258: }
259: }
260:
261: public synchronized Connection getConnection() throws SQLException {
262: // cache the connection so that it can be reused
263: if (designtimeConnection == null) {
264: designtimeConnection = getConnection(username, password);
265: }
266: return designtimeConnection;
267: }
268:
269: public synchronized Connection getConnection(String username,
270: String password) throws SQLException {
271: if (designtimeConnection == null) {
272: Log.getLogger().entering(getClass().getName(),
273: toString() + ".getConnection()",
274: new Object[] { username, password });
275: checkLastConnectFail();
276:
277: DatabaseConnection[] dbConns = ConnectionManager
278: .getDefault().getConnections();
279:
280: for (int i = 0; i < dbConns.length; i++) {
281: if (url.equalsIgnoreCase(dbConns[i].getDatabaseURL())) {
282: dbConn = dbConns[i];
283: url = dbConns[i].getDatabaseURL();
284: break;
285: }
286: }
287:
288: if (dbConn != null) {
289: JDBCDriver jdbcDriver = DataSourceResolver
290: .getInstance().findMatchingDriver(
291: dbConn.getDriverClass());
292: urls = jdbcDriver.getURLs();
293:
294: driverClassName = dbConn.getDriverClass();
295: loadDriver();
296: }
297:
298: Properties props = new Properties();
299: if (username != null) {
300: props.put("user", username); // NOI18N
301: }
302: if (password != null) {
303: props.put("password", password); // NOI18N
304: }
305:
306: /*
307: * It turns out we can't rely on drivers to only throw SQLExceptions.
308: * e.g., see bug #5046309 - Test Connection throws Exception when URL has #PORTNUMBER
309: * the above throws a NumberFormatException
310: * so let's catch everything and "wrap" any non-SQLException exceptions
311: */
312: try {
313: if (driverClassName.equals(DRIVER_CLASS_NET)
314: && !isConnectionAttempted) {
315: isConnectionAttempted = true;
316: ensureConnection();
317: }
318:
319: Connection conn = driver.connect(url, props);
320: /*
321: * See Driver.connect spec. connect is supposed to return null if it realizes
322: * it is not the right driver for the url. This is #@!$!$@$#@, but we have to
323: * live with it.
324: */
325: if (conn == null) {
326: SQLException se = new SQLException(
327: MessageFormat
328: .format(
329: rb
330: .getString("WRONG_DRIVER_FOR_URL"),
331: new Object[] {
332: driverClassName,
333: url })); // NOI18N
334: setLastConnectFail(se);
335: throw se;
336: }
337:
338: designtimeConnection = new DesignTimeConnection(this ,
339: conn);
340:
341: } catch (Exception e) {
342: if (e instanceof SQLException) {
343: setLastConnectFail((SQLException) e);
344: throw (SQLException) e;
345: }
346: SQLException sqlEx = new SQLException(e
347: .getLocalizedMessage());
348: sqlEx.initCause(e);
349: setLastConnectFail(sqlEx);
350: throw sqlEx;
351: }
352: }
353: return designtimeConnection;
354: }
355:
356: public PrintWriter getLogWriter() throws SQLException {
357: return logWriter;
358: }
359:
360: public void setLogWriter(PrintWriter out) throws SQLException {
361: this .logWriter = out;
362: }
363:
364: public int getLoginTimeout() throws SQLException {
365: return loginTimeout;
366: }
367:
368: public void setLoginTimeout(int seconds) throws SQLException {
369: this .loginTimeout = seconds;
370: }
371:
372: public String getDriverClassName() {
373: return driverClassName;
374: }
375:
376: public void setDriverClassName(String driverClassName) {
377: this .driverClassName = driverClassName;
378: /*
379: * invalidate any driver instance we are holding on to
380: */
381: driver = null;
382: }
383:
384: public String getUrl() {
385: return url;
386: }
387:
388: public void setUrl(String url) {
389: this .url = url;
390: }
391:
392: public String getUsername() {
393: return username;
394: }
395:
396: public void setUsername(String username) {
397: this .username = username;
398: }
399:
400: public String getPassword() {
401: return password;
402: }
403:
404: public void setPassword(String password) {
405: this .password = password;
406: }
407:
408: public String getValidationQuery() {
409: return validationQuery;
410: }
411:
412: public void setValidationQuery(String validationQuery) {
413: this .validationQuery = validationQuery;
414: }
415:
416: // We only store the ValidationQuery as "select * from <table>"
417: // Extract the <table> here.
418: public String getValidationTable() {
419: // see if it start's with SELECT_PHRASE, otherwise try a hack
420: String validationTable = parseForValidationTable(getValidationQuery());
421:
422: return (validationTable == null ? "" : validationTable); // NOI18N
423: }
424:
425: public void setValidationTable(String table) {
426: setValidationQuery(composeValidationQuery(table));
427: }
428:
429: protected static String composeValidationQuery(String table) {
430: return SELECT_PHRASE + table;
431: }
432:
433: protected static String parseForValidationTable(String valQuery) {
434: // see if it start's with SELECT_PHRASE, otherwise try a hack
435: String validationTable = null;
436:
437: if (valQuery == null)
438: return null;
439: String vq = valQuery.toLowerCase();
440:
441: if (vq != null && vq.startsWith(SELECT_PHRASE.toLowerCase())) {
442: if (vq.length() > SELECT_PHRASE.length()) {
443: validationTable = valQuery.substring(SELECT_PHRASE
444: .length());
445: }
446: } else {
447: // HACK - look for last "from" and get the next word after that.
448: if ((valQuery != null) && !valQuery.trim().equals("")) { // NOI18N
449: StringTokenizer st = new StringTokenizer(valQuery);
450: while (st.hasMoreTokens()) {
451: if (st.nextToken().toUpperCase().equals("FROM")) { // NOI18N
452: if (st.hasMoreTokens()) {
453: validationTable = st.nextToken();
454: }
455: break;
456: }
457: }
458: }
459: }
460: return validationTable;
461: }
462:
463: public boolean test() {
464: testSQLException = null;
465: testConnectionSucceeded = false;
466: testSQLRowsReturned = SQL_NOT_RUN;
467: Connection conn = null;
468: try {
469: conn = getConnection();
470: testConnectionSucceeded = true;
471: } catch (SQLException e) {
472: testSQLException = e;
473: }
474: if (testConnectionSucceeded && validationQuery != null
475: && !validationQuery.equals("")) {
476: try {
477: Statement stmt = conn.createStatement();
478: String valQuery = SELECT_PHRASE_APPSERVER8
479: + getValidationTable();
480: ResultSet rs = stmt.executeQuery(valQuery);
481: // There could be table with out rows. Let us depend
482: // only on the SQL exception.
483: // testSQLRowsReturned = 0 ; // shouldn't need if we select count(*).
484: if (rs.next()) {
485: testSQLRowsReturned = rs.getInt(1);
486: }
487:
488: } catch (SQLException e) {
489: testSQLException = e;
490: return false;
491: }
492: }
493: // lastly, close the connection
494: if (conn != null) {
495: try {
496: conn.close();
497: } catch (SQLException e2) {
498: }
499: }
500: return testConnectionSucceeded;
501: }
502:
503: public SQLException getTestException() {
504: return testSQLException;
505: }
506:
507: public int getTestRowsReturned() {
508: return testSQLRowsReturned;
509: }
510:
511: public boolean getTestConnectionSucceeded() {
512: return testConnectionSucceeded;
513: }
514:
515: /**
516: * gets schemas selected for this datasource, an empty set means all schemas
517: */
518: public String[] getSchemas() {
519: return (String[]) schemas.toArray(new String[0]);
520: }
521:
522: public void setSchemas(Collection schemas) {
523: clearSchemas();
524: this .schemas.addAll(schemas);
525: }
526:
527: /**
528: * attempt to set the initial setting for schemas
529: * do this by attempting to get a schema with the same name as the username
530: * if this is found, set this datasource to only show that one schema
531: * else don't do anything (all schemas will show or the database doesn't support
532: * schemas)
533: *
534: * throws SQLException if we can't connect or can't get DatabaseMetaData
535: *
536: * throws NamingException if this DesignTimeDataSource is already bound to
537: * a context and something goes wrong in the save
538: */
539: synchronized public void initSchemas() throws SQLException,
540: NamingException {
541: if (getSchemasInitialized()) {
542: return;
543: }
544: clearSchemas();
545: DatabaseMetaDataHelper dbmdh = new DatabaseMetaDataHelper(this );
546: String[] schemas = dbmdh.getSchemas();
547: for (int i = 0; i < schemas.length; i++) {
548: if (schemas[i].toLowerCase().equals(username.toLowerCase())) {
549: /*
550: * make sure we have at least one table or view in this schema
551: * if we don't, then show all schemas
552: */
553: String query;
554: if ((query = dbmdh.getValidationQuery(schemas[i])) != null) {
555: if (validationQuery == null) {
556: validationQuery = query;
557: }
558: addSchema(schemas[i]);
559: } else {
560: /*
561: * We shouldn't have to do this. No schemas selected
562: * is supposed to signal all schemas -- but servernav
563: * seems to think differently.
564: */
565: for (int j = 0; j < schemas.length; j++) {
566: addSchema(schemas[j]);
567: }
568: }
569: break;
570: }
571: }
572: /* Validation query will still be null if this database has no schemas or if
573: * we didn't limit this datasource to a single schema above. If so, let's try
574: * to set it now.
575: */
576: if (validationQuery == null) {
577: validationQuery = dbmdh.getValidationQuery(null);
578: }
579: setSchemasInitialized(true);
580: save();
581: }
582:
583: public boolean getSchemasInitialized() {
584: return schemasInitialized;
585: }
586:
587: public void setSchemasInitialized(boolean schemasInitialized) {
588: this .schemasInitialized = schemasInitialized;
589: }
590:
591: public void clearSchemas() {
592: this .schemas.clear();
593: }
594:
595: public void addSchema(String schema) {
596: schemas.add(schema);
597: }
598:
599: public void removeSchema(String schema) {
600: schemas.remove(schema);
601: }
602:
603: public String getTag(String key, int level, int tabWidth) {
604:
605: return getSpaces(level, tabWidth)
606: + "<object name=\""
607: + key
608: + "\" class=\""
609: + getClass().getName()
610: + "\">\n" //NOI18N
611:
612: + getSpaces(level + 1, tabWidth)
613: + "<arg class=\"java.lang.Boolean\" value=\"" //NOI18N
614: + (getSchemasInitialized() ? "true" : "false")
615: + "\"/>\n" //NOI18N
616:
617: + getSpaces(level + 1, tabWidth)
618: + "<arg class=\"java.lang.String\""
619: + getSchemaValueAttribute()
620: + "/>\n" //NOI18N
621:
622: + getSpaces(level + 1, tabWidth)
623: + "<arg class=\"java.lang.Boolean\" value=\"true\"/>\n" // NOI18N
624:
625: + getSpaces(level + 1, tabWidth)
626: + "<arg class=\"java.lang.String\"" // NOI18N
627: + ((driverClassName == null) ? "" : " value=\""
628: + driverClassName //NOI18N
629: + "\"") //NOI18N
630: + "/>\n" //NOI18N
631:
632: + getSpaces(level + 1, tabWidth)
633: + "<arg class=\"java.lang.String\"" // NOI18N
634: + ((url == null) ? "" : " value=\"" + escapeXML(url)
635: + "\"") // NOI18N
636: + "/>\n" // NOI18N
637:
638: + getSpaces(level + 1, tabWidth)
639: + "<arg class=\"java.lang.String\"" // NOI18N
640: + ((validationQuery == null) ? "" : " value=\""
641: + escapeXML(validationQuery) + "\"") // NOI18N
642: + "/>\n" // NOI18N
643:
644: + getSpaces(level + 1, tabWidth)
645: + "<arg class=\"java.lang.String\"" // NOI18N
646: + ((username == null) ? "" : " value=\"" + username
647: + "\"") // NOI18N
648: + "/>\n" // NOI18N
649:
650: + getSpaces(level + 1, tabWidth)
651: + "<arg class=\"java.lang.String\"" // NOI18N
652: + ((password == null) ? "" : " value=\""
653: + encryptPassword(password) + "\"") // NOI18N
654: + "/>\n" // NOI18N
655:
656: + getSpaces(level, tabWidth) + "</object>\n"; // NOI18N
657: }
658:
659: /**
660: * escape to XML legal. The chars -
661: * quote("), apostrophe('), ampersand, less than, greater than
662: * need to be escaped.
663: */
664: protected static String escapeXML(String orig) {
665: String retVal = orig.replaceAll("&", "&"); // do this first.
666: retVal = retVal.replaceAll("<", "<");
667: retVal = retVal.replaceAll(">", ">");
668: retVal = retVal.replaceAll("\"", """);
669: retVal = retVal.replaceAll("'", "'");
670: return retVal;
671: }
672:
673: public void addObjectChangeListener(ObjectChangeListener listener) {
674: objectChangeListeners.add(listener);
675: }
676:
677: public void removeObjectChangeListener(ObjectChangeListener listener) {
678: objectChangeListeners.remove(listener);
679: }
680:
681: public void save() throws NamingException {
682: if (!objectChangeListeners.isEmpty()) {
683: ObjectChangeEvent evt = new ObjectChangeEvent(this );
684: for (Iterator i = objectChangeListeners.iterator(); i
685: .hasNext();) {
686: ((ObjectChangeListener) i.next()).objectChanged(evt);
687: }
688: }
689: }
690:
691: private static SortedSet parseSchemas(String schemas) {
692:
693: SortedSet set = new TreeSet();
694:
695: if (schemas != null && !schemas.trim().equals("")) {
696: String[] schema = schemas.split(","); // NOI18N
697: for (int i = 0; i < schema.length; i++) {
698: if (!schema[i].trim().equals("")) {
699: set.add(schema[i]);
700: }
701: }
702: }
703: return set;
704: }
705:
706: private String getSchemaValueAttribute() {
707:
708: String csv = "";
709:
710: for (Iterator i = schemas.iterator(); i.hasNext();) {
711: if (!csv.equals("")) {
712: csv += ","; // NOI18N
713: }
714: csv += (String) i.next();
715: }
716:
717: return csv.equals("") ? "" : (" value=\"" + csv + "\""); // NOI18N
718: }
719:
720: public static String encryptPassword(String password) {
721:
722: if (password == null) {
723: return null;
724: }
725:
726: try {
727: Cipher cipher = Cipher.getInstance("DES"); // NOI18N
728: cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
729: byte[] passwordBytes = password.getBytes("UTF8"); // NOI18N
730: // encrypt
731: byte[] encryptedBytes = cipher.doFinal(passwordBytes);
732: // convert to hex
733: char[] hexChars = new char[encryptedBytes.length * 2];
734: for (int i = 0; i < encryptedBytes.length; i++) {
735: hexChars[i * 2] = nibbleToHex((encryptedBytes[i] & 240) >> 4);
736: hexChars[i * 2 + 1] = nibbleToHex(encryptedBytes[i] & 15);
737: }
738: return new String(hexChars);
739: } catch (Exception e) {
740: e.printStackTrace();
741: return "";
742: }
743: }
744:
745: public static String composeSelect(String tableName,
746: DatabaseMetaData metaData) {
747:
748: SQLIdentifiers.Quoter quoter;
749: quoter = SQLIdentifiers.createQuoter(metaData);
750:
751: String[] names = tableName.split("\\.");
752: String selectName = "";
753: for (int i = 0; i < names.length; i++) {
754: if (i != 0) {
755: selectName += ".";
756: }
757: // Delimit identifiers if necessary
758: selectName += quoter.quoteIfNeeded(names[i]);
759: }
760: return "SELECT * FROM " + selectName; // NOI18N
761: }
762:
763: private static final char[] hexCharacters = { '0', '1', '2', '3',
764: '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
765:
766: private static char nibbleToHex(int val) {
767: return hexCharacters[val];
768: }
769:
770: private static final String hexString = "0123456789ABCDEF"; // NOI18N
771:
772: private static byte hexToByte(char char1, char char2) {
773: return (byte) ((hexString.indexOf(char1) << 4) + hexString
774: .indexOf(char2));
775: }
776:
777: static String decryptPassword(String password) {
778:
779: if (password == null) {
780: return null;
781: }
782:
783: try {
784: char[] hexChars = password.toCharArray();
785: /*
786: char[] hexChars = new char[password.length()];
787: for (int i = 0; i < hexChars.length; i++) {
788: hexChars[i] = password.charAt(hexChars.length-1-i);
789: }
790: */
791: byte[] encryptedBytes = new byte[hexChars.length / 2];
792: for (int i = 0; i < encryptedBytes.length; i++) {
793: encryptedBytes[i] = hexToByte(hexChars[i * 2],
794: hexChars[i * 2 + 1]);
795: }
796: Cipher cipher = Cipher.getInstance("DES"); // NOI18N
797: cipher.init(Cipher.DECRYPT_MODE, getSecretKey());
798: byte[] passwordBytes = cipher.doFinal(encryptedBytes);
799: return new String(passwordBytes);
800: } catch (Exception e) {
801: e.printStackTrace();
802: return "";
803: }
804: }
805:
806: protected String getSpaces(int level, int tabWidth) {
807:
808: String str = "";
809:
810: for (int i = 0; i < level; i++) {
811: for (int j = 0; j < tabWidth; j++) {
812: str += " ";
813: }
814: }
815:
816: return str;
817: }
818:
819: private void loadDriver() throws SQLException {
820:
821: Log.getLogger().entering(getClass().getName(),
822: toString() + ".loadDriver"); //NOI18N
823: if (driver == null) {
824: try {
825: Class driverClass = Class.forName(driverClassName,
826: true, getDriverClassLoader(getClass()
827: .getClassLoader()));
828: driver = (Driver) driverClass.newInstance();
829: } catch (ClassNotFoundException e) {
830: throw new SQLException(e.getClass().getName() + ": "
831: + e.getLocalizedMessage());//NOI18N
832: } catch (InstantiationException e) {
833: throw new SQLException(e.getClass().getName() + ": "
834: + e.getLocalizedMessage());//NOI18N
835: } catch (IllegalAccessException e) {
836: throw new SQLException(e.getClass().getName() + ": "
837: + e.getLocalizedMessage());//NOI18N
838: }
839: }
840: }
841:
842: private static URLClassLoader getDriverClassLoader(
843: ClassLoader parent) {
844:
845: Log.getLogger().entering("DesignTimeDataSource",
846: "getDriverClassLoader()"); //NOI18N
847: return URLClassLoader.newInstance(urls, parent);
848: }
849:
850: public String toString() {
851: StringBuffer s = new StringBuffer();
852: s.append(getClass().getName());
853: s.append('(');
854: boolean first = true;
855: if (driverClassName != null) {
856: s.append(driverClassName);
857: first = false;
858: }
859: if (url != null) {
860: if (!first) {
861: s.append(',');
862: }
863: s.append(url);
864: first = false;
865: }
866: if (username != null) {
867: if (!first) {
868: s.append(',');
869: }
870: s.append(username);
871: first = false;
872: }
873: if (validationQuery != null) {
874: if (!first) {
875: s.append(',');
876: }
877: s.append(validationQuery);
878: first = false;
879: }
880: s.append(')');
881: return s.toString();
882: }
883:
884: // Methods added for compliance with Java 1.6
885:
886: public boolean isWrapperFor(Class iface) throws SQLException {
887: throw new RuntimeException(rb.getString("NOT_IMPLEMENTED"));
888: }
889:
890: public Object unwrap(Class iface) throws SQLException {
891: throw new RuntimeException(rb.getString("NOT_IMPLEMENTED"));
892: }
893:
894: /*
895: * Make connection if needed
896: */
897: public synchronized void run() {
898: JDBCDriver jdbcDriver = DataSourceResolver.getInstance()
899: .findMatchingDriver(driverClassName);
900: DatabaseConnection conn = DatabaseConnection.create(jdbcDriver,
901: url, username, username.toUpperCase(), password, true);
902: ConnectionManager.getDefault().showConnectionDialog(conn);
903: }
904:
905: public void ensureConnection() {
906: if (task == null) {
907: task = CONNECT_RP.create(this );
908: }
909: task.schedule(10);
910: }
911:
912: }
|