Project

General

Profile

1 17 jones
/**
2 203 jones
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8 17 jones
 *
9 203 jones
 *   '$Author$'
10
 *     '$Date$'
11
 * '$Revision$'
12 17 jones
 */
13
14 75 jones
package edu.ucsb.nceas.metacat;
15 51 jones
16 17 jones
import java.sql.*;
17
import java.util.Stack;
18 18 jones
import java.util.EmptyStackException;
19 17 jones
20 185 jones
import org.xml.sax.Attributes;
21
import org.xml.sax.SAXException;
22 204 jones
import org.xml.sax.SAXParseException;
23 186 jones
import org.xml.sax.ext.DeclHandler;
24 185 jones
import org.xml.sax.ext.LexicalHandler;
25
import org.xml.sax.helpers.DefaultHandler;
26 17 jones
27 31 jones
/**
28
 * A database aware Class implementing callback bethods for the SAX parser to
29
 * call when processing the XML stream and generating events
30
 */
31 186 jones
public class DBSAXHandler extends DefaultHandler
32
                          implements LexicalHandler, DeclHandler {
33 17 jones
34 204 jones
   private boolean	atFirstElement;
35 243 jones
   private boolean	processingDTD;
36 204 jones
   private String 	docname = null;
37 135 jones
   private String 	doctype;
38
   private String 	systemid;
39 17 jones
   private boolean 	stackCreated = false;
40 137 jones
   private Stack 	nodeStack;
41 17 jones
   private Connection	conn = null;
42 142 jones
   private DBSAXDocument currentDocument;
43 185 jones
   private DBSAXNode    rootNode;
44 203 jones
   private String       action = null;
45
   private String       docid = null;
46 17 jones
47 220 jones
   private static final int MAXDATACHARS = 4000;
48
49 31 jones
   /** Construct an instance of the handler class
50
    *
51
    * @param conn the JDBC connection to which information is written
52
    */
53 122 jones
   public DBSAXHandler(Connection conn) {
54 185 jones
     this.conn = conn;
55 204 jones
     this.atFirstElement = true;
56 243 jones
     this.processingDTD = false;
57 17 jones
58 185 jones
     // Create the stack for keeping track of node context
59
     // if it doesn't already exist
60
     if (!stackCreated) {
61
       nodeStack = new Stack();
62
       stackCreated = true;
63
     }
64 17 jones
   }
65
66 203 jones
   /** Construct an instance of the handler class
67
    *
68
    * @param conn the JDBC connection to which information is written
69
    */
70
   public DBSAXHandler(Connection conn, String action, String docid) {
71
     this(conn);
72
     this.action = action;
73
     this.docid = docid;
74
   }
75
76 72 bojilova
   /** SAX Handler that receives notification of beginning of the document */
77 122 jones
   public void startDocument() throws SAXException {
78 203 jones
     MetaCatUtil.debugMessage("start Document");
79
80 185 jones
     // Create the document node representation as root
81
     rootNode = new DBSAXNode(conn, docname);
82 204 jones
     MetaCatUtil.debugMessage("PRINTING DOCNAME FROM ROOTNODE: " +
83
                               rootNode.getTagName());
84 185 jones
     // Add the node to the stack, so that any text data can be
85
     // added as it is encountered
86
     nodeStack.push(rootNode);
87 72 bojilova
   }
88
89
   /** SAX Handler that receives notification of end of the document */
90 122 jones
   public void endDocument() throws SAXException {
91 185 jones
     currentDocument.setTitleFromChildElement();
92 203 jones
     MetaCatUtil.debugMessage("end Document");
93
     if ((docid != null) && (!docid.equals(currentDocument.getDocID()))) {
94
       throw (new SAXException("New document ID generated:",
95 204 jones
           new AccessionNumberGeneratedException(currentDocument.getDocID())));
96 203 jones
     } else {
97
       throw (new SAXException("New document ID generated:",
98 204 jones
           new AccessionNumberGeneratedException(currentDocument.getDocID())));
99 122 jones
     }
100 72 bojilova
   }
101
102 185 jones
   /** SAX Handler that is called at the start of each XML element */
103
   public void startElement(String uri, String localName,
104
                            String qName, Attributes atts)
105
               throws SAXException {
106 203 jones
     MetaCatUtil.debugMessage("Start ELEMENT " + localName);
107 72 bojilova
108 203 jones
     DBSAXNode parentNode = null;
109
     DBSAXNode currentNode = null;
110 17 jones
111 203 jones
     // Get a reference to the parent node for the id
112
     try {
113
       parentNode = (DBSAXNode)nodeStack.peek();
114
     } catch (EmptyStackException e) {
115
     }
116 18 jones
117 203 jones
     // Document representation that points to the root document node
118 204 jones
     if (atFirstElement) {
119
       atFirstElement = false;
120 203 jones
       // If no DOCTYPE declaration: docname = root element name
121
       if (docname == null) {
122
         docname = localName;
123 204 jones
         doctype = docname;
124
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname);
125
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype);
126 203 jones
       } else if (doctype == null) {
127 204 jones
         doctype = docname;
128
         //doctype = DBEntityResolver.doctype;
129
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype);
130 203 jones
       }
131
       rootNode.writeNodename(docname);
132
       rootNode.writeRootNodeID(rootNode.getNodeID());
133
       try {
134
         currentDocument = new DBSAXDocument(conn, rootNode.getNodeID(),
135
                                           docname, doctype, docid, action);
136
         } catch (AccessionNumberException ane) {
137 204 jones
           throw (new SAXException("Error with " + action, ane));
138 203 jones
         }
139
       rootNode.writeDocID(currentDocument.getDocID());
140
     }
141 135 jones
142 203 jones
     // Create the current node representation
143 313 bojilova
     currentNode = new DBSAXNode(conn, localName, parentNode, currentDocument);
144 17 jones
145 203 jones
     // Add all of the attributes
146
     for (int i=0; i<atts.getLength(); i++) {
147
       currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
148
     }
149 17 jones
150 203 jones
     // Add the node to the stack, so that any text data can be
151
     // added as it is encountered
152
     nodeStack.push(currentNode);
153
  }
154 17 jones
155 31 jones
   /** SAX Handler that is called for each XML text node */
156 122 jones
   public void characters(char[] cbuf, int start, int len) {
157 203 jones
     MetaCatUtil.debugMessage("CHARACTERS");
158 186 jones
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
159 220 jones
     String data = null;
160
     int leftover = len;
161
     int offset = start;
162
     boolean moredata = true;
163
164
     // This loop deals with the case where there are more characters
165
     // than can fit in a single database text field (limit is
166
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
167
     // write a series of nodes that are MAXDATACHARS long, and then the
168
     // final node contains the remainder
169
     while (moredata) {
170
       if (leftover > MAXDATACHARS) {
171
         data = new String(cbuf, offset, MAXDATACHARS);
172
         leftover -= MAXDATACHARS;
173
         offset += MAXDATACHARS;
174
       } else {
175
         data = new String(cbuf, offset, leftover);
176
         moredata = false;
177
       }
178 122 jones
179 220 jones
       // Write the content of the node to the database
180
       currentNode.writeChildNodeToDB("TEXT", null, data);
181
     }
182 17 jones
   }
183
184 31 jones
   /**
185
    * SAX Handler that is called for each XML text node that is Ignorable
186
    * white space
187
    */
188 122 jones
   public void ignorableWhitespace(char[] cbuf, int start, int len) {
189 203 jones
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE");
190 17 jones
   }
191
192 122 jones
   /**
193
    * SAX Handler called once for each processing instruction found:
194
    * node that PI may occur before or after the root element.
195
    */
196
   public void processingInstruction(String target, String data)
197
          throws SAXException {
198 203 jones
     MetaCatUtil.debugMessage("PI");
199 186 jones
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
200
     currentNode.writeChildNodeToDB("PI", target, data);
201 92 bojilova
   }
202 72 bojilova
203 31 jones
   /** SAX Handler that is called at the end of each XML element */
204 185 jones
   public void endElement(String uri, String localName,
205
                          String qName) throws SAXException {
206 203 jones
     MetaCatUtil.debugMessage("End ELEMENT " + localName);
207 17 jones
208 185 jones
     // Get the node from the stack
209
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
210 17 jones
   }
211
212 185 jones
   //
213
   // the next section implements the LexicalHandler interface
214
   //
215
216
   /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
217
   public void startDTD(String name, String publicId, String systemId)
218
               throws SAXException {
219
     docname = name;
220
     doctype = publicId;
221
     systemid = systemId;
222
223 204 jones
     MetaCatUtil.debugMessage("Start DTD");
224 203 jones
     MetaCatUtil.debugMessage("DOCNAME: " + docname);
225
     MetaCatUtil.debugMessage("DOCTYPE: " + doctype);
226
     MetaCatUtil.debugMessage("  SYSID: " + systemid);
227 185 jones
   }
228
229
   /**
230
    * SAX Handler that receives notification of end of DTD
231
    */
232
   public void endDTD() throws SAXException {
233 204 jones
     MetaCatUtil.debugMessage("end DTD");
234 185 jones
   }
235
236
   /**
237
    * SAX Handler that receives notification of comments in the DTD
238
    */
239
   public void comment(char[] ch, int start, int length) throws SAXException {
240 203 jones
     MetaCatUtil.debugMessage("COMMENT");
241 186 jones
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
242
     currentNode.writeChildNodeToDB("COMMENT", null, new String(ch));
243 185 jones
   }
244
245
   /**
246
    * SAX Handler that receives notification of the start of CDATA sections
247
    */
248
   public void startCDATA() throws SAXException {
249 203 jones
     MetaCatUtil.debugMessage("start CDATA");
250 185 jones
   }
251
252
   /**
253
    * SAX Handler that receives notification of the end of CDATA sections
254
    */
255
   public void endCDATA() throws SAXException {
256 203 jones
     MetaCatUtil.debugMessage("end CDATA");
257 185 jones
   }
258
259
   /**
260
    * SAX Handler that receives notification of the start of entities
261
    */
262
   public void startEntity(String name) throws SAXException {
263 243 jones
     MetaCatUtil.debugMessage("start ENTITY: " + name);
264
     if (name.equals("[dtd]")) {
265
       processingDTD = true;
266
     }
267 185 jones
   }
268
269
   /**
270
    * SAX Handler that receives notification of the end of entities
271
    */
272
   public void endEntity(String name) throws SAXException {
273 243 jones
     MetaCatUtil.debugMessage("end ENTITY: " + name);
274
     if (name.equals("[dtd]")) {
275
       processingDTD = false;
276
     }
277 185 jones
   }
278 186 jones
279
   /**
280
    * SAX Handler that receives notification of element declarations
281
    */
282
   public void elementDecl(String name, String model)
283
                        throws org.xml.sax.SAXException {
284 243 jones
     MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model);
285 186 jones
   }
286
287
   /**
288
    * SAX Handler that receives notification of attribute declarations
289
    */
290
   public void attributeDecl(String eName, String aName,
291
                        String type, String valueDefault, String value)
292
                        throws org.xml.sax.SAXException {
293 243 jones
     MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " "
294
                        + aName + " " + type + " " + valueDefault + " "
295
                        + value);
296 186 jones
   }
297
298
   /**
299
    * SAX Handler that receives notification of internal entity declarations
300
    */
301
   public void internalEntityDecl(String name, String value)
302
                        throws org.xml.sax.SAXException {
303 243 jones
     MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value);
304 186 jones
   }
305
306
   /**
307
    * SAX Handler that receives notification of external entity declarations
308
    */
309
   public void externalEntityDecl(String name, String publicId,
310
                        String systemId)
311
                        throws org.xml.sax.SAXException {
312 243 jones
     MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
313
                              + " " + systemId);
314 186 jones
   }
315
316 204 jones
   //
317
   // the next section implements the ErrorHandler interface
318
   //
319 186 jones
320 204 jones
   /**
321
    * SAX Handler that receives notification of fatal parsing errors
322
    */
323
   public void fatalError(SAXParseException exception) throws SAXException {
324
     MetaCatUtil.debugMessage("FATALERROR");
325
     throw (new SAXException("Fatal processing error.", exception));
326
   }
327
328
   /**
329
    * SAX Handler that receives notification of recoverable parsing errors
330
    */
331
   public void error(SAXParseException exception) throws SAXException {
332
     MetaCatUtil.debugMessage("ERROR");
333
   }
334
335
   /**
336
    * SAX Handler that receives notification of warnings
337
    */
338
   public void warning(SAXParseException exception) throws SAXException {
339
     MetaCatUtil.debugMessage("FATALERROR");
340
   }
341
342
   //
343
   // Helper, getter and setter methods
344
   //
345
346
   /**
347
    * get the document name
348
    */
349
   public String getDocname() {
350
     return docname;
351
   }
352
353
   /**
354
    * get the document processing state
355
    */
356 243 jones
   public boolean processingDTD() {
357
     return processingDTD;
358 204 jones
   }
359 17 jones
}
360 203 jones
361
/**
362
 * '$Log$
363 313 bojilova
 * 'Revision 1.31  2000/06/29 23:27:08  jones
364
 * 'Fixed bug in DBEntityResolver so that it now properly delegates to
365
 * 'the system id found inthe database.
366
 * 'Changed DBValidate to use DBEntityResolver, rather than the OASIS
367
 * 'catalog, and to return validation results in XML format.
368
 * '
369 243 jones
 * 'Revision 1.30  2000/06/28 03:14:35  jones
370
 * 'Fixed bug where TEXT nodes couldn't be longer than 4000 characters, which
371
 * 'is the maximum length of a VARCHAR2 field in Oracle.  Now, if text
372
 * 'exceeds the field length, I break the text up into a series of TEXT
373
 * 'nodes each of the max field length, and the remainder in the last
374
 * 'TEXT node. The only problem with this is that our current search
375
 * 'algorithms only will find phrases within a single TEXT nodes, so if
376
 * 'the search term spans the node boundary, the search algorithm will not
377
 * 'return a hit. I expect this is extremely rare, basically inconsequential.
378
 * '
379 220 jones
 * 'Revision 1.29  2000/06/27 04:31:07  jones
380
 * 'Fixed bugs associated with the new UPDATE and DELETE functions of
381
 * 'DBWriter.  There were problematic interactions between some static
382
 * 'variables used in DBEntityResolver and the way in which the
383
 * 'Servlet objects are re-used across multiple client invocations.
384
 * '
385
 * 'Generally cleaned up error reporting.  Now all errors and success
386
 * 'results are reported as XML documents from MetaCatServlet.  Need
387
 * 'to make the command line tools do the same.
388
 * '
389 204 jones
 * 'Revision 1.28  2000/06/26 10:35:05  jones
390
 * 'Merged in substantial changes to DBWriter and associated classes and to
391
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
392
 * 'functions.  The command line tools and the parameters for the
393
 * 'servlet have changed substantially.
394
 * '
395 203 jones
 * 'Revision 1.27.2.6  2000/06/26 02:02:20  jones
396
 * 'Continued fixing problems with exception handling that deals
397
 * 'with INSERT and UPDATE actions and the docid passed to DBWriter
398
 * '
399
 * 'Revision 1.27.2.5  2000/06/26 00:51:06  jones
400
 * 'If docid passed to DBWriter.write() is not unique, classes now generate
401
 * 'an AccessionNumberException containing the new docid generated as a
402
 * 'replacement.  The docid is then extracted from the exception and
403
 * 'returned to the calling application for user feedback or client processing.
404
 * '
405
 * 'Revision 1.27.2.4  2000/06/25 23:38:16  jones
406
 * 'Added RCSfile keyword
407
 * '
408
 * 'Revision 1.27.2.3  2000/06/25 23:34:17  jones
409
 * 'Changed documentation formatting, added log entries at bottom of source files
410
 * ''
411
 */