KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > tools > XmlLoad


1 package com.quadcap.sql.tools;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.BufferedInputStream JavaDoc;
42 import java.io.BufferedReader JavaDoc;
43 import java.io.FileInputStream JavaDoc;
44 import java.io.FileReader JavaDoc;
45 import java.io.InputStream JavaDoc;
46 import java.io.InputStreamReader JavaDoc;
47 import java.io.IOException JavaDoc;
48 import java.io.OutputStream JavaDoc;
49 import java.io.PrintWriter JavaDoc;
50 import java.io.Reader JavaDoc;
51
52 import java.math.BigDecimal JavaDoc;
53
54 //-//#ifdef JDK11
55
//-import com.quadcap.jdbc.Connection;
56
//-import com.quadcap.jdbc.DatabaseMetaData;
57
//-import com.quadcap.jdbc.ResultSet;
58
//-import com.quadcap.jdbc.ResultSetMetaData;
59
//-import com.quadcap.jdbc.Statement;
60
//-import com.quadcap.sql.types.Type;
61
//#else
62
import java.sql.Connection JavaDoc;
63 import java.sql.DatabaseMetaData JavaDoc;
64 import java.sql.ResultSet JavaDoc;
65 import java.sql.ResultSetMetaData JavaDoc;
66 import java.sql.Statement JavaDoc;
67 //#endif
68

69 import java.sql.SQLException JavaDoc;
70 import java.sql.Types JavaDoc;
71
72 import java.util.zip.GZIPInputStream JavaDoc;
73
74 import org.xml.sax.AttributeList JavaDoc;
75 import org.xml.sax.DocumentHandler JavaDoc;
76 import org.xml.sax.ErrorHandler JavaDoc;
77 import org.xml.sax.InputSource JavaDoc;
78 import org.xml.sax.Parser JavaDoc;
79 import org.xml.sax.Locator JavaDoc;
80 import org.xml.sax.SAXException JavaDoc;
81 import org.xml.sax.SAXParseException JavaDoc;
82
83 import org.xml.sax.helpers.ParserFactory JavaDoc;
84
85 /**
86  * This class implements the reverse functionality of XmlDump -- it loads
87  * a database with the data contained in the specified XML file.
88  *
89  * @author Stan Bailes
90  */

91 public class XmlLoad implements DocumentHandler JavaDoc, ErrorHandler JavaDoc {
92     Connection JavaDoc conn;
93     ResultSet JavaDoc rs;
94     ResultSetMetaData JavaDoc rm;
95     Statement JavaDoc stmt;
96     String JavaDoc tableName = "";
97     String JavaDoc columnName = "";
98     StringBuffer JavaDoc data = new StringBuffer JavaDoc();
99
100     static final int XML = 0;
101     static final int DATABASE = 1;
102     static final int DDL = 2;
103     static final int DML = 3;
104     static final int TABLE = 4;
105     static final int COLUMN = 5;
106
107     int state = XML;
108
109     Parser JavaDoc parser;
110     Locator JavaDoc locator;
111
112     /**
113      * No-argument constructor. The new object needs a database connection
114      * before it can do anything useful.
115      *
116      * @exception Exception may be thrown if there's a problem constructing
117      * the XML parser.
118      */

119     public XmlLoad() throws Exception JavaDoc {
120     parser = ParserFactory.makeParser("com.quadcap.text.sax.Parser");
121     parser.setDocumentHandler(this);
122     parser.setErrorHandler(this);
123     }
124
125     /**
126      * Construct a new <code>XmlLoad</code> object bound to the specified
127      * connection
128      *
129      * @param conn the database connection
130      *
131      * @exception Exception may be thrown if there's a problem constructing
132      * the XML parser.
133      */

134     public XmlLoad(Connection JavaDoc conn) throws Exception JavaDoc {
135     this();
136     setConnection(conn);
137     }
138
139     /**
140      * Set the loader's database connection
141      *
142      * @param conn the new database connection
143      * @exception SQLException may be thrown
144      */

145     public void setConnection(Connection JavaDoc conn) throws SQLException JavaDoc {
146     if (stmt != null) {
147         if (rs != null) {
148         rs.close();
149         }
150         stmt.close();
151     }
152     this.conn = conn;
153 //-//#ifdef JDK11
154
//- this.stmt = (Statement)conn.createStatement();
155
//#else
156
this.stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
157                      ResultSet.CONCUR_UPDATABLE);
158 //#endif
159
}
160
161     /**
162      * Get the loader's database connection
163      *
164      * @return the current database connection
165      */

166     public Connection JavaDoc getConnection() {
167     return conn;
168     }
169
170     /**
171      * Load the XML document from the specified input stream, importing the
172      * data contained therein into the database referenced by the current
173      * connection. The input document should be a well-formed XML
174      * <code>&lt;database&gt;</code> document.
175      *
176      * @param is the input stream containing the XML document.
177      *
178      * @exception Exception may be thrown if there's a parse error or
179      * a database error.
180      */

181     public void load(InputStream JavaDoc is) throws Exception JavaDoc {
182     parser.parse(new InputSource JavaDoc(is));
183     }
184
185     /**
186      * Load the XML document from the specified reader, importing the
187      * data contained therein into the database referenced by the current
188      * connection. The input document should be a well-formed XML
189      * <code>&lt;database&gt;</code> document.
190      *
191      * @param r the input reader containing the XML document.
192      *
193      * @exception Exception may be thrown if there's a parse error or
194      * a database error.
195      */

196     public void load(Reader JavaDoc r) throws Exception JavaDoc {
197     parser.parse(new InputSource JavaDoc(r));
198     }
199
200     /**
201      * SAX parser callback to handle XML Parser errors.
202      * This implementation just prints them
203      * to System.err.
204      *
205      * @param exception the exception generated by the parser.
206      */

207     public void error(SAXParseException JavaDoc exception) {
208     System.err.println("error");
209     exception.printStackTrace(System.err);
210     }
211
212     /**
213      * SAX parser callback to handle XML Parser fatal errors.
214      * This implementation just prints them
215      * to System.err.
216      *
217      * @param exception the exception generated by the parser.
218      */

219     public void fatalError(SAXParseException JavaDoc exception) {
220     System.err.println("fatal error");
221     exception.printStackTrace(System.err);
222     }
223
224     /**
225      * SAX parser callback to handle XML Parser fatal errors.
226      * This implementation just prints them
227      * to System.err.
228      *
229      * @param exception the exception generated by the parser.
230      */

231     public void warning(SAXParseException JavaDoc exception) {
232     System.err.println("warning");
233     exception.printStackTrace(System.err);
234     }
235
236     /**
237      * SAX parser callback to handle character data found in the
238      * parsed document.
239      *
240      * @param ch the buffer containing the parsed characters.
241      * @param star the buffer position of the first character
242      * @param length the number of characters
243      *
244      * @exception SAXException may be thrown if this data represents
245      * a database value and there's a SQL exception thrown while
246      * trying to update the underlying resultset object with this
247      * data.
248      */

249     public void characters(char[] ch, int start, int length)
250     throws SAXException JavaDoc
251     {
252     data.append(ch, start, length);
253     }
254
255     /**
256      * SAX parser callback function that is called when the end of the
257      * document is reached. This implementation does nothing.
258      */

259     public void endDocument() {
260     }
261
262     /**
263      * SAX parser callback function called for the end of an element.
264      * If this element
265      * represents the <code>&lt;database&gt;</code> element, we finish up
266      * by closing the active statement. If this element represents a table
267      * row element, we insert the current row. Otherwise, we do nothing.
268      *
269      * @param name the name of this element
270      * @exception SAXException may be thrown to wrap any underlying database
271      * exception.
272      */

273     public void endElement(String JavaDoc name) throws SAXException JavaDoc {
274     try {
275         switch (state) {
276         case DATABASE:
277         // all done
278
if (rs != null) {
279                     rs.close();
280                     rs = null;
281                 }
282                 if (stmt != null) {
283                     stmt.close();
284                     stmt = null;
285                 }
286         state = XML;
287         break;
288         case TABLE:
289         // done with this row
290
try {
291                     rs.insertRow();
292                 } catch (Throwable JavaDoc ex) {
293                     System.err.println(locator.getSystemId() + ":" +
294                                        locator.getLineNumber() + ":" +
295                                        locator.getColumnNumber() + ": " +
296                                        ex.toString());
297                 }
298         state = DML;
299         break;
300         case DDL:
301                 try {
302                     stmt.execute(data.toString());
303                 } catch (Throwable JavaDoc ex) {
304                     System.err.println(locator.getSystemId() + ":" +
305                                        locator.getLineNumber() + ":" +
306                                        locator.getColumnNumber() + ": " +
307                                        ex.toString());
308                 }
309         state = DATABASE;
310                 break;
311         case DML:
312         state = DATABASE;
313         break;
314         case COLUMN:
315         int type = rm.getColumnType(rs.findColumn(columnName));
316         rs.updateObject(columnName,
317                 makeObject(type, data.toString()));
318         state = TABLE;
319         break;
320         default:
321         throw makeException("endElement: bad state: " + state);
322         }
323     } catch (Throwable JavaDoc e) {
324             System.err.println(locator.getSystemId() + ":" +
325                                locator.getLineNumber() + ":" +
326                                locator.getColumnNumber() + ": " +
327                                e.toString());
328             System.err.println("[" + data + "]");
329         printException(e);
330         throw makeException(e.toString());
331     }
332     }
333
334     public SAXException JavaDoc makeException(String JavaDoc s) {
335         return new SAXException JavaDoc(locator.getSystemId() + ":" +
336                                 locator.getLineNumber() + ":" +
337                                 locator.getColumnNumber() + ": " + s);
338     }
339     
340     /**
341      * SAX parser callback for ignorable whitespace. We just ignore it
342      *
343      * @param ch the buffer containing the parsed characters.
344      * @param star the buffer position of the first character
345      * @param length the number of characters
346      */

347     public void ignorableWhitespace(char[] ch, int start, int length) {
348     }
349
350     /**
351      * SAX parser callback for processing instructions. This implementation
352      * does nothing.
353      *
354      * @param target the processing instruction target.
355      * @param data the processing instruction data.
356      */

357     public void processingInstruction(String JavaDoc target, String JavaDoc data) {
358     }
359
360     /**
361      * SAX parser callback used to receive a document locator.
362      *
363      * @param locator the parser's locator object.
364      */

365     public void setDocumentLocator(Locator JavaDoc locator) {
366     this.locator = locator;
367     }
368
369     /**
370      * SAX parser callback for document start.
371      * This implementation does nothing.
372      */

373     public void startDocument() {
374     }
375
376     /**
377      * SAX parser callback for the start of an element. If this element
378      * represents a table row, and the table is different from the last
379      * table seen, we establish an updatable <code>ResultSet</code> for the
380      * new table which can be used to insert new rows into the table.
381      * If this element represents a table row, we move to the insert row.
382      * If this element represents a column, we remember the column name.
383      *
384      * @param name the element name
385      * @param attrs the element's attributes
386      *
387      * @exception SAXException may be thrown to wrap an underlying database
388      * error, or if there is a problem with the XML document itself.
389      */

390     public void startElement(String JavaDoc name, AttributeList JavaDoc attrs)
391     throws SAXException JavaDoc
392     {
393     data.setLength(0);
394     try {
395         switch (state) {
396         case XML:
397         if (!name.equals("database")) {
398             throw makeException("Outer tag must be 'database'");
399         }
400         state = DATABASE;
401         break;
402         case DATABASE:
403         if (name.equals("ddl")) {
404             state = DDL;
405         } else if (name.equals("dml")) {
406             state = DML;
407         } else {
408             throw makeException("Bad tag: " + name +
409                        ", expected 'ddl' or 'dml'");
410         }
411         break;
412         case DDL:
413         throw makeException("Nested elements (" + name +
414                                     ") not allowed in 'ddl' element");
415         case DML:
416         if (!tableName.equals(name)) {
417             if (rs != null) rs.close();
418             rs = (ResultSet JavaDoc)stmt.executeQuery("select * from " + name +
419                        " for update");
420             rm = (ResultSetMetaData JavaDoc)rs.getMetaData();
421         }
422         rs.moveToInsertRow();
423         tableName = name;
424         state = TABLE;
425         break;
426         case TABLE:
427         columnName = name;
428         state = COLUMN;
429         break;
430         case COLUMN:
431         throw makeException("Nested elements not allowed in column element");
432         default:
433         throw makeException("bad state: " + state);
434         }
435     } catch (SQLException JavaDoc e) {
436         printException(e);
437         throw makeException(e.toString());
438     }
439     }
440
441     static byte[] hexMap = new byte[256];
442     static {
443     for (int i = 0; i < XmlDump.hexBytes.length; i++) {
444         hexMap[XmlDump.hexBytes[i]] = (byte)i;
445     }
446     }
447
448     byte[] makeBytes(String JavaDoc val) {
449     byte[] buf = new byte[val.length() / 2];
450     int pos = 0;
451     for (int i = 0; i < buf.length; i++) {
452         buf[i] = (byte)(hexMap[val.charAt(pos++)] << 4);
453         buf[i] += hexMap[val.charAt(pos++)];
454     }
455     return buf;
456     }
457         
458
459     Object JavaDoc makeObject(int jdbcType, String JavaDoc val)
460     throws SAXException JavaDoc
461     {
462     switch (jdbcType) {
463     case Types.BIT:
464         return new Boolean JavaDoc(val);
465     case Types.TINYINT:
466         return new Byte JavaDoc(val);
467     case Types.SMALLINT:
468         return new Short JavaDoc(val);
469     case Types.INTEGER:
470         return new Integer JavaDoc(val);
471     case Types.BIGINT:
472         return new Long JavaDoc(val);
473     case Types.FLOAT:
474     case Types.REAL:
475     case Types.DOUBLE:
476         return new Double JavaDoc(val);
477     case Types.NUMERIC:
478     case Types.DECIMAL:
479         return new BigDecimal JavaDoc(val);
480     case Types.CHAR:
481     case Types.VARCHAR:
482     case Types.LONGVARCHAR:
483         case Types.OTHER:
484 //-//#ifdef JDK11
485
//- case Type.CLOB:
486
//#else
487
case Types.CLOB:
488 //#endif
489
return val;
490     case Types.DATE:
491     case Types.TIME:
492     case Types.TIMESTAMP:
493         return val;
494     case Types.BINARY:
495     case Types.VARBINARY:
496     case Types.LONGVARBINARY:
497 //-//#ifdef JDK11
498
//- case Type.BLOB:
499
//#else
500
case Types.BLOB:
501 //#endif
502
return makeBytes(val);
503     case Types.NULL:
504         return null;
505 //#ifndef JDK11
506
case Types.JAVA_OBJECT:
507     case Types.DISTINCT:
508     case Types.STRUCT:
509     case Types.ARRAY:
510     case Types.REF:
511 //#endif
512
default:
513         throw makeException("not implemented, jdbc type: " + jdbcType);
514     }
515     }
516
517     final static void printException(Throwable JavaDoc t) {
518         if (t != null) {
519             //t.printStackTrace(System.err);
520
com.quadcap.util.Debug.print(t);
521             if (t instanceof SAXException JavaDoc) {
522                 printException(((SAXException JavaDoc)t).getException());
523             }
524         }
525     }
526
527     /**
528      * A main program which supports the command-line invocation of either
529      * the Loader or XmlLoad functions. This function accepts
530      * one or more file names as arguments. </p>
531      *
532      * <p>For each file name that ends with the <code>".sql"</code> extension,
533      * the Loader.loadFile() method is invoked
534      * to execute the SQL commands in the file.</p>
535      *
536      * <p>For each file name that ends with the <code>".xml"</code>
537      * or <code>".xml.gz"</code> extension, the
538      * XmlLoad.load() method is invoked to
539      * load the XML data from that file into the database.
540      *
541      * @param args
542      * <i>database-name</i> <i>file</i> ...
543      */

544     public static void main(String JavaDoc[] args) {
545     try {
546         Connection JavaDoc xconn = XmlDump.makeConnection();
547             try {
548                 for (int i = 0; i < args.length; i++) {
549                     String JavaDoc f = args[i];
550                     if (f.endsWith(".sql")) {
551                         Loader load = new Loader(xconn);
552                         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(System.out);
553                         load.setWriter(pw);
554                         load.loadFile(f);
555                         pw.flush();
556                     } else if (f.endsWith(".xml")) {
557                         XmlLoad load = new XmlLoad(xconn);
558                         FileReader JavaDoc fr = new FileReader JavaDoc(f);
559                         BufferedReader JavaDoc br = new BufferedReader JavaDoc(fr);
560                         load.load(br);
561                         br.close();
562                     } else if (f.endsWith(".xml.gz")) {
563                         XmlLoad load = new XmlLoad(xconn);
564                         FileInputStream JavaDoc fis = new FileInputStream JavaDoc(f);
565                         BufferedInputStream JavaDoc bis = new BufferedInputStream JavaDoc(fis);
566                         GZIPInputStream JavaDoc gis = new GZIPInputStream JavaDoc(bis);
567                         InputStreamReader JavaDoc ir = new InputStreamReader JavaDoc(gis);
568                         load.load(ir);
569                         ir.close();
570                     }
571                 }
572             } finally {
573                 xconn.close();
574             }
575     } catch (Exception JavaDoc e) {
576         printException(e);
577     }
578     }
579 }
580
Popular Tags