001: /*
002: * ConnectionProperties.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.executequery;
023:
024: import java.io.CharArrayWriter;
025: import java.io.File;
026: import java.io.FileInputStream;
027: import java.io.FileOutputStream;
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.io.OutputStream;
031:
032: import java.util.Enumeration;
033: import java.util.Properties;
034: import java.util.Vector;
035: import javax.xml.parsers.SAXParser;
036: import javax.xml.parsers.SAXParserFactory;
037: import javax.xml.transform.OutputKeys;
038: import javax.xml.transform.Transformer;
039: import javax.xml.transform.TransformerFactory;
040: import javax.xml.transform.sax.SAXSource;
041: import javax.xml.transform.stream.StreamResult;
042:
043: import org.xml.sax.Attributes;
044: import org.xml.sax.ContentHandler;
045: import org.xml.sax.DTDHandler;
046: import org.xml.sax.EntityResolver;
047: import org.xml.sax.ErrorHandler;
048: import org.xml.sax.InputSource;
049: import org.xml.sax.SAXException;
050: import org.xml.sax.SAXParseException;
051: import org.xml.sax.XMLReader;
052: import org.xml.sax.helpers.AttributesImpl;
053: import org.xml.sax.helpers.DefaultHandler;
054: import org.executequery.databasemediators.DatabaseDriver;
055: import org.executequery.databasemediators.DatabaseConnection;
056: import org.underworldlabs.util.FileUtils;
057: import org.underworldlabs.util.MiscUtils;
058:
059: /* ----------------------------------------------------------
060: * CVS NOTE: Changes to the CVS repository prior to the
061: * release of version 3.0.0beta1 has meant a
062: * resetting of CVS revision numbers.
063: * ----------------------------------------------------------
064: */
065:
066: /**
067: *
068: * @author Takis Diakoumis
069: * @version $Revision: 1.5 $
070: * @date $Date: 2006/06/28 08:35:55 $
071: */
072: public class ConnectionProperties {
073:
074: // -------------------------------------------
075: // XML tag names and attributes
076:
077: private static final String SAVED_CONNECTIONS = "savedconnections";
078: private static final String CONNECTION = "connection";
079: private static final String NAME = "name";
080: private static final String USER = "user";
081: private static final String PASSWORD = "password";
082: private static final String ENCRYPTED = "encrypted";
083: private static final String DRIVER_ID = "driverid";
084: private static final String HOST = "host";
085: private static final String DATA_SOURCE = "datasource";
086: private static final String TX_ISOLATION = "txisolation";
087: private static final String AUTO_COMMIT = "autocommit";
088: private static final String PORT = "port";
089: private static final String URL = "url";
090: private static final String DRIVER_NAME = "drivername";
091: private static final String ADVANCED = "advanced";
092: private static final String PROPERTY = "property";
093: private static final String KEY = "key";
094: private static final String VALUE = "value";
095: private static final String STORE_PASSWORD = "storepassword";
096:
097: private static final String CDDATA = "CDATA";
098:
099: // -------------------------------------------
100:
101: /** the database connections collection */
102: private static Vector<DatabaseConnection> connections;
103:
104: /** private constructor */
105: private ConnectionProperties() {
106: }
107:
108: public static String[] getConnectionNames() {
109: String[] names = new String[connections.size()];
110: for (int i = 0; i < names.length; i++) {
111: names[i] = connections.get(i).toString();
112: }
113: return names;
114: }
115:
116: /**
117: * Returns whether the name specified exists within the saved
118: * connections. the connection object specified allows for it
119: * to be removed from consideration (checking against itself).
120: *
121: * @param the connection to exclude
122: * @param the name to validated
123: */
124: public static boolean nameExists(DatabaseConnection dc, String name) {
125: if (name == null) {
126: name = dc.getName();
127: }
128: for (int i = 0, k = connections.size(); i < k; i++) {
129: DatabaseConnection _dc = connections.elementAt(i);
130: String _name = _dc.getName();
131: if (_dc != dc && _name.equalsIgnoreCase(name)) {
132: return true;
133: }
134: }
135: return false;
136: }
137:
138: /**
139: * Returns the stored connections collection.
140: *
141: * @return the connections within a Vector object
142: */
143: public static Vector<DatabaseConnection> getConnectionsVector() {
144: return connections;
145: }
146:
147: /**
148: * Returns the connection properties object with the specified name.
149: *
150: * @param the name of the connection sought
151: * @return the connection properties object
152: */
153: public static DatabaseConnection getDatabaseConnection(String name) {
154: for (int i = 0, k = connections.size(); i < k; i++) {
155: DatabaseConnection dc = connections.elementAt(i);
156: if (dc.getName().equalsIgnoreCase(name)) {
157: return dc;
158: }
159: }
160: return null;
161: }
162:
163: /**
164: * Returns the stored connections as an array.
165: *
166: * @return the connections as an array
167: */
168: public static DatabaseConnection[] getConnectionsArray() {
169: DatabaseConnection[] dca = new DatabaseConnection[connections
170: .size()];
171: for (int i = 0; i < connections.size(); i++) {
172: dca[i] = connections.elementAt(i);
173: }
174: return dca;
175: }
176:
177: /**
178: * Saves the connections to file.
179: *
180: * @return 1 if saved ok, 0 otherwise
181: */
182: public static synchronized int saveConnections()
183: throws ValidationException {
184: // validate the names are unique
185: for (int i = 0, k = connections.size(); i < k; i++) {
186: DatabaseConnection dc = connections.get(i);
187: for (int j = 0; j < k; j++) {
188: DatabaseConnection _dc = connections.get(j);
189: if (nameExists(dc, null)) {
190: throw new ValidationException(
191: "The connection name " + dc.getName()
192: + " already exists.");
193: }
194: }
195: }
196:
197: OutputStream os = null;
198: try {
199:
200: // ---------------------------------------
201: // ----- Save the connections to file ----
202: // ---------------------------------------
203:
204: TransformerFactory transFactory = TransformerFactory
205: .newInstance();
206: Transformer transformer = transFactory.newTransformer();
207: ConnectionParser cp = new ConnectionParser();
208:
209: File connXML = new File(SystemUtilities
210: .getUserPropertiesPath()
211: + "savedconnections.xml");
212:
213: os = new FileOutputStream(connXML);
214: DatabaseConnection[] dca = getConnectionsArray();
215: SAXSource source = new SAXSource(cp,
216: new ConnectionInputSource(dca));
217: StreamResult r = new StreamResult(os);
218:
219: transformer.setOutputProperty(OutputKeys.INDENT, "yes");
220: transformer.transform(source, r);
221:
222: return 1;
223: } catch (Exception e) {
224: e.printStackTrace();
225: return 0;
226: } finally {
227: try {
228: if (os != null) {
229: os.close();
230: }
231: } catch (IOException e) {
232: }
233: }
234: }
235:
236: /**
237: * Loads the connections from file and stores them within
238: * collection - a Vector object.
239: */
240: public static synchronized void loadConnections() {
241: String confPath = SystemUtilities.getUserPropertiesPath();
242: String from = "org/executequery/savedconnections-default.xml";
243: String to = confPath + "savedconnections.xml";
244:
245: File file = new File(to);
246: if (file.exists()) {
247: InputStream in = null;
248: try {
249: SAXParserFactory factory = SAXParserFactory
250: .newInstance();
251: factory.setNamespaceAware(true);
252:
253: SAXParser parser = factory.newSAXParser();
254: XMLConnectionHandler handler = new XMLConnectionHandler();
255:
256: in = new FileInputStream(file);
257: parser.parse(in, handler);
258: } catch (Exception e) {
259: e.printStackTrace();
260:
261: StringBuffer sb = new StringBuffer(
262: "Error opening connection definitions.\n");
263: sb
264: .append(
265: "The file savedconnections.xml is damaged and will be\nrenamed to ")
266: .append(
267: "savedconnections.xml.old. A new empty file\nwill be created in ")
268: .append("its place.");
269: GUIUtilities.displayErrorMessage(sb.toString());
270:
271: if (file != null && file.exists()) {
272: file.renameTo(new File(confPath
273: + "savedconnections.xml.old"));
274: }
275:
276: recreateDefinitionsFile(from, to);
277: connections = new Vector<DatabaseConnection>();
278: } finally {
279: if (in != null) {
280: try {
281: in.close();
282: } catch (IOException e) {
283: }
284: }
285: }
286:
287: } else {
288: recreateDefinitionsFile(from, to);
289: connections = new Vector<DatabaseConnection>();
290: }
291:
292: // check that the driver names have been removed for IDs
293: for (int i = 0, n = connections.size(); i < n; i++) {
294: DatabaseConnection dc = connections.get(i);
295: if (dc.getDriverId() == 0) {
296: DatabaseDriver driver = JDBCProperties
297: .getDatabaseDriver(dc.getDriverName());
298: if (driver != null) {
299: dc.setDriverId(driver.getId());
300: }
301: }
302: }
303:
304: SystemUtilities.setSavedConnections(getConnectionsArray());
305:
306: }
307:
308: private static void recreateDefinitionsFile(String from, String to) {
309: try {
310: FileUtils.copyResource(from, to);
311: } catch (IOException ioExc) {
312: GUIUtilities
313: .displayErrorMessage("An error occurred recreating the connections definitions.");
314: }
315: }
316:
317: static class XMLConnectionHandler extends DefaultHandler {
318:
319: private CharArrayWriter contents;
320: private DatabaseConnection dc;
321: private Properties advancedProps;
322:
323: public XMLConnectionHandler() {
324: if (connections == null) {
325: connections = new Vector<DatabaseConnection>();
326: }
327: contents = new CharArrayWriter();
328: }
329:
330: public void startElement(String nameSpaceURI, String localName,
331: String qName, Attributes attrs) {
332: contents.reset();
333:
334: if (localName.equals(CONNECTION)) {
335: dc = new DatabaseConnection();
336: String value = attrs.getValue(STORE_PASSWORD);
337: if (!MiscUtils.isNull(value)) {
338: dc.setPasswordStored(Boolean.valueOf(value)
339: .booleanValue());
340: }
341: } else if (localName.equals(PASSWORD)) {
342: String value = attrs.getValue(ENCRYPTED);
343: if (!MiscUtils.isNull(value)) {
344: dc.setPasswordEncrypted(Boolean.valueOf(value)
345: .booleanValue());
346: }
347: } else if (localName.equals(PROPERTY)) {
348: if (advancedProps == null) {
349: advancedProps = new Properties();
350: }
351: advancedProps.setProperty(attrs.getValue(KEY), attrs
352: .getValue(VALUE));
353: }
354:
355: }
356:
357: public void endElement(String nameSpaceURI, String localName,
358: String qName) {
359:
360: if (localName.equals(NAME)) {
361: dc.setName(contents.toString());
362: } else if (localName.equals(USER)) {
363: dc.setUserName(contents.toString());
364: } else if (localName.equals(PASSWORD)) {
365: String value = contents.toString();
366: if (!MiscUtils.isNull(value)) {
367: if (dc.isPasswordEncrypted()) {
368: dc.setEncryptedPassword(value);
369: } else {
370: dc.setPassword(value);
371: }
372: dc.setPasswordStored(true);
373: } else {
374: dc.setPasswordStored(false);
375: }
376: } else if (localName.equals(HOST)) {
377: dc.setHost(contents.toString());
378: } else if (localName.equals(DATA_SOURCE)) {
379: dc.setSourceName(contents.toString());
380: } else if (localName.equals(PORT)) {
381: dc.setPort(contents.toString());
382: } else if (localName.equals(URL)) {
383: dc.setURL(contents.toString());
384: } else if (localName.equals(DRIVER_ID)) {
385: dc.setDriverId(Long.parseLong(contents.toString()));
386: } else if (localName.equals(DRIVER_NAME)) {
387: dc.setDriverName(contents.toString());
388: } else if (localName.equals(AUTO_COMMIT)) {
389: String value = contents.toString();
390: if (!MiscUtils.isNull(value)) {
391: dc.setAutoCommit(Boolean.valueOf(value));
392: }
393: } else if (localName.equals(TX_ISOLATION)) {
394: String value = contents.toString();
395: if (!MiscUtils.isNull(value)) {
396: dc.setTransactionIsolation(new Integer(value));
397: } else {
398: dc.setTransactionIsolation(-1);
399: }
400: } else if (localName.equals(ADVANCED)) {
401: if (advancedProps != null && advancedProps.size() > 0) {
402: dc.setJdbcProperties(advancedProps);
403: }
404: } else if (localName.equals(CONNECTION)) {
405: connections.add(dc);
406: advancedProps = null;
407: dc = null;
408: }
409:
410: }
411:
412: public void characters(char[] data, int start, int length) {
413: contents.write(data, start, length);
414: }
415:
416: public void ignorableWhitespace(char[] data, int start,
417: int length) {
418: characters(data, start, length);
419: }
420:
421: public void error(SAXParseException spe) throws SAXException {
422: throw new SAXException(spe.getMessage());
423: }
424: } // XMLHandler
425:
426: static class ConnectionInputSource extends InputSource {
427: private DatabaseConnection[] dca;
428:
429: public ConnectionInputSource(DatabaseConnection[] dc) {
430: dca = dc;
431: }
432:
433: public DatabaseConnection[] getConnections() {
434: return dca;
435: }
436:
437: } // class ConnectionInputSource
438:
439: static class ConnectionParser implements XMLReader {
440: private String nsu = Constants.EMPTY;
441: private AttributesImpl atts = new AttributesImpl();
442:
443: private ContentHandler handler;
444:
445: private static char[] newLine = { '\n' };
446: private static String indent_1 = "\n ";
447: private static String indent_2 = "\n ";
448: private static String indent_3 = "\n ";
449:
450: public ConnectionParser() {
451: }
452:
453: public void parse(InputSource input) throws SAXException,
454: IOException {
455: if (!(input instanceof ConnectionInputSource)) {
456: throw new SAXException(
457: "Parser can only accept a ConnectionInputSource");
458: }
459:
460: parse((ConnectionInputSource) input);
461: }
462:
463: public void parse(ConnectionInputSource input)
464: throws IOException, SAXException {
465: try {
466: if (handler == null) {
467: throw new SAXException("No content handler");
468: }
469:
470: DatabaseConnection[] conns = input.getConnections();
471:
472: handler.startDocument();
473: handler.startElement(nsu, SAVED_CONNECTIONS,
474: SAVED_CONNECTIONS, atts);
475: handler.ignorableWhitespace(newLine, 0, 1);
476:
477: String marker = null;
478: Properties advProps = null;
479:
480: for (int i = 0; i < conns.length; i++) {
481: DatabaseConnection conn = conns[i];
482: handler.ignorableWhitespace(indent_1.toCharArray(),
483: 0, indent_1.length());
484:
485: atts.addAttribute(nsu, STORE_PASSWORD,
486: STORE_PASSWORD, CDDATA, Boolean
487: .toString(conns[i]
488: .isPasswordStored()));
489:
490: handler.startElement(nsu, CONNECTION, CONNECTION,
491: atts);
492: atts.removeAttribute(atts.getIndex(STORE_PASSWORD));
493:
494: writeXML(NAME, conn.getName(), indent_2);
495: writeXML(USER, conn.getUserName(), indent_2);
496:
497: atts.addAttribute(nsu, ENCRYPTED, ENCRYPTED,
498: CDDATA, Boolean.toString(conn
499: .isPasswordEncrypted()));
500:
501: if (conn.isPasswordStored()) {
502: writeXML(PASSWORD, conn.getPassword(), indent_2);
503: } else {
504: writeXML(PASSWORD, Constants.EMPTY, indent_2);
505: }
506: atts.removeAttribute(atts.getIndex(ENCRYPTED));
507:
508: writeXML(HOST, conn.getHost(), indent_2);
509: writeXML(DATA_SOURCE, conn.getSourceName(),
510: indent_2);
511: writeXML(PORT, conn.getPort(), indent_2);
512: writeXML(URL, conn.getURL(), indent_2);
513: // TODO: remove driver name from save
514: writeXML(DRIVER_NAME, conn.getDriverName(),
515: indent_2);
516:
517: writeXML(DRIVER_ID, Long.toString(conn
518: .getDriverId()), indent_2);
519:
520: writeXML(AUTO_COMMIT, Boolean.toString(conn
521: .isAutoCommit()), indent_2);
522: writeXML(TX_ISOLATION, Integer.toString(conn
523: .getTransactionIsolation()), indent_2);
524:
525: if (conn.hasAdvancedProperties()) {
526: handler.ignorableWhitespace(indent_2
527: .toCharArray(), 0, indent_2.length());
528: handler.startElement(nsu, ADVANCED, ADVANCED,
529: atts);
530:
531: advProps = conn.getJdbcProperties();
532:
533: for (Enumeration j = advProps.propertyNames(); j
534: .hasMoreElements();) {
535: marker = (String) j.nextElement();
536: atts.addAttribute(Constants.EMPTY, KEY,
537: KEY, CDDATA, marker);
538: atts.addAttribute(Constants.EMPTY, VALUE,
539: VALUE, CDDATA, advProps
540: .getProperty(marker));
541: writeXML(PROPERTY, null, indent_3);
542: atts.removeAttribute(atts.getIndex(KEY));
543: atts.removeAttribute(atts.getIndex(VALUE));
544: }
545:
546: handler.ignorableWhitespace(indent_2
547: .toCharArray(), 0, indent_2.length());
548: handler.endElement(nsu, ADVANCED, ADVANCED);
549: } else {
550: writeXML(ADVANCED, null, indent_2);
551: }
552:
553: handler.ignorableWhitespace(indent_1.toCharArray(),
554: 0, indent_1.length());
555: handler.endElement(nsu, CONNECTION, CONNECTION);
556: handler.ignorableWhitespace(newLine, 0, 1);
557:
558: //conn.setNewConnection(false);
559: marker = null;
560: }
561:
562: handler.ignorableWhitespace(newLine, 0, 1);
563: handler.endElement(nsu, SAVED_CONNECTIONS,
564: SAVED_CONNECTIONS);
565: handler.endDocument();
566:
567: } catch (Exception e) {
568: e.printStackTrace();
569: }
570: }
571:
572: private void writeXML(String name, String line, String space)
573: throws SAXException {
574: if (line == null) {
575: line = Constants.EMPTY;
576: }
577:
578: int textLength = line.length();
579: handler.ignorableWhitespace(space.toCharArray(), 0, space
580: .length());
581: handler.startElement(nsu, name, name, atts);
582: handler.characters(line.toCharArray(), 0, textLength);
583: handler.endElement(nsu, name, name);
584: }
585:
586: public void setContentHandler(ContentHandler handler) {
587: this .handler = handler;
588: }
589:
590: public ContentHandler getContentHandler() {
591: return this .handler;
592: }
593:
594: public void setErrorHandler(ErrorHandler handler) {
595: }
596:
597: public ErrorHandler getErrorHandler() {
598: return null;
599: }
600:
601: public void parse(String systemId) throws IOException,
602: SAXException {
603: }
604:
605: public DTDHandler getDTDHandler() {
606: return null;
607: }
608:
609: public EntityResolver getEntityResolver() {
610: return null;
611: }
612:
613: public void setEntityResolver(EntityResolver resolver) {
614: }
615:
616: public void setDTDHandler(DTDHandler handler) {
617: }
618:
619: public Object getProperty(String name) {
620: return null;
621: }
622:
623: public void setProperty(String name, java.lang.Object value) {
624: }
625:
626: public void setFeature(String name, boolean value) {
627: }
628:
629: public boolean getFeature(String name) {
630: return false;
631: }
632: } // class ConnectionParser
633:
634: }
|