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