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