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
 *    Release: @release@
9
 *
10
 *   '$Author: bojilova $'
11
 *     '$Date: 2000-08-31 17:01:30 -0700 (Thu, 31 Aug 2000) $'
12
 * '$Revision: 425 $'
13
 */
14

    
15
package edu.ucsb.nceas.metacat;
16

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

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

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

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

    
49
   private static final int MAXDATACHARS = 4000;
50

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

    
60
     // 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
   }
67
 
68
   /** Construct an instance of the handler class 
69
    *
70
    * @param conn the JDBC connection to which information is written
71
    * @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
    */
75
   public DBSAXHandler(Connection conn,String action,String docid,String user)
76
   {
77
     this(conn);
78
     this.action = action;
79
     this.docid = docid;
80
     this.user = user;
81
   }
82

    
83
   /** SAX Handler that receives notification of beginning of the document */
84
   public void startDocument() throws SAXException {
85
     MetaCatUtil.debugMessage("start Document");
86

    
87
     // Create the document node representation as root
88
     rootNode = new DBSAXNode(conn);
89
     // Add the node to the stack, so that any text data can be 
90
     // added as it is encountered
91
     nodeStack.push(rootNode);
92
   }
93

    
94
   /** SAX Handler that receives notification of end of the document */
95
   public void endDocument() throws SAXException {
96
     currentDocument.setTitleFromChildElement();
97
     MetaCatUtil.debugMessage("end Document");
98
     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
   }
106

    
107
   /** 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
     MetaCatUtil.debugMessage("Start ELEMENT " + localName);
112

    
113
     DBSAXNode parentNode = null;
114
     DBSAXNode currentNode = null;
115

    
116
     // Get a reference to the parent node for the id
117
     try {
118
       parentNode = (DBSAXNode)nodeStack.peek();
119
     } catch (EmptyStackException e) {
120
       parentNode = null;
121
     }
122

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

    
146
     // Create the current node representation
147
     currentNode = new DBSAXNode(conn, localName, parentNode, currentDocument);
148

    
149
     // Add all of the attributes
150
     for (int i=0; i<atts.getLength(); i++) {
151
       currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
152
     }      
153

    
154
     // Add the node to the stack, so that any text data can be 
155
     // added as it is encountered
156
     nodeStack.push(currentNode);
157
  }
158

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

    
183
       // Write the content of the node to the database
184
       currentNode.writeChildNodeToDB("TEXT", null, data);
185
     }
186
   }
187

    
188
   /** 
189
    * SAX Handler that is called for each XML text node that is Ignorable
190
    * white space
191
    */
192
   public void ignorableWhitespace(char[] cbuf, int start, int len) {
193
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE");
194
   }
195

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

    
207
   /** SAX Handler that is called at the end of each XML element */
208
   public void endElement(String uri, String localName,
209
                          String qName) throws SAXException {
210
     MetaCatUtil.debugMessage("End ELEMENT " + localName);
211

    
212
     // Get the node from the stack
213
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
214
   }
215

    
216
   //
217
   // the next section implements the LexicalHandler interface
218
   //
219

    
220
   /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
221
   public void startDTD(String name, String publicId, String systemId) 
222
               throws SAXException {
223
     docname = name;
224
     doctype = publicId;
225
     systemid = systemId;
226

    
227
     MetaCatUtil.debugMessage("Start DTD");
228
     MetaCatUtil.debugMessage("DOCNAME: " + docname);
229
     MetaCatUtil.debugMessage("DOCTYPE: " + doctype);
230
     MetaCatUtil.debugMessage("  SYSID: " + systemid);
231
   }
232

    
233
   /** 
234
    * SAX Handler that receives notification of end of DTD 
235
    */
236
   public void endDTD() throws SAXException {
237
     MetaCatUtil.debugMessage("end DTD");
238
   }
239

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

    
249
   /** 
250
    * SAX Handler that receives notification of the start of CDATA sections
251
    */
252
   public void startCDATA() throws SAXException {
253
     MetaCatUtil.debugMessage("start CDATA");
254
   }
255

    
256
   /** 
257
    * SAX Handler that receives notification of the end of CDATA sections
258
    */
259
   public void endCDATA() throws SAXException {
260
     MetaCatUtil.debugMessage("end CDATA");
261
   }
262

    
263
   /** 
264
    * SAX Handler that receives notification of the start of entities
265
    */
266
   public void startEntity(String name) throws SAXException {
267
     MetaCatUtil.debugMessage("start ENTITY: " + name);
268
     if (name.equals("[dtd]")) {
269
       processingDTD = true;
270
     }
271
   }
272

    
273
   /** 
274
    * SAX Handler that receives notification of the end of entities
275
    */
276
   public void endEntity(String name) throws SAXException {
277
     MetaCatUtil.debugMessage("end ENTITY: " + name);
278
     if (name.equals("[dtd]")) {
279
       processingDTD = false;
280
     }
281
   }
282

    
283
   /** 
284
    * SAX Handler that receives notification of element declarations
285
    */
286
   public void elementDecl(String name, String model)
287
                        throws org.xml.sax.SAXException {
288
     MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model);
289
   }
290

    
291
   /** 
292
    * SAX Handler that receives notification of attribute declarations
293
    */
294
   public void attributeDecl(String eName, String aName,
295
                        String type, String valueDefault, String value)
296
                        throws org.xml.sax.SAXException {
297
     MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " " 
298
                        + aName + " " + type + " " + valueDefault + " "
299
                        + value);
300
   }
301

    
302
   /** 
303
    * SAX Handler that receives notification of internal entity declarations
304
    */
305
   public void internalEntityDecl(String name, String value)
306
                        throws org.xml.sax.SAXException {
307
     MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value);
308
   }
309

    
310
   /** 
311
    * SAX Handler that receives notification of external entity declarations
312
    */
313
   public void externalEntityDecl(String name, String publicId,
314
                        String systemId)
315
                        throws org.xml.sax.SAXException {
316
     MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId 
317
                              + " " + systemId);
318
   }
319

    
320
   //
321
   // the next section implements the ErrorHandler interface
322
   //
323

    
324
   /** 
325
    * SAX Handler that receives notification of fatal parsing errors
326
    */
327
   public void fatalError(SAXParseException exception) throws SAXException {
328
     MetaCatUtil.debugMessage("FATALERROR");
329
     throw (new SAXException("Fatal processing error.", exception));
330
   }
331

    
332
   /** 
333
    * SAX Handler that receives notification of recoverable parsing errors
334
    */
335
   public void error(SAXParseException exception) throws SAXException {
336
     MetaCatUtil.debugMessage("ERROR");
337
   }
338

    
339
   /** 
340
    * SAX Handler that receives notification of warnings
341
    */
342
   public void warning(SAXParseException exception) throws SAXException {
343
     MetaCatUtil.debugMessage("FATALERROR");
344
   }
345

    
346
   // 
347
   // Helper, getter and setter methods
348
   //
349
   
350
   /**
351
    * get the document name
352
    */
353
   public String getDocname() {
354
     return docname;
355
   }
356

    
357
   /**
358
    * get the document processing state
359
    */
360
   public boolean processingDTD() {
361
     return processingDTD;
362
   }
363
}
(9-9/27)