View Javadoc
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; 23 import org.w3c.dom.NodeList; 24 import org.w3c.dom.Node; 25 import org.w3c.dom.Element; 26 import org.enhydra.xml.SearchElement; 27 import org.enhydra.xml.XMLDocumentFactory; 28 import javax.xml.parsers.DocumentBuilder; 29 import javax.xml.parsers.DocumentBuilderFactory; 30 31 import java.sql.*; 32 import java.io.File; 33 import java.util.Properties; 34 import java.io.RandomAccessFile; 35 import java.util.ArrayList; 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 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 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 fileName, boolean isAutoCommit) throws SQLException { 70 try { 71 XmlWriter.isError = false; 72 this.autoCommit = isAutoCommit; 73 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 74 DocumentBuilder builder = factory.newDocumentBuilder(); 75 //check if database exist, and if not, create one 76 this.fileName = fileName; 77 File file = new File( fileName ); 78 if( !file.exists() ) { 79 file.getParentFile().mkdirs(); 80 this.document = builder.newDocument(); 81 Element 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 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 sqlStatement, String tableName) throws SQLException { 117 try { 118 boolean allreadyExist = false; 119 NodeList sqlStatements = searchDocument.getSubElementsByTagName("ddl"); 120 XmlSqlParser parser = new XmlSqlParser(); 121 for( int i = 0; i < sqlStatements.getLength(); i++ ) { 122 Node node = sqlStatements.item(i); 123 parser.parse( node.getFirstChild().toString() ); 124 if ( parser.getTableName().equalsIgnoreCase( tableName ) ) { 125 allreadyExist = true; 126 } 127 } 128 NodeList 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 newDDLElement = document.createElement("ddl"); 137 newDDLElement.appendChild( document.createTextNode( sqlStatement ) ); 138 SearchElement newDDL = new SearchElement( newDDLElement ); 139 NodeList dml = searchDocument.getSubElementsByTagName("dml"); 140 Element before = null; 141 if( dml.getLength() != 0 ) 142 before = (Element)dml.item(0); 143 searchDocument.insertBefore( newDDL , before ); 144 } 145 saveDOM(); 146 } catch( Exception 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 tableName, String[] whereColumnNames , String[] whereColumnValues) throws SQLException { 161 try { 162 NodeList 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 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 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 tableName ) throws SQLException { 195 try { 196 //delete data 197 NodeList 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 sqlStatements = searchDocument.getSubElementsByTagName("ddl"); 204 XmlSqlParser parser = new XmlSqlParser(); 205 for( int i = 0; i < sqlStatements.getLength(); i++ ) { 206 Node node = sqlStatements.item(i); 207 try { 208 parser.parse( node.getFirstChild().toString() ); 209 } catch(Exception 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 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 tableName, String[] columnNames , String[] columnValues) throws SQLException { 235 try { 236 String[] allColumnNames = (String[])this.getTableProperties( tableName ).get(0); 237 boolean hasCreateTable = 238 !this.getTableProperties( tableName ).get(1).toString().equalsIgnoreCase("NO CREATE TABLE"); 239 if( hasCreateTable ) { 240 String[] primaryKeys = (String[])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 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 newTable = document.createElement(tableName); 259 if( hasCreateTable ) { 260 //has CREATE TABLE statement 261 Element newColumn; 262 for( int i = 0; i < columnNames.length; i++ ) { 263 newColumn = document.createElement( columnNames[i] ); 264 if( columnValues[i].equals("null") ) { 265 String[] notNullCols = (String[])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 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 tables = searchDocument.getSubElementsByTagName("dml/"+tableName); 301 Element before = null; 302 if( tables.getLength() != 0 ) { 303 before = (Element)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 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 tableName, String[] columnNames , String[] columnValues , String[] whereColumnNames , String[] 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[] primaryKeys = (String[])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 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 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 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 columns = ( (SearchElement)tableRows.item(i) ).getSubElementsByTagName(columnNames[k]); 359 String[] notNullCols = null; 360 if( hasCreateTable ) 361 notNullCols = (String[])this.getTableProperties( tableName ).get(2); 362 if( columns.getLength() == 0 ) { 363 //if column tag do not exist in row 364 Element 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 textNode = column.getFirstChild(); 385 if( textNode == null ) { 386 Element 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 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 getTableProperties(String tableName) throws SQLException { 448 ArrayList properties = new ArrayList(); 449 NodeList sqlStatements = searchDocument.getSubElementsByTagName("ddl"); 450 XmlSqlParser parser = new XmlSqlParser(); 451 for( int i = 0; i < sqlStatements.getLength(); i++ ) { 452 Node node = sqlStatements.item(i); 453 try { 454 parser.parse( node.getFirstChild().toString() ); 455 } catch(Exception 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 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 tableColumns = tableTags.item(0).getChildNodes(); 474 ArrayList arrColumns = new ArrayList(); 475 for( int i = 0; i < tableColumns.getLength(); i++ ) { 476 String 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[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 prop = new Properties(); 496 prop.setProperty("version","1.0"); 497 prop.setProperty("encoding","ISO-8859-1"); 498 XMLDocumentFactory.serialize( this.searchDocument , fileName , prop ); 499 } catch( Exception 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 prop = new Properties(); 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 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 fileName) throws SQLException { 535 if( !XmlWriter.isError && XmlWriter.searchDocumentStatic != null ) { 536 try { 537 Properties prop = new Properties(); 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 e ) { 543 throw new SQLException("Error in saving DOM : "+e.getMessage()); 544 } 545 } 546 } 547 548 } 549

This page was automatically generated by Maven