001package org.apache.commons.digester3.examples.api.dbinsert; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one or more 005 * contributor license agreements. See the NOTICE file distributed with 006 * this work for additional information regarding copyright ownership. 007 * The ASF licenses this file to You under the Apache License, Version 2.0 008 * (the "License"); you may not use this file except in compliance with 009 * the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020import java.io.File; 021import java.io.IOException; 022import java.sql.Connection; 023 024import org.apache.commons.digester3.Digester; 025import org.xml.sax.SAXException; 026 027/** 028 * A simple program to demonstrate that the Commons Digester module can be 029 * used to trigger actions as the xml is parsed, rather than just build 030 * up in-memory representations of the parsed data. This example also shows 031 * how to write a custom Rule class. 032 * <p> 033 * This code will parse the provided "example.xml" file, and immediately 034 * insert the processed data into a database as each row tag is parsed, 035 * instead of building up an in-memory representation. Actually, in order 036 * to keep this example simple and easy to run, sql insert statements are 037 * printed out rather than actually performing database inserts, but the 038 * principle remains. 039 * <p> 040 * Very verbose comments are included here, as this class is intended 041 * as a tutorial; if you look closely at method "addRules", you will 042 * see that the amount of code required to use the Digester is actually 043 * quite low. 044 * <p> 045 * Usage: java Main example.xml 046 */ 047public class Main 048{ 049 050 /** 051 * Main method : entry point for running this example program. 052 * <p> 053 * Usage: java Main example.xml 054 */ 055 public static void main( String[] args ) 056 { 057 if ( args.length != 1 ) 058 { 059 usage(); 060 System.exit( -1 ); 061 } 062 063 String filename = args[0]; 064 065 // Create a Digester instance 066 Digester d = new Digester(); 067 068 // Here you would establish a real connection. 069 // There would also be a finally clause to ensure it is 070 // closed after parsing terminates, etc. 071 Connection connection = null; 072 073 // Add rules to the digester that will be triggered while 074 // parsing occurs. 075 addRules( d, connection ); 076 077 // Process the input file. 078 System.out.println( "Parsing commencing..." ); 079 try 080 { 081 File srcfile = new File( filename ); 082 d.parse( srcfile ); 083 } 084 catch ( IOException ioe ) 085 { 086 System.out.println( "Error reading input file:" + ioe.getMessage() ); 087 System.exit( -1 ); 088 } 089 catch ( SAXException se ) 090 { 091 System.out.println( "Error parsing input file:" + se.getMessage() ); 092 System.exit( -1 ); 093 } 094 095 // And here there is nothing to do. The digester rules have 096 // (deliberately) not built a representation of the input, but 097 // instead processed the data as it was read. 098 System.out.println( "Parsing complete." ); 099 } 100 101 private static void addRules( Digester d, java.sql.Connection conn ) 102 { 103 104 // -------------------------------------------------- 105 // when we encounter a "table" tag, do the following: 106 107 // Create a new instance of class Table, and push that 108 // object onto the digester stack of objects. We only need 109 // this so that when a row is inserted, it can find out what 110 // the enclosing tablename was. 111 // 112 // Note that the object is popped off the stack at the end of the 113 // "table" tag (normal behaviour for ObjectCreateRule). Because we 114 // never added the table object to some parent object, when it is 115 // popped off the digester stack it becomes garbage-collected. That 116 // is fine in this situation; we've done all the necessary work and 117 // don't need the table object any more. 118 d.addObjectCreate( "database/table", Table.class ); 119 120 // Map *any* attributes on the table tag to appropriate 121 // setter-methods on the top object on the stack (the Table 122 // instance created by the preceeding rule). We only expect one 123 // attribute, though: a 'name' attribute specifying what table 124 // we are inserting rows into. 125 d.addSetProperties( "database/table" ); 126 127 // -------------------------------------------------- 128 // When we encounter a "row" tag, invoke methods on the provided 129 // RowInserterRule instance. 130 // 131 // This rule creates a Row instance and pushes it on the digester 132 // object stack, rather like ObjectCreateRule, so that the column 133 // tags have somewhere to store their information. And when the 134 // </row> end tag is found, the rule will trigger to remove this 135 // object from the stack, and also do an actual database insert. 136 // 137 // Note that the rule instance we are passing to the digester has 138 // been initialised with some useful data (the SQL connection). 139 // 140 // Note also that in this case we are not using the digester's 141 // factory methods to create the rule instance; that's just a 142 // convenience - and obviously not an option for Rule classes 143 // that are not part of the digester core implementation. 144 RowInserterRule rowInserterRule = new RowInserterRule( conn ); 145 d.addRule( "database/table/row", rowInserterRule ); 146 147 // -------------------------------------------------- 148 // when we encounter a "column" tag, call setColumn on the top 149 // object on the stack, passing two parameters: the "name" 150 // attribute, and the text within the tag body. 151 d.addCallMethod( "database/table/row/column", "addColumn", 2 ); 152 d.addCallParam( "database/table/row/column", 0, "name" ); 153 d.addCallParam( "database/table/row/column", 1 ); 154 } 155 156 private static void usage() 157 { 158 System.out.println( "Usage: java Main example.xml" ); 159 } 160 161}