View Javadoc

1   package org.apache.commons.digester3.examples.api.dbinsert;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   * 
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */ 
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.sql.Connection;
23  
24  import org.apache.commons.digester3.Digester;
25  import org.xml.sax.SAXException;
26  
27  /**
28   * A simple program to demonstrate that the Commons Digester module can be
29   * used to trigger actions as the xml is parsed, rather than just build
30   * up in-memory representations of the parsed data. This example also shows
31   * how to write a custom Rule class.
32   * <p>
33   * This code will parse the provided "example.xml" file, and immediately 
34   * insert the processed data into a database as each row tag is parsed,
35   * instead of building up an in-memory representation. Actually, in order 
36   * to keep this example simple and easy to run, sql insert statements are 
37   * printed out rather than actually performing database inserts, but the 
38   * principle remains.
39   * <p> 
40   * Very verbose comments are included here, as this class is intended
41   * as a tutorial; if you look closely at method "addRules", you will
42   * see that the amount of code required to use the Digester is actually
43   * quite low.
44   * <p>
45   * Usage: java Main example.xml
46   */
47  public class Main
48  {
49  
50      /**
51       * Main method : entry point for running this example program.
52       * <p>
53       * Usage: java Main example.xml
54       */
55      public static void main( String[] args )
56      {
57          if ( args.length != 1 )
58          {
59              usage();
60              System.exit( -1 );
61          }
62  
63          String filename = args[0];
64  
65          // Create a Digester instance
66          Digester d = new Digester();
67  
68          // Here you would establish a real connection.
69          // There would also be a finally clause to ensure it is
70          // closed after parsing terminates, etc.
71          Connection connection = null;
72  
73          // Add rules to the digester that will be triggered while
74          // parsing occurs.
75          addRules( d, connection );
76  
77          // Process the input file.
78          System.out.println( "Parsing commencing..." );
79          try
80          {
81              File srcfile = new File( filename );
82              d.parse( srcfile );
83          }
84          catch ( IOException ioe )
85          {
86              System.out.println( "Error reading input file:" + ioe.getMessage() );
87              System.exit( -1 );
88          }
89          catch ( SAXException se )
90          {
91              System.out.println( "Error parsing input file:" + se.getMessage() );
92              System.exit( -1 );
93          }
94  
95          // And here there is nothing to do. The digester rules have
96          // (deliberately) not built a representation of the input, but
97          // instead processed the data as it was read.
98          System.out.println( "Parsing complete." );
99      }
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 }