Project

General

Profile

1
/**
2
 *  '$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
 *
9
 *   '$Author: jones $'
10
 *     '$Date: 2000-06-27 20:14:35 -0700 (Tue, 27 Jun 2000) $'
11
 * '$Revision: 220 $'
12
 */
13

    
14
package edu.ucsb.nceas.metacat;
15

    
16
import java.sql.*;
17
import java.util.Stack;
18
import java.util.EmptyStackException;
19

    
20
import org.xml.sax.Attributes;
21
import org.xml.sax.SAXException;
22
import org.xml.sax.SAXParseException;
23
import org.xml.sax.ext.DeclHandler;
24
import org.xml.sax.ext.LexicalHandler;
25
import org.xml.sax.helpers.DefaultHandler;
26

    
27
/** 
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
public class DBSAXHandler extends DefaultHandler 
32
                          implements LexicalHandler, DeclHandler {
33

    
34
   private boolean	atFirstElement;
35
   private String 	docname = null;
36
   private String 	doctype;
37
   private String 	systemid;
38
   private boolean 	stackCreated = false;
39
   private Stack 	nodeStack;
40
   private Connection	conn = null;
41
   private DBSAXDocument currentDocument;
42
   private DBSAXNode    rootNode;
43
   private String       action = null;
44
   private String       docid = null;
45

    
46
   private static final int MAXDATACHARS = 4000;
47

    
48
   /** Construct an instance of the handler class 
49
    *
50
    * @param conn the JDBC connection to which information is written
51
    */
52
   public DBSAXHandler(Connection conn) {
53
     this.conn = conn;
54
     this.atFirstElement = true;
55

    
56
     // Create the stack for keeping track of node context
57
     // if it doesn't already exist
58
     if (!stackCreated) {
59
       nodeStack = new Stack();
60
       stackCreated = true;
61
     }
62
   }
63
 
64
   /** Construct an instance of the handler class 
65
    *
66
    * @param conn the JDBC connection to which information is written
67
    */
68
   public DBSAXHandler(Connection conn, String action, String docid) {
69
     this(conn);
70
     this.action = action;
71
     this.docid = docid;
72
   }
73

    
74
   /** SAX Handler that receives notification of beginning of the document */
75
   public void startDocument() throws SAXException {
76
     MetaCatUtil.debugMessage("start Document");
77

    
78
     // Create the document node representation as root
79
     rootNode = new DBSAXNode(conn, docname);
80
     MetaCatUtil.debugMessage("PRINTING DOCNAME FROM ROOTNODE: " + 
81
                               rootNode.getTagName());
82
     // Add the node to the stack, so that any text data can be 
83
     // added as it is encountered
84
     nodeStack.push(rootNode);
85
   }
86

    
87
   /** SAX Handler that receives notification of end of the document */
88
   public void endDocument() throws SAXException {
89
     currentDocument.setTitleFromChildElement();
90
     MetaCatUtil.debugMessage("end Document");
91
     if ((docid != null) && (!docid.equals(currentDocument.getDocID()))) {
92
       throw (new SAXException("New document ID generated:",
93
           new AccessionNumberGeneratedException(currentDocument.getDocID())));
94
     } else {
95
       throw (new SAXException("New document ID generated:",
96
           new AccessionNumberGeneratedException(currentDocument.getDocID())));
97
     }
98
   }
99

    
100
   /** SAX Handler that is called at the start of each XML element */
101
   public void startElement(String uri, String localName,
102
                            String qName, Attributes atts) 
103
               throws SAXException {
104
     MetaCatUtil.debugMessage("Start ELEMENT " + localName);
105

    
106
     DBSAXNode parentNode = null;
107
     DBSAXNode currentNode = null;
108

    
109
     // Get a reference to the parent node for the id
110
     try {
111
       parentNode = (DBSAXNode)nodeStack.peek();
112
     } catch (EmptyStackException e) {
113
     }
114

    
115
     // Document representation that points to the root document node
116
     if (atFirstElement) {
117
       atFirstElement = false;
118
       // If no DOCTYPE declaration: docname = root element name 
119
       if (docname == null) {
120
         docname = localName;
121
         doctype = docname;
122
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname);
123
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype);
124
       } else if (doctype == null) {
125
         doctype = docname;
126
         //doctype = DBEntityResolver.doctype;
127
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype);
128
       }
129
       rootNode.writeNodename(docname);
130
       rootNode.writeRootNodeID(rootNode.getNodeID());
131
       try {
132
         currentDocument = new DBSAXDocument(conn, rootNode.getNodeID(), 
133
                                           docname, doctype, docid, action);
134
         } catch (AccessionNumberException ane) {
135
           throw (new SAXException("Error with " + action, ane));
136
         }
137
       rootNode.writeDocID(currentDocument.getDocID());
138
     }      
139

    
140
     // Create the current node representation
141
     currentNode = new DBSAXNode(conn, localName, parentNode, 
142
                                 rootNode, currentDocument);
143

    
144
     // Add all of the attributes
145
     for (int i=0; i<atts.getLength(); i++) {
146
       currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
147
     }      
148

    
149
     // Add the node to the stack, so that any text data can be 
150
     // added as it is encountered
151
     nodeStack.push(currentNode);
152
  }
153

    
154
   /** SAX Handler that is called for each XML text node */
155
   public void characters(char[] cbuf, int start, int len) {
156
     MetaCatUtil.debugMessage("CHARACTERS");
157
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
158
     String data = null;
159
     int leftover = len;
160
     int offset = start;
161
     boolean moredata = true;
162
    
163
     // This loop deals with the case where there are more characters 
164
     // than can fit in a single database text field (limit is 
165
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
166
     // write a series of nodes that are MAXDATACHARS long, and then the
167
     // final node contains the remainder
168
     while (moredata) {
169
       if (leftover > MAXDATACHARS) {
170
         data = new String(cbuf, offset, MAXDATACHARS);
171
         leftover -= MAXDATACHARS;
172
         offset += MAXDATACHARS;
173
       } else {
174
         data = new String(cbuf, offset, leftover);
175
         moredata = false;
176
       }
177

    
178
       // Write the content of the node to the database
179
       currentNode.writeChildNodeToDB("TEXT", null, data);
180
     }
181
   }
182

    
183
   /** 
184
    * SAX Handler that is called for each XML text node that is Ignorable
185
    * white space
186
    */
187
   public void ignorableWhitespace(char[] cbuf, int start, int len) {
188
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE");
189
   }
190

    
191
   /** 
192
    * SAX Handler called once for each processing instruction found: 
193
    * node that PI may occur before or after the root element.
194
    */
195
   public void processingInstruction(String target, String data) 
196
          throws SAXException {
197
     MetaCatUtil.debugMessage("PI");
198
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
199
     currentNode.writeChildNodeToDB("PI", target, data);
200
   }
201

    
202
   /** SAX Handler that is called at the end of each XML element */
203
   public void endElement(String uri, String localName,
204
                          String qName) throws SAXException {
205
     MetaCatUtil.debugMessage("End ELEMENT " + localName);
206

    
207
     // Get the node from the stack
208
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
209
   }
210

    
211
   //
212
   // the next section implements the LexicalHandler interface
213
   //
214

    
215
   /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
216
   public void startDTD(String name, String publicId, String systemId) 
217
               throws SAXException {
218
     docname = name;
219
     doctype = publicId;
220
     systemid = systemId;
221

    
222
     MetaCatUtil.debugMessage("Start DTD");
223
     MetaCatUtil.debugMessage("DOCNAME: " + docname);
224
     MetaCatUtil.debugMessage("DOCTYPE: " + doctype);
225
     MetaCatUtil.debugMessage("  SYSID: " + systemid);
226
   }
227

    
228
   /** 
229
    * SAX Handler that receives notification of end of DTD 
230
    */
231
   public void endDTD() throws SAXException {
232
     MetaCatUtil.debugMessage("end DTD");
233
   }
234

    
235
   /** 
236
    * SAX Handler that receives notification of comments in the DTD
237
    */
238
   public void comment(char[] ch, int start, int length) throws SAXException {
239
     MetaCatUtil.debugMessage("COMMENT");
240
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
241
     currentNode.writeChildNodeToDB("COMMENT", null, new String(ch));
242
   }
243

    
244
   /** 
245
    * SAX Handler that receives notification of the start of CDATA sections
246
    */
247
   public void startCDATA() throws SAXException {
248
     MetaCatUtil.debugMessage("start CDATA");
249
   }
250

    
251
   /** 
252
    * SAX Handler that receives notification of the end of CDATA sections
253
    */
254
   public void endCDATA() throws SAXException {
255
     MetaCatUtil.debugMessage("end CDATA");
256
   }
257

    
258
   /** 
259
    * SAX Handler that receives notification of the start of entities
260
    */
261
   public void startEntity(String name) throws SAXException {
262
     MetaCatUtil.debugMessage("start ENTITY");
263
   }
264

    
265
   /** 
266
    * SAX Handler that receives notification of the end of entities
267
    */
268
   public void endEntity(String name) throws SAXException {
269
     MetaCatUtil.debugMessage("end ENTITY");
270
   }
271

    
272
   /** 
273
    * SAX Handler that receives notification of element declarations
274
    */
275
   public void elementDecl(String name, String model)
276
                        throws org.xml.sax.SAXException {
277
     MetaCatUtil.debugMessage("ELEMENTDECL");
278
   }
279

    
280
   /** 
281
    * SAX Handler that receives notification of attribute declarations
282
    */
283
   public void attributeDecl(String eName, String aName,
284
                        String type, String valueDefault, String value)
285
                        throws org.xml.sax.SAXException {
286
     MetaCatUtil.debugMessage("ATTRIBUTEDECL");
287
   }
288

    
289
   /** 
290
    * SAX Handler that receives notification of internal entity declarations
291
    */
292
   public void internalEntityDecl(String name, String value)
293
                        throws org.xml.sax.SAXException {
294
     MetaCatUtil.debugMessage("INTERNENTITYDECL");
295
   }
296

    
297
   /** 
298
    * SAX Handler that receives notification of external entity declarations
299
    */
300
   public void externalEntityDecl(String name, String publicId,
301
                        String systemId)
302
                        throws org.xml.sax.SAXException {
303
     MetaCatUtil.debugMessage("EXTERNENTITYDECL");
304
   }
305

    
306
   //
307
   // the next section implements the ErrorHandler interface
308
   //
309

    
310
   /** 
311
    * SAX Handler that receives notification of fatal parsing errors
312
    */
313
   public void fatalError(SAXParseException exception) throws SAXException {
314
     MetaCatUtil.debugMessage("FATALERROR");
315
     throw (new SAXException("Fatal processing error.", exception));
316
   }
317

    
318
   /** 
319
    * SAX Handler that receives notification of recoverable parsing errors
320
    */
321
   public void error(SAXParseException exception) throws SAXException {
322
     MetaCatUtil.debugMessage("ERROR");
323
   }
324

    
325
   /** 
326
    * SAX Handler that receives notification of warnings
327
    */
328
   public void warning(SAXParseException exception) throws SAXException {
329
     MetaCatUtil.debugMessage("FATALERROR");
330
   }
331

    
332
   // 
333
   // Helper, getter and setter methods
334
   //
335
   
336
   /**
337
    * get the document name
338
    */
339
   public String getDocname() {
340
     return docname;
341
   }
342

    
343
   /**
344
    * get the document processing state
345
    */
346
   public boolean atFirstElement() {
347
     return atFirstElement;
348
   }
349
}
350

    
351
/**
352
 * '$Log$
353
 * 'Revision 1.29  2000/06/27 04:31:07  jones
354
 * 'Fixed bugs associated with the new UPDATE and DELETE functions of
355
 * 'DBWriter.  There were problematic interactions between some static
356
 * 'variables used in DBEntityResolver and the way in which the
357
 * 'Servlet objects are re-used across multiple client invocations.
358
 * '
359
 * 'Generally cleaned up error reporting.  Now all errors and success
360
 * 'results are reported as XML documents from MetaCatServlet.  Need
361
 * 'to make the command line tools do the same.
362
 * '
363
 * 'Revision 1.28  2000/06/26 10:35:05  jones
364
 * 'Merged in substantial changes to DBWriter and associated classes and to
365
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
366
 * 'functions.  The command line tools and the parameters for the
367
 * 'servlet have changed substantially.
368
 * '
369
 * 'Revision 1.27.2.6  2000/06/26 02:02:20  jones
370
 * 'Continued fixing problems with exception handling that deals
371
 * 'with INSERT and UPDATE actions and the docid passed to DBWriter
372
 * '
373
 * 'Revision 1.27.2.5  2000/06/26 00:51:06  jones
374
 * 'If docid passed to DBWriter.write() is not unique, classes now generate
375
 * 'an AccessionNumberException containing the new docid generated as a
376
 * 'replacement.  The docid is then extracted from the exception and
377
 * 'returned to the calling application for user feedback or client processing.
378
 * '
379
 * 'Revision 1.27.2.4  2000/06/25 23:38:16  jones
380
 * 'Added RCSfile keyword
381
 * '
382
 * 'Revision 1.27.2.3  2000/06/25 23:34:17  jones
383
 * 'Changed documentation formatting, added log entries at bottom of source files
384
 * ''
385
 */
(11-11/24)