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 349 jones
 *    Release: @release@
9 17 jones
 *
10 203 jones
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13 17 jones
 */
14
15 75 jones
package edu.ucsb.nceas.metacat;
16 51 jones
17 17 jones
import java.sql.*;
18
import java.util.Stack;
19 18 jones
import java.util.EmptyStackException;
20 17 jones
21 185 jones
import org.xml.sax.Attributes;
22
import org.xml.sax.SAXException;
23 204 jones
import org.xml.sax.SAXParseException;
24 186 jones
import org.xml.sax.ext.DeclHandler;
25 185 jones
import org.xml.sax.ext.LexicalHandler;
26
import org.xml.sax.helpers.DefaultHandler;
27 17 jones
28 31 jones
/**
29
 * A database aware Class implementing callback bethods for the SAX parser to
30
 * call when processing the XML stream and generating events
31
 */
32 186 jones
public class DBSAXHandler extends DefaultHandler
33
                          implements LexicalHandler, DeclHandler {
34 17 jones
35 204 jones
   private boolean	atFirstElement;
36 243 jones
   private boolean	processingDTD;
37 204 jones
   private String 	docname = null;
38 135 jones
   private String 	doctype;
39
   private String 	systemid;
40 17 jones
   private boolean 	stackCreated = false;
41 137 jones
   private Stack 	nodeStack;
42 17 jones
   private Connection	conn = null;
43 396 jones
   private DocumentImpl currentDocument;
44 185 jones
   private DBSAXNode    rootNode;
45 203 jones
   private String       action = null;
46
   private String       docid = null;
47 425 bojilova
   private String       user = null;
48 17 jones
49 220 jones
   private static final int MAXDATACHARS = 4000;
50 460 bojilova
   private static final int MAXTITLELEN = 1000;
51 220 jones
52 31 jones
   /** Construct an instance of the handler class
53
    *
54
    * @param conn the JDBC connection to which information is written
55
    */
56 122 jones
   public DBSAXHandler(Connection conn) {
57 185 jones
     this.conn = conn;
58 204 jones
     this.atFirstElement = true;
59 243 jones
     this.processingDTD = false;
60 17 jones
61 185 jones
     // Create the stack for keeping track of node context
62
     // if it doesn't already exist
63
     if (!stackCreated) {
64
       nodeStack = new Stack();
65
       stackCreated = true;
66
     }
67 17 jones
   }
68
69 203 jones
   /** Construct an instance of the handler class
70
    *
71
    * @param conn the JDBC connection to which information is written
72 425 bojilova
    * @param action - "INSERT" or "UPDATE"
73
    * @param docid to be inserted or updated into JDBC connection
74
    * @param user the user connected to MetaCat servlet
75 203 jones
    */
76 425 bojilova
   public DBSAXHandler(Connection conn,String action,String docid,String user)
77
   {
78 203 jones
     this(conn);
79
     this.action = action;
80
     this.docid = docid;
81 425 bojilova
     this.user = user;
82 203 jones
   }
83
84 72 bojilova
   /** SAX Handler that receives notification of beginning of the document */
85 122 jones
   public void startDocument() throws SAXException {
86 203 jones
     MetaCatUtil.debugMessage("start Document");
87
88 185 jones
     // Create the document node representation as root
89 457 bojilova
     rootNode = new DBSAXNode(conn, this.docid);
90 185 jones
     // Add the node to the stack, so that any text data can be
91
     // added as it is encountered
92
     nodeStack.push(rootNode);
93 72 bojilova
   }
94
95
   /** SAX Handler that receives notification of end of the document */
96 122 jones
   public void endDocument() throws SAXException {
97 460 bojilova
// NOT NEEDED ANY MORE - use currentDocument.setTitle() from characters(cbuf,start,end)
98
//     currentDocument.setTitleFromChildElement();
99 203 jones
     MetaCatUtil.debugMessage("end Document");
100 460 bojilova
// NOT NEEDED ANY MORE - Accession# is generated at the very beginning before the parsing
101 457 bojilova
//     if ((docid != null) && (!docid.equals(currentDocument.getDocID()))) {
102
//       throw (new SAXException("New document ID generated:",
103
//           new AccessionNumberGeneratedException(currentDocument.getDocID())));
104
//     } else {
105
//       throw (new SAXException("New document ID generated:",
106
//           new AccessionNumberGeneratedException(currentDocument.getDocID())));
107
//     }
108 72 bojilova
   }
109
110 185 jones
   /** SAX Handler that is called at the start of each XML element */
111
   public void startElement(String uri, String localName,
112
                            String qName, Attributes atts)
113
               throws SAXException {
114 203 jones
     MetaCatUtil.debugMessage("Start ELEMENT " + localName);
115 72 bojilova
116 203 jones
     DBSAXNode parentNode = null;
117
     DBSAXNode currentNode = null;
118 17 jones
119 203 jones
     // Get a reference to the parent node for the id
120
     try {
121
       parentNode = (DBSAXNode)nodeStack.peek();
122
     } catch (EmptyStackException e) {
123 408 jones
       parentNode = null;
124 203 jones
     }
125 18 jones
126 203 jones
     // Document representation that points to the root document node
127 204 jones
     if (atFirstElement) {
128
       atFirstElement = false;
129 203 jones
       // If no DOCTYPE declaration: docname = root element name
130
       if (docname == null) {
131
         docname = localName;
132 204 jones
         doctype = docname;
133
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname);
134
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype);
135 203 jones
       } else if (doctype == null) {
136 204 jones
         doctype = docname;
137
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype);
138 203 jones
       }
139
       rootNode.writeNodename(docname);
140
       try {
141 396 jones
         currentDocument = new DocumentImpl(conn, rootNode.getNodeID(),
142 425 bojilova
                                       docname, doctype, docid, action, user);
143 457 bojilova
       } catch (Exception ane) {
144 408 jones
         throw (new SAXException("Error with " + action, ane));
145
       }
146 457 bojilova
       // not needed any more
147
       //rootNode.writeDocID(currentDocument.getDocID());
148 203 jones
     }
149 135 jones
150 203 jones
     // Create the current node representation
151 457 bojilova
     currentNode = new DBSAXNode(conn, localName, parentNode,
152
                                 currentDocument.getRootNodeID(),docid,
153
                                 currentDocument.getDoctype());
154 460 bojilova
155 203 jones
     // Add all of the attributes
156
     for (int i=0; i<atts.getLength(); i++) {
157 457 bojilova
       currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i), docid);
158 203 jones
     }
159 17 jones
160 203 jones
     // Add the node to the stack, so that any text data can be
161
     // added as it is encountered
162
     nodeStack.push(currentNode);
163
  }
164 17 jones
165 460 bojilova
  /** SAX Handler that is called for each XML text node */
166
  public void characters(char[] cbuf, int start, int len) throws SAXException {
167 203 jones
     MetaCatUtil.debugMessage("CHARACTERS");
168 186 jones
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
169 220 jones
     String data = null;
170
     int leftover = len;
171
     int offset = start;
172
     boolean moredata = true;
173
174
     // This loop deals with the case where there are more characters
175
     // than can fit in a single database text field (limit is
176
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
177
     // write a series of nodes that are MAXDATACHARS long, and then the
178
     // final node contains the remainder
179
     while (moredata) {
180
       if (leftover > MAXDATACHARS) {
181
         data = new String(cbuf, offset, MAXDATACHARS);
182
         leftover -= MAXDATACHARS;
183
         offset += MAXDATACHARS;
184
       } else {
185
         data = new String(cbuf, offset, leftover);
186
         moredata = false;
187
       }
188 122 jones
189 220 jones
       // Write the content of the node to the database
190 457 bojilova
       currentNode.writeChildNodeToDB("TEXT", null, data, docid);
191 220 jones
     }
192 460 bojilova
193
     // write the title of document if there are tag <title>
194
     if ( currentNode.getTagName().equals("title") ) {
195
       if ( leftover > MAXTITLELEN )
196
         currentDocument.setTitle(new String(cbuf, start, MAXTITLELEN));
197
       else
198
         currentDocument.setTitle(new String(cbuf, start, leftover));
199
     }
200
201 17 jones
   }
202
203 31 jones
   /**
204
    * SAX Handler that is called for each XML text node that is Ignorable
205
    * white space
206
    */
207 122 jones
   public void ignorableWhitespace(char[] cbuf, int start, int len) {
208 203 jones
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE");
209 17 jones
   }
210
211 122 jones
   /**
212
    * SAX Handler called once for each processing instruction found:
213
    * node that PI may occur before or after the root element.
214
    */
215
   public void processingInstruction(String target, String data)
216
          throws SAXException {
217 203 jones
     MetaCatUtil.debugMessage("PI");
218 186 jones
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
219 457 bojilova
     currentNode.writeChildNodeToDB("PI", target, data, docid);
220 92 bojilova
   }
221 72 bojilova
222 31 jones
   /** SAX Handler that is called at the end of each XML element */
223 185 jones
   public void endElement(String uri, String localName,
224
                          String qName) throws SAXException {
225 203 jones
     MetaCatUtil.debugMessage("End ELEMENT " + localName);
226 17 jones
227 185 jones
     // Get the node from the stack
228
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
229 17 jones
   }
230
231 185 jones
   //
232
   // the next section implements the LexicalHandler interface
233
   //
234
235
   /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
236
   public void startDTD(String name, String publicId, String systemId)
237
               throws SAXException {
238
     docname = name;
239
     doctype = publicId;
240
     systemid = systemId;
241
242 204 jones
     MetaCatUtil.debugMessage("Start DTD");
243 203 jones
     MetaCatUtil.debugMessage("DOCNAME: " + docname);
244
     MetaCatUtil.debugMessage("DOCTYPE: " + doctype);
245
     MetaCatUtil.debugMessage("  SYSID: " + systemid);
246 185 jones
   }
247
248
   /**
249
    * SAX Handler that receives notification of end of DTD
250
    */
251
   public void endDTD() throws SAXException {
252 204 jones
     MetaCatUtil.debugMessage("end DTD");
253 185 jones
   }
254
255
   /**
256
    * SAX Handler that receives notification of comments in the DTD
257
    */
258
   public void comment(char[] ch, int start, int length) throws SAXException {
259 203 jones
     MetaCatUtil.debugMessage("COMMENT");
260 186 jones
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
261 457 bojilova
     currentNode.writeChildNodeToDB("COMMENT", null, new String(ch), docid);
262 185 jones
   }
263
264
   /**
265
    * SAX Handler that receives notification of the start of CDATA sections
266
    */
267
   public void startCDATA() throws SAXException {
268 203 jones
     MetaCatUtil.debugMessage("start CDATA");
269 185 jones
   }
270
271
   /**
272
    * SAX Handler that receives notification of the end of CDATA sections
273
    */
274
   public void endCDATA() throws SAXException {
275 203 jones
     MetaCatUtil.debugMessage("end CDATA");
276 185 jones
   }
277
278
   /**
279
    * SAX Handler that receives notification of the start of entities
280
    */
281
   public void startEntity(String name) throws SAXException {
282 243 jones
     MetaCatUtil.debugMessage("start ENTITY: " + name);
283
     if (name.equals("[dtd]")) {
284
       processingDTD = true;
285
     }
286 185 jones
   }
287
288
   /**
289
    * SAX Handler that receives notification of the end of entities
290
    */
291
   public void endEntity(String name) throws SAXException {
292 243 jones
     MetaCatUtil.debugMessage("end ENTITY: " + name);
293
     if (name.equals("[dtd]")) {
294
       processingDTD = false;
295
     }
296 185 jones
   }
297 186 jones
298
   /**
299
    * SAX Handler that receives notification of element declarations
300
    */
301
   public void elementDecl(String name, String model)
302
                        throws org.xml.sax.SAXException {
303 243 jones
     MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model);
304 186 jones
   }
305
306
   /**
307
    * SAX Handler that receives notification of attribute declarations
308
    */
309
   public void attributeDecl(String eName, String aName,
310
                        String type, String valueDefault, String value)
311
                        throws org.xml.sax.SAXException {
312 243 jones
     MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " "
313
                        + aName + " " + type + " " + valueDefault + " "
314
                        + value);
315 186 jones
   }
316
317
   /**
318
    * SAX Handler that receives notification of internal entity declarations
319
    */
320
   public void internalEntityDecl(String name, String value)
321
                        throws org.xml.sax.SAXException {
322 243 jones
     MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value);
323 186 jones
   }
324
325
   /**
326
    * SAX Handler that receives notification of external entity declarations
327
    */
328
   public void externalEntityDecl(String name, String publicId,
329
                        String systemId)
330
                        throws org.xml.sax.SAXException {
331 243 jones
     MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
332
                              + " " + systemId);
333 186 jones
   }
334
335 204 jones
   //
336
   // the next section implements the ErrorHandler interface
337
   //
338 186 jones
339 204 jones
   /**
340
    * SAX Handler that receives notification of fatal parsing errors
341
    */
342
   public void fatalError(SAXParseException exception) throws SAXException {
343
     MetaCatUtil.debugMessage("FATALERROR");
344
     throw (new SAXException("Fatal processing error.", exception));
345
   }
346
347
   /**
348
    * SAX Handler that receives notification of recoverable parsing errors
349
    */
350
   public void error(SAXParseException exception) throws SAXException {
351
     MetaCatUtil.debugMessage("ERROR");
352
   }
353
354
   /**
355
    * SAX Handler that receives notification of warnings
356
    */
357
   public void warning(SAXParseException exception) throws SAXException {
358
     MetaCatUtil.debugMessage("FATALERROR");
359
   }
360
361
   //
362
   // Helper, getter and setter methods
363
   //
364
365
   /**
366
    * get the document name
367
    */
368
   public String getDocname() {
369
     return docname;
370
   }
371
372
   /**
373
    * get the document processing state
374
    */
375 243 jones
   public boolean processingDTD() {
376
     return processingDTD;
377 204 jones
   }
378 17 jones
}