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