KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > webdocwf > util > xml > XmlWriter


1 /*
2     Copyright (C) 2003 Together
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Lesser General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     Lesser General Public License for more details.
13
14     You should have received a copy of the GNU Lesser General Public
15     License along with this library; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */

18
19 package org.webdocwf.util.xml;
20
21 //xml imports
22
import org.w3c.dom.Document JavaDoc;
23 import org.w3c.dom.NodeList JavaDoc;
24 import org.w3c.dom.Node JavaDoc;
25 import org.w3c.dom.Element JavaDoc;
26 import org.enhydra.xml.SearchElement;
27 import org.enhydra.xml.XMLDocumentFactory;
28 import javax.xml.parsers.DocumentBuilder JavaDoc;
29 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
30
31 import java.sql.*;
32 import java.io.File JavaDoc;
33 import java.util.Properties JavaDoc;
34 import java.io.RandomAccessFile JavaDoc;
35 import java.util.ArrayList JavaDoc;
36
37 /**
38  * Load existing XML file , creating DOM from file or creating
39  * new DOM.Class has methods for insert,update,delete data from XML file and save new DOM in XML file.
40  *
41  * @author Zoran Milakovic
42 */

43
44 public class XmlWriter {
45
46   /**
47    * Document made from XML file, and in which will
48    * be made changes.Document will be saved in XML file.
49    */

50   public static SearchElement searchDocumentStatic;
51   private SearchElement searchDocument;
52   private Document JavaDoc document;
53   private static boolean isError = false;
54   /**
55    * If parameter is true document will be saved in xml file after each query,other wise
56    * document will be saved when Connection.commit() method is called.
57    */

58   private boolean autoCommit = false;
59   /**
60    * Full path of the XML file.
61    */

62   private String JavaDoc fileName;
63
64   /**
65    * Constructor used when autoCommit is set to false or true.
66    * @param fileName name of xml file.
67    * @param isAutoCommit define is mod auto commit or not.
68    */

69   public XmlWriter(String JavaDoc fileName, boolean isAutoCommit) throws SQLException {
70     try {
71       XmlWriter.isError = false;
72       this.autoCommit = isAutoCommit;
73       DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
74       DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
75 //check if database exist, and if not, create one
76
this.fileName = fileName;
77       File JavaDoc file = new File JavaDoc( fileName );
78       if( !file.exists() ) {
79         file.getParentFile().mkdirs();
80         this.document = builder.newDocument();
81         Element JavaDoc newDatabaseElement = document.createElement("database");
82         newDatabaseElement.appendChild( document.createElement("dml") );
83         document.insertBefore( newDatabaseElement , null );
84         this.searchDocument = (SearchElement)SearchElement.newInstance( document );
85         this.createDatabase();
86       }
87
88       if( isAutoCommit ) {
89         this.document = builder.parse( file );
90         this.searchDocument = (SearchElement)SearchElement.newInstance( document );
91       } else {
92         if( this.searchDocumentStatic == null ) {
93           this.document = builder.parse( file );
94           this.searchDocument = (SearchElement)SearchElement.newInstance( this.document );
95         } else {
96           this.searchDocument = searchDocumentStatic;
97         }
98       }
99
100       /* set document to new value, to prevent exist of two same documents
101          in database to decrease memory usage */

102       this.document = builder.newDocument();
103
104       } catch( Exception JavaDoc e ) { throw new SQLException("Error in constructor : "+e.getMessage()); }
105   }
106
107   /**
108    * Adds sql statement CREATE TABLE in XML file.
109    * Method will throw SQLException with appropriate message if table already exist
110    *
111    * @param sqlStatement CREATE TABLE statement which will be add into XML file
112    * @param tableName name of table which will be created
113    * @throws SQLException
114    */

115
116   protected void createTable(String JavaDoc sqlStatement, String JavaDoc tableName) throws SQLException {
117     try {
118       boolean allreadyExist = false;
119       NodeList JavaDoc sqlStatements = searchDocument.getSubElementsByTagName("ddl");
120       XmlSqlParser parser = new XmlSqlParser();
121       for( int i = 0; i < sqlStatements.getLength(); i++ ) {
122         Node JavaDoc node = sqlStatements.item(i);
123         parser.parse( node.getFirstChild().toString() );
124         if ( parser.getTableName().equalsIgnoreCase( tableName ) ) {
125           allreadyExist = true;
126         }
127       }
128       NodeList JavaDoc existingTables = searchDocument.getSubElementsByTagName("dml/"+tableName);
129       if( existingTables.getLength() != 0 ) {
130         allreadyExist = true;
131       }
132       if( allreadyExist ) {
133         this.isError = true;
134         throw new SQLException("Table with specified name already exist ! ");
135       } else {
136         Element JavaDoc newDDLElement = document.createElement("ddl");
137         newDDLElement.appendChild( document.createTextNode( sqlStatement ) );
138         SearchElement newDDL = new SearchElement( newDDLElement );
139         NodeList JavaDoc dml = searchDocument.getSubElementsByTagName("dml");
140         Element JavaDoc before = null;
141         if( dml.getLength() != 0 )
142           before = (Element JavaDoc)dml.item(0);
143         searchDocument.insertBefore( newDDL , before );
144       }
145       saveDOM();
146     } catch( Exception JavaDoc e ) {
147       this.isError = true;
148       throw new SQLException("Error in creating table : "+e.getMessage());
149     }
150   }
151
152   /**
153    * Delete row(s) from XML file.
154    *
155    * @param tableName name of table from which will be deleted rows.
156    * @param whereColumnNames names of columns in WHERE clause.
157    * @param whereColumnValues values of columns in WHERE clause.
158    * @throws SQLException
159    */

160   protected void delete(String JavaDoc tableName, String JavaDoc[] whereColumnNames , String JavaDoc[] whereColumnValues) throws SQLException {
161     try {
162       NodeList JavaDoc tableRows = searchDocument.getSubElementsByTagName("dml/"+tableName);
163       //check if table row match conditions
164
for(int i = 0; i < tableRows.getLength(); i++) {
165         boolean isMatch = true;
166         if( whereColumnNames != null && whereColumnValues != null ) {
167           for(int k = 0; k < whereColumnNames.length; k++) {
168             NodeList JavaDoc columns = ( (SearchElement)tableRows.item(i) ).getSubElementsByCondition(whereColumnNames[k]+"="+whereColumnValues[k]);
169             if( columns.getLength() == 0 )
170               isMatch = false;
171           }
172         }
173         if( whereColumnNames.length == 0 )
174           isMatch=true;
175         if( isMatch ) {
176           //deleting row from XML database
177
SearchElement parent = new SearchElement( tableRows.item(i).getParentNode() );
178           parent.removeChild( tableRows.item(i) );
179         }
180       }
181       saveDOM();
182       } catch( Exception JavaDoc e ) {
183         this.isError = true;
184         throw new SQLException("Error in delete data: "+e.getMessage());
185       }
186   }
187
188   /**
189    * Delete table from XML file.
190    *
191    * @param tableName name of table which will be deleted.
192    * @throws SQLException
193    */

194   protected void dropTable( String JavaDoc tableName ) throws SQLException {
195     try {
196       //delete data
197
NodeList JavaDoc tableRows = searchDocument.getSubElementsByTagName("dml/"+tableName);
198       for( int i = 0; i < tableRows.getLength(); i++ ) {
199         SearchElement parent = new SearchElement( tableRows.item(i).getParentNode() );
200         parent.removeChild( tableRows.item(i) );
201       }
202       //delete CREATE TABLE statement if exist
203
NodeList JavaDoc sqlStatements = searchDocument.getSubElementsByTagName("ddl");
204       XmlSqlParser parser = new XmlSqlParser();
205       for( int i = 0; i < sqlStatements.getLength(); i++ ) {
206         Node JavaDoc node = sqlStatements.item(i);
207         try {
208           parser.parse( node.getFirstChild().toString() );
209         } catch(Exception JavaDoc e) {
210           this.isError = true;
211           throw new SQLException("Error in parsing statement : "+e.getMessage());
212         }
213         if ( parser.getTableName().equalsIgnoreCase( tableName ) && parser.sqlType.equalsIgnoreCase( parser.CREATE_TABLE ) ) {
214           SearchElement parent = new SearchElement( sqlStatements.item(i).getParentNode() );
215           parent.removeChild( sqlStatements.item(i) );
216         }
217       }
218       saveDOM();
219       } catch( Exception JavaDoc e ) {
220         this.isError = true;
221         throw new SQLException("Error in drop table : "+e.getMessage());
222       }
223   }
224
225
226   /**
227    * Insert row in XML file.
228    *
229    * @param tableName name of table in which will be added rows.
230    * @param columnNames names of columns in which will be added data.
231    * @param columnValues value which will be insert into table.
232    * @throws SQLException
233    */

234   protected void insert(String JavaDoc tableName, String JavaDoc[] columnNames , String JavaDoc[] columnValues) throws SQLException {
235     try {
236       String JavaDoc[] allColumnNames = (String JavaDoc[])this.getTableProperties( tableName ).get(0);
237       boolean hasCreateTable =
238           !this.getTableProperties( tableName ).get(1).toString().equalsIgnoreCase("NO CREATE TABLE");
239       if( hasCreateTable ) {
240         String JavaDoc[] primaryKeys = (String JavaDoc[])this.getTableProperties( tableName ).get(1);
241         //check if column is primarykey and if is it duplicate value
242
for(int k = 0; k < columnNames.length; k++) {
243           boolean isPrimarykey = false;
244           for(int i = 0; i < primaryKeys.length; i++) {
245             if( columnNames[k].equals( primaryKeys[i] ) )
246               isPrimarykey = true;
247           }
248           if( isPrimarykey ) {
249             NodeList JavaDoc columns = searchDocument.getSubElementsByCondition("dml/"+tableName+"/"+columnNames[k]+"="+columnValues[k]);
250             if( columns.getLength() != 0 ) {
251               this.isError = true;
252               throw new SQLException("Can not insert duplicate value in primary key column "+columnNames[k]+" !");
253             }
254           }
255         }
256       }
257       //create new table
258
Element JavaDoc newTable = document.createElement(tableName);
259       if( hasCreateTable ) {
260         //has CREATE TABLE statement
261
Element JavaDoc newColumn;
262         for( int i = 0; i < columnNames.length; i++ ) {
263           newColumn = document.createElement( columnNames[i] );
264           if( columnValues[i].equals("null") ) {
265             String JavaDoc[] notNullCols = (String JavaDoc[])this.getTableProperties( tableName ).get(2);
266             for( int ii=0; ii < notNullCols.length; ii++ ) {
267               if( notNullCols[ii].equalsIgnoreCase(columnNames[i]) )
268                 throw new SQLException("Column '" + columnNames[i] + "' can not be NULL.");
269             }
270             //do not add empty column, because there are CREATE TABLE statement
271
continue;
272           }
273           else {
274             newColumn.appendChild( document.createTextNode( columnValues[i] ) );
275           }
276           newTable.appendChild( newColumn );
277         }
278       }
279       //no CREATE TABLE statement
280
else {
281         Element JavaDoc newColumn;
282         for( int i = 0; i < allColumnNames.length; i++ ) {
283           newColumn = document.createElement( allColumnNames[i] );
284           for( int j = 0; j < columnNames.length; j++ ) {
285             if( allColumnNames[i].equalsIgnoreCase( columnNames[j] ) ){
286               if( columnValues[j].equals("null") )
287                 newColumn.appendChild( document.createTextNode( "" ) );
288               else
289                 newColumn.appendChild( document.createTextNode( columnValues[j] ) );
290             }
291             else {
292               newColumn.appendChild( document.createTextNode("") );
293             }
294           }
295           newTable.appendChild( newColumn );
296         }
297       }
298
299       SearchElement newTableHash = new SearchElement( newTable );
300       NodeList JavaDoc tables = searchDocument.getSubElementsByTagName("dml/"+tableName);
301       Element JavaDoc before = null;
302       if( tables.getLength() != 0 ) {
303         before = (Element JavaDoc)tables.item(0);
304         (new SearchElement(searchDocument.getSubElementsByTagName("dml").item(0))).insertBefore( newTableHash , before );
305       } else {
306         searchDocument.getSubElementsByTagName("dml").item(0).insertBefore( newTableHash , null );
307       }
308       saveDOM();
309       } catch( Exception JavaDoc e ) {
310         this.isError = true;
311         throw new SQLException("Error in insert data : "+e.getMessage());
312       }
313   }
314
315   /**
316    * Update row in in XML file.
317    *
318    * @param tableName name of table which will be updatad.
319    * @param columnNames names of columns in which will be added data.
320    * @param columnValues value which will be insert into table.
321    * @param whereColumnNames names of columns in WHERE clause.
322    * @param whereColumnValues values of columns in WHERE clause.
323    * @throws SQLException
324    */

325   protected void update(String JavaDoc tableName, String JavaDoc[] columnNames , String JavaDoc[] columnValues , String JavaDoc[] whereColumnNames , String JavaDoc[] whereColumnValues ) throws SQLException {
326     try {
327       boolean hasCreateTable =
328           !this.getTableProperties( tableName ).get(1).toString().equalsIgnoreCase("NO CREATE TABLE");
329       if( hasCreateTable ) {
330         //check primary key column
331
String JavaDoc[] primaryKeys = (String JavaDoc[])this.getTableProperties( tableName ).get(1);
332         boolean isPrimarykey = false;
333         for(int i = 0; i < primaryKeys.length; i++) {
334           if( columnNames[0].equals( primaryKeys[i] ) )
335             isPrimarykey = true;
336         }
337         if( isPrimarykey ) {
338           NodeList JavaDoc columns = searchDocument.getSubElementsByCondition("dml/"+tableName+"/"+columnNames[0]+"="+columnValues[0]);
339           if( columns.getLength() != 0 ) {
340             this.isError = true;
341             throw new SQLException("Can not insert duplicate value in primarykey column "+columnNames[0]+" !");
342           }
343         }
344       }
345       NodeList JavaDoc tableRows = this.searchDocument.getSubElementsByTagName("dml/"+tableName);
346       //check if table row match conditions
347
for(int i = 0; i < tableRows.getLength(); i++) {
348         boolean isMatch = true;
349         if( whereColumnNames != null && whereColumnValues != null ) {
350           for(int k = 0; k < whereColumnNames.length; k++) {
351             NodeList JavaDoc columns = ( (SearchElement)tableRows.item(i) ).getSubElementsByCondition(whereColumnNames[k]+"="+whereColumnValues[k]);
352             if( columns.getLength() == 0 )
353               isMatch = false;
354           }
355         }
356         if( isMatch ) {
357           for( int k = 0; k < columnNames.length; k++ ) {
358             NodeList JavaDoc columns = ( (SearchElement)tableRows.item(i) ).getSubElementsByTagName(columnNames[k]);
359             String JavaDoc[] notNullCols = null;
360             if( hasCreateTable )
361               notNullCols = (String JavaDoc[])this.getTableProperties( tableName ).get(2);
362             if( columns.getLength() == 0 ) {
363               //if column tag do not exist in row
364
Element JavaDoc newColumn = document.createElement( columnNames[k] );
365               if( columnValues[k].equals("null") ) {
366                 if( hasCreateTable ) {
367                   for( int ii=0; ii < notNullCols.length; ii++ ) {
368                     if( notNullCols[ii].equalsIgnoreCase(columnNames[k]) )
369                       throw new SQLException("Column '" + columnNames[k] + "' can not be NULL.");
370                   }
371                 }
372                 if ( hasCreateTable )
373                   continue; //do not add empty column
374
else
375                   newColumn.appendChild( document.createTextNode( "" ) );
376               }
377               else
378                 newColumn.appendChild( document.createTextNode( columnValues[k] ) );
379               tableRows.item(i).appendChild( new SearchElement(newColumn) );
380             }
381             else {
382               //if column tag exist
383
SearchElement column = (SearchElement)columns.item(0);
384               Node JavaDoc textNode = column.getFirstChild();
385               if( textNode == null ) {
386                 Element JavaDoc newColumn = document.createElement( columnNames[k] );
387                 if( columnValues[k].equals("null") ) {
388                   if( hasCreateTable ) {
389                     for( int ii=0; ii < notNullCols.length; ii++ ) {
390                       if( notNullCols[ii].equalsIgnoreCase(columnNames[k]) )
391                         throw new SQLException("Column '" + columnNames[k] + "' can not be NULL.");
392                     }
393                   }
394                   //when has CREATE TABLE statement, remove tag with null value
395
if( hasCreateTable )
396                     column.getParentNode().removeChild(column);
397                   else
398                     newColumn.appendChild( document.createTextNode( "" ) );
399                 }
400                 //when new value is not null
401
else {
402                   newColumn.appendChild( document.createTextNode( columnValues[k] ) );
403                   SearchElement parent = new SearchElement( column.getParentNode() );
404                   parent.replaceChild( new SearchElement(newColumn) , column );
405                 }
406               }
407               else {
408                 if( columnValues[k].equals("null") ) {
409                   if( hasCreateTable ) {
410                     for( int ii=0; ii < notNullCols.length; ii++ ) {
411                       if( notNullCols[ii].equalsIgnoreCase(columnNames[k]) )
412                         throw new SQLException("Column '" + columnNames[k] + "' can not be NULL.");
413                     }
414                   }
415                   //when has CREATE TABLE statement, remove tag with null value
416
if( hasCreateTable )
417                     column.getParentNode().removeChild(column);
418                   else
419                     column.getFirstChild().setNodeValue( "" );
420                 }
421                 else
422                   column.getFirstChild().setNodeValue( columnValues[k] );
423               }
424             }
425           }
426         }
427       }
428       saveDOM();
429       } catch( Exception JavaDoc e ) {
430         this.isError = true;
431         throw new SQLException("Error in update data : "+e.getMessage());
432       }
433   }
434
435   /**
436    * Gets table properties in form ArrayList.
437    * ArrayList[0] is string array with ALL column names in table.
438    * ArrayList[1] is string array with colmn names which are PRIMARYKEYs.
439    * ArrayList[2] is string array with colmn names which can not be NULL.
440    *
441    * If table has no CREATE TABLE statement , ArrayList[1] will have value "NO CREATE TABLE"
442    *
443    * @param tableName name of table.
444    * @return list of table properties.
445    * @throws SQLException
446    */

447   public ArrayList JavaDoc getTableProperties(String JavaDoc tableName) throws SQLException {
448     ArrayList JavaDoc properties = new ArrayList JavaDoc();
449     NodeList JavaDoc sqlStatements = searchDocument.getSubElementsByTagName("ddl");
450       XmlSqlParser parser = new XmlSqlParser();
451       for( int i = 0; i < sqlStatements.getLength(); i++ ) {
452         Node JavaDoc node = sqlStatements.item(i);
453         try {
454           parser.parse( node.getFirstChild().toString() );
455         } catch(Exception JavaDoc e) {
456           this.isError = true;
457           throw new SQLException("Error in parsing statement : "+e.getMessage());
458         }
459         if ( parser.getTableName().equalsIgnoreCase( tableName ) && parser.sqlType.equalsIgnoreCase( parser.CREATE_TABLE ) ) {
460           properties.add( parser.getColumnNames() );
461           properties.add( parser.getPrimaryKeys() );
462           properties.add( parser.getNotnullColumns() );
463         }
464       }
465       // no CREATE TABLE statement
466
if( properties.size() == 0 ) {
467         NodeList JavaDoc tableTags = searchDocument.getSubElementsByTagName("dml/"+tableName);
468         if( tableTags.getLength() == 0 ) {
469           this.isError = true;
470           throw new SQLException("No existing table with specified name : "+tableName);
471         }
472         if( tableTags.getLength() != 0 ) {
473           NodeList JavaDoc tableColumns = tableTags.item(0).getChildNodes();
474           ArrayList JavaDoc arrColumns = new ArrayList JavaDoc();
475           for( int i = 0; i < tableColumns.getLength(); i++ ) {
476             String JavaDoc value = tableColumns.item(i).getNodeName();
477             if( value != null && !value.equalsIgnoreCase("#text") ) {
478               arrColumns.add( tableColumns.item(i).getNodeName() );
479             }
480           }
481             properties.add( arrColumns.toArray(new String JavaDoc[0]) );
482             properties.add( "NO CREATE TABLE" );
483         }
484       }
485     return properties;
486   }
487
488   /**
489    * Method is called when create new database file.
490    *
491    * @throws SQLException
492    */

493   protected void createDatabase() throws SQLException {
494       try {
495         Properties JavaDoc prop = new Properties JavaDoc();
496         prop.setProperty("version","1.0");
497         prop.setProperty("encoding","ISO-8859-1");
498         XMLDocumentFactory.serialize( this.searchDocument , fileName , prop );
499       } catch( Exception JavaDoc e ) {
500         throw new SQLException("Error in saving DOM : "+e.getMessage());
501       }
502   }
503
504   /**
505    * Save DOM as XML file.
506    *
507    * @throws SQLException
508    */

509   protected void saveDOM() throws SQLException {
510     if( !XmlWriter.isError ) {
511       try {
512         Properties JavaDoc prop = new Properties JavaDoc();
513         prop.setProperty("version","1.0");
514         prop.setProperty("encoding","ISO-8859-1");
515         if( this.autoCommit ) {
516           XMLDocumentFactory.serialize( this.searchDocument , fileName , prop );
517         }
518         else
519           this.searchDocumentStatic = searchDocument;
520
521       } catch( Exception JavaDoc e ) {
522         this.isError = true;
523         throw new SQLException("Error in saving DOM : "+e.getMessage());
524       }
525     }
526   }
527
528   /**
529    * Method is used for saving DOM in xml file from connection object,when XmlConnection.commit() method
530    * is called.
531    * @param fileName full path of xml file.
532    * @throws SQLException
533    */

534   public static void commit(String JavaDoc fileName) throws SQLException {
535     if( !XmlWriter.isError && XmlWriter.searchDocumentStatic != null ) {
536       try {
537         Properties JavaDoc prop = new Properties JavaDoc();
538         prop.setProperty("version","1.0");
539         prop.setProperty("encoding","ISO-8859-1");
540         XMLDocumentFactory.serialize( XmlWriter.searchDocumentStatic , fileName , prop );
541         XmlWriter.searchDocumentStatic = null;
542       } catch( Exception JavaDoc e ) {
543         throw new SQLException("Error in saving DOM : "+e.getMessage());
544       }
545     }
546   }
547
548 }
549
550
Popular Tags