Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that reads in an XML text document and
4
 *             write its contents to a database connection using SAX
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones
8
 *    Release: @release@
9
 *
10
 *   '$Author: jones $'
11
 *     '$Date: 2000-08-14 13:53:34 -0700 (Mon, 14 Aug 2000) $'
12
 * '$Revision: 349 $'
13
 */
14

    
15
package edu.ucsb.nceas.metacat;
16

    
17
import java.io.*;
18
import java.sql.*;
19
import java.util.Stack;
20

    
21
import org.xml.sax.AttributeList;
22
import org.xml.sax.ContentHandler;
23
import org.xml.sax.DTDHandler;
24
import org.xml.sax.EntityResolver;
25
import org.xml.sax.ErrorHandler;
26
import org.xml.sax.InputSource;
27
import org.xml.sax.XMLReader;
28
import org.xml.sax.SAXException;
29
import org.xml.sax.SAXParseException;
30
import org.xml.sax.helpers.XMLReaderFactory;
31

    
32
/**
33
 * A Class that reads in an XML text document and
34
 * write its contents to a database connection using SAX
35
 */
36
public class DBWriter {
37

    
38
  private Connection	conn = null;
39
  private String parserName = null;
40

    
41
  /**
42
   * the main routine used to test the DBWriter utility.
43
   * <p>
44
   * Usage: java DBWriter <-f filename -a action -d docid>
45
   *
46
   * @param filename the filename to be loaded into the database
47
   */
48
  static public void main(String[] args) {
49
     
50
    try {
51
      String filename = null;
52
      String action   = null;
53
      String docid    = null;
54

    
55
      for ( int i=0 ; i < args.length; ++i ) {
56
        if ( args[i].equals( "-f" ) ) {
57
          filename =  args[++i];
58
        } else if ( args[i].equals( "-a" ) ) {
59
          action =  args[++i];
60
        } else if ( args[i].equals( "-d" ) ) {
61
          docid =  args[++i];
62
        } else {
63
          System.err.println
64
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
65
        }
66
      }
67
      
68
      boolean argsAreValid = false;
69
      if (action != null) {
70
        if (action.equals("INSERT")) {
71
          if (filename != null) {
72
            argsAreValid = true;
73
          } 
74
        } else if (action.equals("UPDATE")) {
75
          if ((filename != null) && (docid != null)) {
76
            argsAreValid = true;
77
          } 
78
        } else if (action.equals("DELETE")) {
79
          if (docid != null) {
80
            argsAreValid = true;
81
          } 
82
        } 
83
      } 
84

    
85
      if (!argsAreValid) {
86
        System.err.println("Wrong number of arguments!!!");
87
        System.err.println(
88
              "USAGE: java DBWriter <-f filename -a action -d docid>");
89
        return;
90
      }
91
 
92
      // Open a connection to the database
93
      MetaCatUtil   util = new MetaCatUtil();
94
      Connection dbconn = util.openDBConnection();
95

    
96
      DBWriter dbw = new DBWriter(dbconn, util.getOption("saxparser"));
97
      if (action.equals("DELETE")) {
98
        dbw.delete(docid);
99
        System.out.println("Document deleted: " + docid);
100
      } else {
101
        String newdocid = dbw.write(filename, action, docid);
102
        if ((docid != null) && (!docid.equals(newdocid))) {
103
          if (action.equals("INSERT")) {
104
            System.out.println("New document ID generated!!! ");
105
          } else if (action.equals("UPDATE")) {
106
            System.out.println("ERROR: Couldn't update document!!! ");
107
          }
108
        } else if ((docid == null) && (action.equals("UPDATE"))) {
109
            System.out.println("ERROR: Couldn't update document!!! ");
110
        }
111
        System.out.println("Document processing finished for: " + filename
112
              + " (" + newdocid + ")");
113
      }
114

    
115
    } catch (AccessionNumberException ane) {
116
      System.out.println("ERROR: Couldn't delete document!!! ");
117
      System.out.println(ane.getMessage());
118
    } catch (Exception e) {
119
      System.err.println("EXCEPTION HANDLING REQUIRED");
120
      System.err.println(e.getMessage());
121
      e.printStackTrace(System.err);
122
    }
123
  }
124
  
125
  /**
126
   * construct a new instance of the class to write an XML file to the database
127
   *
128
   * @param conn the database connection to which to write the XML file
129
   * @param parserName the name of a SAX2 compliant parser class
130
   */
131
  public DBWriter(Connection conn, String parserName) {
132
    this.conn = conn;
133
    this.parserName = parserName;
134
  }
135

    
136
  /**
137
   * Insert XML stream to the database
138
   *
139
   * @param xml the xml stream to be loaded into the database
140
   */
141
  public String write( Reader xml, String action, String docid )
142
                throws Exception, IOException, SQLException, 
143
                       ClassNotFoundException, SAXException, SAXParseException {
144
    try {
145
        XMLReader parser = initializeParser(action, docid);
146
        conn.setAutoCommit(false);
147
        parser.parse(new InputSource(xml));
148
        conn.commit();
149
        conn.setAutoCommit(true);
150
        return docid;
151
      } catch (SAXParseException e) {
152
        conn.rollback();
153
        throw e;
154
      } catch (SAXException e) {
155

    
156
        // If its a problem with the accession number its ok, just the 
157
        // accession number was regenerated
158
        AccessionNumberGeneratedException ang = null;
159
        try {
160
          Exception embedded = e.getException();
161
          if ((embedded != null) && 
162
              (embedded instanceof AccessionNumberGeneratedException)) {
163
            ang = (AccessionNumberGeneratedException)e.getException();
164
          }
165
        } catch (ClassCastException cce) {
166
          // Do nothing and just fall through to the ang != null test
167
        }
168
        if (ang != null) {
169
          conn.commit();
170
          conn.setAutoCommit(true);
171
          return (ang.getMessage());
172
        } else {
173
          conn.rollback();
174
          throw e;
175
        }
176
      } catch (Exception e) {
177
        conn.rollback();
178
        throw e;
179
      }
180
  }
181

    
182
  /**
183
   * Insert an XML file to the database
184
   *
185
   * @param filename the filename to be loaded into the database
186
   */
187
  public String write( String filename, String action, String docid )
188
                throws Exception, IOException, SQLException, 
189
                       ClassNotFoundException, SAXException, SAXParseException {
190
     return write(new FileReader(new File(filename).toString()), action, docid);
191
  }
192
  
193
  private XMLReader initializeParser(String action, String docid) {
194
    XMLReader parser = null;
195
    //
196
    // Set up the SAX document handlers for parsing
197
    //
198
    try {
199
      ContentHandler chandler   = new DBSAXHandler(conn, action, docid);
200
      EntityResolver dbresolver = new DBEntityResolver(conn, 
201
                                      (DBSAXHandler)chandler);
202
      DTDHandler dtdhandler     = new DBDTDHandler(conn);
203

    
204
      // Get an instance of the parser
205
      parser = XMLReaderFactory.createXMLReader(parserName);
206

    
207
      // Turn off validation
208
      parser.setFeature("http://xml.org/sax/features/validation", false);
209
      
210
      // Set Handlers in the parser
211
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
212
                         chandler);
213
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
214
                         chandler);
215
      parser.setContentHandler((ContentHandler)chandler);
216
      parser.setEntityResolver((EntityResolver)dbresolver);
217
      parser.setDTDHandler((DTDHandler)dtdhandler);
218
      parser.setErrorHandler((ErrorHandler)chandler);
219

    
220
    } catch (Exception e) {
221
       System.err.println(e.toString());
222
    }
223

    
224
    return parser;
225
  }
226

    
227
  /**
228
   * Delete an XML file from the database (actually, just make it a revision
229
   * in the xml_revisions table)
230
   *
231
   * @param docid the ID of the document to be deleted from the database
232
   */
233
  public void delete( String docid )
234
                  throws IOException, SQLException, 
235
                         ClassNotFoundException, AccessionNumberException {
236

    
237
    String newdocid = AccessionNumber.generate(docid, "DELETE");
238

    
239
    conn.setAutoCommit(false);
240
    // Copy the record to the xml_revisions table
241
    DBSAXDocument document = new DBSAXDocument(conn);
242
    document.saveDocument( docid );
243

    
244
    // Now delete it from the xml_documents table
245
    Statement stmt = conn.createStatement();
246
    stmt.execute("DELETE FROM xml_index WHERE docid LIKE '" + docid + "'");
247
    stmt.execute("DELETE FROM xml_documents WHERE docid LIKE '" + docid + "'");
248
    stmt.close();
249
    conn.commit();
250
  }
251
}
252

    
253
/**
254
 * '$Log$
255
 * 'Revision 1.24  2000/08/14 17:59:32  bojilova
256
 * 'on "DELETE" added delete from xml_index table for a given docid
257
 * 'before delete from xml_documents, b' of foreign key in xml_index(docid)
258
 * 'to xml_documents(docid)
259
 * '
260
 * 'Revision 1.23  2000/06/29 23:27:08  jones
261
 * 'Fixed bug in DBEntityResolver so that it now properly delegates to
262
 * 'the system id found inthe database.
263
 * 'Changed DBValidate to use DBEntityResolver, rather than the OASIS
264
 * 'catalog, and to return validation results in XML format.
265
 * '
266
 * 'Revision 1.22  2000/06/27 04:31:07  jones
267
 * 'Fixed bugs associated with the new UPDATE and DELETE functions of
268
 * 'DBWriter.  There were problematic interactions between some static
269
 * 'variables used in DBEntityResolver and the way in which the
270
 * 'Servlet objects are re-used across multiple client invocations.
271
 * '
272
 * 'Generally cleaned up error reporting.  Now all errors and success
273
 * 'results are reported as XML documents from MetaCatServlet.  Need
274
 * 'to make the command line tools do the same.
275
 * '
276
 * 'Revision 1.21  2000/06/26 10:35:05  jones
277
 * 'Merged in substantial changes to DBWriter and associated classes and to
278
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
279
 * 'functions.  The command line tools and the parameters for the
280
 * 'servlet have changed substantially.
281
 * '
282
 * 'Revision 1.20.2.7  2000/06/26 10:18:06  jones
283
 * 'Partial fix for MetaCatServlet INSERT?UPDATE bug.  Only will work on
284
 * 'the first call to the servlet.  Subsequent calls fail.  Seems to be
285
 * 'related to exception handling.  Multiple successive DELETE actions
286
 * 'work fine.
287
 * '
288
 * 'Revision 1.20.2.6  2000/06/26 08:38:02  jones
289
 * 'Added DELETE feature to DBWriter.  Now takes an action "DELETE" and a
290
 * 'docid and will move the record from the xml_documents table to the
291
 * 'xml_revisions table.
292
 * 'Modified option parsing to support option symbols on command line.
293
 * '
294
 * 'Revision 1.20.2.5  2000/06/26 02:02:20  jones
295
 * 'Continued fixing problems with exception handling that deals
296
 * 'with INSERT and UPDATE actions and the docid passed to DBWriter
297
 * '
298
 * 'Revision 1.20.2.4  2000/06/26 00:51:06  jones
299
 * 'If docid passed to DBWriter.write() is not unique, classes now generate
300
 * 'an AccessionNumberException containing the new docid generated as a
301
 * 'replacement.  The docid is then extracted from the exception and
302
 * 'returned to the calling application for user feedback or client processing.
303
 * '
304
 * 'Revision 1.20.2.3  2000/06/25 23:38:16  jones
305
 * 'Added RCSfile keyword
306
 * '
307
 * 'Revision 1.20.2.2  2000/06/25 23:34:18  jones
308
 * 'Changed documentation formatting, added log entries at bottom of source files
309
 * ''
310
 */
(17-17/27)