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: tao $'
11
 *     '$Date: 2003-02-04 18:08:25 -0800 (Tue, 04 Feb 2003) $'
12
 * '$Revision: 1389 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31
import java.sql.*;
32
import java.io.StringReader;
33
import java.util.Stack;
34
import java.util.Vector;
35
import java.util.Hashtable;
36
import java.util.Enumeration;
37
import java.util.EmptyStackException;
38

    
39
import org.xml.sax.Attributes;
40
import org.xml.sax.SAXException;
41
import org.xml.sax.SAXParseException;
42
import org.xml.sax.ext.DeclHandler;
43
import org.xml.sax.ext.LexicalHandler;
44
import org.xml.sax.helpers.DefaultHandler;
45

    
46
/**
47
 * A database aware Class implementing callback bethods for the SAX parser to
48
 * call when processing the XML stream and generating events
49
 */
50
public class DBSAXHandler extends DefaultHandler
51
                          implements LexicalHandler, DeclHandler, Runnable {
52

    
53
   private boolean	atFirstElement;
54
   private boolean	processingDTD;
55
   private String 	docname = null;
56
   private String 	doctype;
57
   private String 	systemid;
58
   private boolean 	stackCreated = false;
59
   private Stack 	  nodeStack;
60
   private Vector   nodeIndex;
61
   private DBConnection	  connection = null;
62
   private DocumentImpl currentDocument;
63
   private DBSAXNode    rootNode;
64
   private String   action = null;
65
   private String   docid = null;
66
   private String   revision = null;
67
   private String   user = null;
68
   private String[] groups = null;
69
   private String   pub = null;
70
   private Thread   xmlIndex;
71
   private boolean endDocument = false;
72
   private int serverCode = 1;
73
   private Hashtable namespaces = new Hashtable();
74

    
75
   private static final int MAXDATACHARS = 4000;
76
// DOCTITLE attr cleared from the db
77
//   private static final int MAXTITLELEN = 1000;
78

    
79
   /** Construct an instance of the handler class
80
    *
81
    * @param conn the JDBC connection to which information is written
82
    */
83
   public DBSAXHandler(DBConnection conn) {
84
     this.connection = conn;
85
     this.atFirstElement = true;
86
     this.processingDTD = false;
87

    
88
     // Create the stack for keeping track of node context
89
     // if it doesn't already exist
90
     if (!stackCreated) {
91
       nodeStack = new Stack();
92
       nodeIndex = new Vector();
93
       stackCreated = true;
94
     }
95
   }
96

    
97
  /** Construct an instance of the handler class
98
    *
99
    * @param conn the JDBC connection to which information is written
100
    * @param action - "INSERT" or "UPDATE"
101
    * @param docid to be inserted or updated into JDBC connection
102
    * @param user the user connected to MetaCat servlet and owns the document
103
    * @param groups the groups to which user belongs
104
    * @param pub flag for public "read" access on document
105
    * @param serverCode the serverid from xml_replication on which this document
106
    *        resides.
107
    *
108
    */
109
   public DBSAXHandler(DBConnection conn, String action, String docid,
110
                      String user, String[] groups, String pub, int serverCode)
111
   {
112
     this(conn);
113
     this.action = action;
114
     this.docid = docid;
115
     this.user = user;
116
     this.groups = groups;
117
     this.pub = pub;
118
     this.serverCode = serverCode;
119
     this.xmlIndex = new Thread(this);
120
   }
121

    
122
  /** Construct an instance of the handler class
123
    * In this constructor, user can specify the version need to upadate
124
    *
125
    * @param conn the JDBC connection to which information is written
126
    * @param action - "INSERT" or "UPDATE"
127
    * @param docid to be inserted or updated into JDBC connection
128
    * @param revision, the user specified the revision need to be update
129
    * @param user the user connected to MetaCat servlet and owns the document
130
    * @param groups the groups to which user belongs
131
    * @param pub flag for public "read" access on document
132
    * @param serverCode the serverid from xml_replication on which this document
133
    *        resides.
134
    *
135
    */
136
   public DBSAXHandler(DBConnection conn, String action, String docid,
137
     String revision, String user, String[] groups, String pub, int serverCode)
138
   {
139
     this(conn);
140
     this.action = action;
141
     this.docid = docid;
142
     this.revision = revision;
143
     this.user = user;
144
     this.groups = groups;
145
     this.pub = pub;
146
     this.serverCode = serverCode;
147
     this.xmlIndex = new Thread(this);
148
   }
149

    
150
   /** SAX Handler that receives notification of beginning of the document */
151
   public void startDocument() throws SAXException {
152
     MetaCatUtil.debugMessage("start Document", 50);
153

    
154
     // Create the document node representation as root
155
     rootNode = new DBSAXNode(connection, this.docid);
156
     // Add the node to the stack, so that any text data can be
157
     // added as it is encountered
158
     nodeStack.push(rootNode);
159
   }
160

    
161
   /** SAX Handler that receives notification of end of the document */
162
   public void endDocument() throws SAXException {
163
     MetaCatUtil.debugMessage("end Document", 50);
164
     // Starting new thread for writing XML Index.
165
     // It calls the run method of the thread.
166
     try {
167
       xmlIndex.start();
168
     } catch (NullPointerException e) {
169
       xmlIndex = null;
170
       throw new
171
       SAXException("Problem with starting thread for writing XML Index. " +
172
                    e.getMessage());
173
     }
174
   }
175

    
176
   /** SAX Handler that is called at the start of Namespace */
177
   public void startPrefixMapping(String prefix, String uri)
178
                                          throws SAXException
179
   {
180
    MetaCatUtil.debugMessage("NAMESPACE", 50);
181

    
182
    namespaces.put(prefix, uri);
183
   }
184

    
185
   /** SAX Handler that is called at the start of each XML element */
186
   public void startElement(String uri, String localName,
187
                            String qName, Attributes atts)
188
               throws SAXException {
189
     // for element <eml:eml...> qname is "eml:eml", local name is "eml"            
190
     // for element <acl....> both qname and local name is "eml"
191
     // uri is namesapce
192
     MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
193
     MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
194
     MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
195
     
196
     
197
     DBSAXNode parentNode = null;
198
     DBSAXNode currentNode = null;
199

    
200
     // Get a reference to the parent node for the id
201
     try {
202
       parentNode = (DBSAXNode)nodeStack.peek();
203
     } catch (EmptyStackException e) {
204
       parentNode = null;
205
     }
206

    
207
     // Document representation that points to the root document node
208
     if (atFirstElement) 
209
     {
210
       atFirstElement = false;
211
       // If no DOCTYPE declaration: docname = root element
212
       // doctype = root element name or name space
213
       if (docname == null) 
214
       {
215
         docname = localName;
216
         // if uri isn't null doctype = uri(namespace)
217
         // othewise root element
218
         if (uri != null && !(uri.trim()).equals(""))
219
         {
220
           doctype = uri;
221
         }
222
         else
223
         {
224
           doctype = docname;
225
         }
226
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
227
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
228
       } 
229
       else if (doctype == null) 
230
       {
231
         // because docname is not null and it is declared in dtd
232
         // so could not be in schema, no namespace
233
         doctype = docname;
234
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
235
       }
236
       rootNode.writeNodename(docname);
237
       try {
238
         // for validated XML Documents store a reference to XML DB Catalog
239
         // Because this is select statement and it needn't to roll back if
240
         // insert document action fialed.
241
         // In order to decrease DBConnection usage count, we get a new
242
         // dbconnection from pool
243
         String catalogid = null;
244
         DBConnection dbConn = null;
245
         int serialNumber = -1;
246

    
247
         if ( systemid != null ) {
248
           try
249
           {
250
            // Get dbconnection
251
            dbConn=DBConnectionPool.getDBConnection
252
                                          ("DBSAXHandler.startElement");
253
            serialNumber=dbConn.getCheckOutSerialNumber();
254

    
255
            Statement stmt = dbConn.createStatement();
256
            ResultSet rs = stmt.executeQuery(
257
                          "SELECT catalog_id FROM xml_catalog " +
258
                          "WHERE entry_type = 'DTD' " +
259
                          "AND public_id = '" + doctype + "'");
260
            boolean hasRow = rs.next();
261
            if ( hasRow ) {
262
              catalogid = rs.getString(1);
263
            }
264
            stmt.close();
265
           }//try
266
           finally
267
           {
268
             // Return dbconnection
269
             DBConnectionPool.returnDBConnection(dbConn, serialNumber);
270
           }//finally
271
         }
272

    
273
         //create documentImpl object by the constructor which can specify
274
         //the revision
275
         currentDocument = new DocumentImpl(connection, rootNode.getNodeID(),
276
                               docname, doctype, docid, revision, action, user,
277
                               this.pub, catalogid, this.serverCode);
278

    
279

    
280
       } catch (Exception ane) {
281
         throw (new SAXException("Error in DBSaxHandler.startElement " +
282
                                 action, ane));
283
       }
284
     }
285

    
286
     // Create the current node representation
287
     currentNode = new DBSAXNode(connection, qName, localName, parentNode,
288
                                 currentDocument.getRootNodeID(),docid,
289
                                 currentDocument.getDoctype());
290

    
291
     // Add all of the namespaces
292
     String prefix;
293
     String nsuri;
294
     Enumeration prefixes = namespaces.keys();
295
     while ( prefixes.hasMoreElements() ) {
296
       prefix = (String)prefixes.nextElement();
297
       nsuri = (String)namespaces.get(prefix);
298
       currentNode.setNamespace(prefix, nsuri, docid);
299
     }
300
     namespaces = null;
301
     namespaces = new Hashtable();
302

    
303
     // Add all of the attributes
304
     for (int i=0; i<atts.getLength(); i++) {
305
       currentNode.setAttribute(atts.getQName(i), atts.getValue(i), docid);
306
     }
307

    
308
     // Add the node to the stack, so that any text data can be
309
     // added as it is encountered
310
     nodeStack.push(currentNode);
311
     // Add the node to the vector used by thread for writing XML Index
312
     nodeIndex.addElement(currentNode);
313

    
314
  }
315

    
316
  /* The run method of xmlIndex thread. It writes XML Index for the document. */
317
  public void run () {
318
    DBSAXNode currNode = null;
319
    DBSAXNode prevNode = null;
320
    DBConnection dbConn = null;
321
    int serialNumber = -1;
322
    String doctype = currentDocument.getDoctype();
323
    int step = 0;
324
    int counter = 0;
325

    
326
    try {
327

    
328
      // Opening separate db connection for writing XML Index
329
      dbConn=DBConnectionPool.getDBConnection("DBSAXHandler.run");
330
      serialNumber=dbConn.getCheckOutSerialNumber();
331
      dbConn.setAutoCommit(false);
332

    
333
      //the following while loop construct checks to make sure that the docid
334
      //of the document that we are trying to index is already
335
      //in the xml_documents table.  if this is not the case, the foreign
336
      //key relationship between xml_documents and xml_index is temporarily
337
      //broken causing multiple problems.
338
      boolean inxmldoc = false;
339
      while(!inxmldoc)
340
      {
341
        String xmlDocumentsCheck = "select distinct docid from xml_documents";
342
        PreparedStatement xmlDocCheck =
343
                                 dbConn.prepareStatement(xmlDocumentsCheck);
344
        // Increase usage count
345
        dbConn.increaseUsageCount(1);
346
        xmlDocCheck.execute();
347
        ResultSet doccheckRS = xmlDocCheck.getResultSet();
348
        boolean tableHasRows = doccheckRS.next();
349
        Vector docids = new Vector();
350
        while(tableHasRows)
351
        {
352
          docids.add(doccheckRS.getString(1).trim());
353
          tableHasRows = doccheckRS.next();
354
        }
355

    
356
        for(int i=0; i<docids.size(); i++)
357
        {
358
          String d = ((String)docids.elementAt(i)).trim();
359
          if(docid.trim().equals(d))
360
          {
361
            inxmldoc = true;
362
          }
363
        }
364
        xmlDocCheck.close();
365
      }
366

    
367
      // Going through the elements of the document and writing its Index
368
      Enumeration nodes = nodeIndex.elements();
369
      while ( nodes.hasMoreElements() ) {
370
        currNode = (DBSAXNode)nodes.nextElement();
371
        currNode.updateNodeIndex(dbConn, docid, doctype);
372
      }
373

    
374

    
375
      dbConn.commit();
376

    
377
      //if this is a package file
378
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
379
      Vector packagedoctypes = new Vector();
380

    
381
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
382

    
383
      if ( packagedoctypes.contains(doctype) )
384
      {
385
        // write the package info to xml_relation table
386
        RelationHandler rth = new RelationHandler(docid, dbConn);
387
        // from the relations get the access file id for that package
388
        String aclid = rth.getAccessFileID(docid);
389
        // if there are access file, write ACL for that package
390
        if ( aclid != null ) {
391
          runAccessControlList(dbConn, aclid);
392
        }
393

    
394
      }
395

    
396
      // if it is an access file
397
      else if ( MetaCatUtil.getOptionList(
398
                     MetaCatUtil.getOption("accessdoctype")).contains(doctype) )
399
      {
400
        // write ACL for the package
401
        //runAccessControlList(dbConn, docid);
402

    
403
      }
404

    
405

    
406
      //dbconn.close();
407

    
408
    } catch (Exception e) {
409
      try {
410
        dbConn.rollback();
411
        //dbconn.close();
412
      } catch (SQLException sqle) {}
413
      System.out.println("Error in DBSAXHandler.run " + e.getMessage());
414
      e.printStackTrace();
415
    }
416
    finally
417
    {
418
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
419
    }//finally
420
  }
421

    
422
  // It runs in xmlIndex thread. It writes ACL for a package.
423
  private void runAccessControlList (DBConnection conn, String aclid)
424
                                                throws Exception
425
  {
426
    // read the access file from xml_nodes
427
    // parse the access file and store the access info into xml_access
428
    AccessControlList aclobj =
429
    new AccessControlList(conn, aclid, //new StringReader(xml),
430
                          user, groups, serverCode);
431
    conn.commit();
432
  }
433

    
434

    
435
  /** SAX Handler that is called for each XML text node */
436
  public void characters(char[] cbuf, int start, int len) throws SAXException {
437
     MetaCatUtil.debugMessage("CHARACTERS", 50);
438
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
439
     String data = null;
440
     int leftover = len;
441
     int offset = start;
442
     boolean moredata = true;
443

    
444
     // This loop deals with the case where there are more characters
445
     // than can fit in a single database text field (limit is
446
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
447
     // write a series of nodes that are MAXDATACHARS long, and then the
448
     // final node contains the remainder
449
     while (moredata) {
450
       if (leftover > MAXDATACHARS) {
451
         data = new String(cbuf, offset, MAXDATACHARS);
452
         leftover -= MAXDATACHARS;
453
         offset += MAXDATACHARS;
454
       } else {
455
         data = new String(cbuf, offset, leftover);
456
         moredata = false;
457
       }
458

    
459
       // Write the content of the node to the database
460
       currentNode.writeChildNodeToDB("TEXT", null, data, docid);
461
     }
462
   }
463

    
464
   /**
465
    * SAX Handler that is called for each XML text node that is
466
    * Ignorable white space
467
    */
468
   public void ignorableWhitespace(char[] cbuf, int start, int len)
469
               throws SAXException {
470
     // When validation is turned "on", white spaces are reported here
471
     // When validation is turned "off" white spaces are not reported here,
472
     // but through characters() callback
473
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
474

    
475

    
476
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
477
     String data = null;
478
     int leftover = len;
479
     int offset = start;
480
     boolean moredata = true;
481

    
482
     // This loop deals with the case where there are more characters
483
     // than can fit in a single database text field (limit is
484
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
485
     // write a series of nodes that are MAXDATACHARS long, and then the
486
     // final node contains the remainder
487
     while (moredata) {
488
       if (leftover > MAXDATACHARS) {
489
         data = new String(cbuf, offset, MAXDATACHARS);
490
         leftover -= MAXDATACHARS;
491
         offset += MAXDATACHARS;
492
       } else {
493
         data = new String(cbuf, offset, leftover);
494
         moredata = false;
495
       }
496

    
497
       // Write the content of the node to the database
498
       currentNode.writeChildNodeToDB("TEXT", null, data, docid);
499
     }
500
   }
501

    
502
   /**
503
    * SAX Handler called once for each processing instruction found:
504
    * node that PI may occur before or after the root element.
505
    */
506
   public void processingInstruction(String target, String data)
507
          throws SAXException {
508
     MetaCatUtil.debugMessage("PI", 50);
509
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
510
     currentNode.writeChildNodeToDB("PI", target, data, docid);
511
   }
512

    
513
   /** SAX Handler that is called at the end of each XML element */
514
   public void endElement(String uri, String localName,
515
                          String qName) throws SAXException {
516
     MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
517

    
518
     // Get the node from the stack
519
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
520
   }
521

    
522
   //
523
   // the next section implements the LexicalHandler interface
524
   //
525

    
526
   /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
527
   public void startDTD(String name, String publicId, String systemId)
528
               throws SAXException {
529
     docname = name;
530
     doctype = publicId;
531
     systemid = systemId;
532

    
533
     processingDTD = true;
534

    
535
     MetaCatUtil.debugMessage("Start DTD", 50);
536
     MetaCatUtil.debugMessage("Setting processingDTD to true", 50);
537
     MetaCatUtil.debugMessage("DOCNAME: " + docname, 50);
538
     MetaCatUtil.debugMessage("DOCTYPE: " + doctype, 50);
539
     MetaCatUtil.debugMessage("  SYSID: " + systemid, 50);
540
   }
541

    
542
   /**
543
    * SAX Handler that receives notification of end of DTD
544
    */
545
   public void endDTD() throws SAXException {
546

    
547
     processingDTD = false;
548
     MetaCatUtil.debugMessage("Setting processingDTD to false", 50);
549
     MetaCatUtil.debugMessage("end DTD", 50);
550
   }
551

    
552
   /**
553
    * SAX Handler that receives notification of comments in the DTD
554
    */
555
   public void comment(char[] ch, int start, int length) throws SAXException {
556
     MetaCatUtil.debugMessage("COMMENT", 50);
557
     if ( !processingDTD ) {
558
       DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
559
       currentNode.writeChildNodeToDB("COMMENT", null, new String(ch), docid);
560
     }
561
   }
562

    
563
   /**
564
    * SAX Handler that receives notification of the start of CDATA sections
565
    */
566
   public void startCDATA() throws SAXException {
567
     MetaCatUtil.debugMessage("start CDATA", 50);
568
   }
569

    
570
   /**
571
    * SAX Handler that receives notification of the end of CDATA sections
572
    */
573
   public void endCDATA() throws SAXException {
574
     MetaCatUtil.debugMessage("end CDATA", 50);
575
   }
576

    
577
   /**
578
    * SAX Handler that receives notification of the start of entities
579
    */
580
   public void startEntity(String name) throws SAXException {
581
     MetaCatUtil.debugMessage("start ENTITY: " + name, 50);
582
//System.out.println("start ENTITY: " + name);
583
     if (name.equals("[dtd]")) {
584
       processingDTD = true;
585
     }
586
   }
587

    
588
   /**
589
    * SAX Handler that receives notification of the end of entities
590
    */
591
   public void endEntity(String name) throws SAXException {
592
     MetaCatUtil.debugMessage("end ENTITY: " + name, 50);
593
//System.out.println("end ENTITY: " + name);
594
     if (name.equals("[dtd]")) {
595
       processingDTD = false;
596
     }
597
   }
598

    
599
   /**
600
    * SAX Handler that receives notification of element declarations
601
    */
602
   public void elementDecl(String name, String model)
603
                        throws org.xml.sax.SAXException {
604
//System.out.println("ELEMENTDECL: " + name + " " + model);
605
     MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model, 50);
606
   }
607

    
608
   /**
609
    * SAX Handler that receives notification of attribute declarations
610
    */
611
   public void attributeDecl(String eName, String aName,
612
                        String type, String valueDefault, String value)
613
                        throws org.xml.sax.SAXException {
614

    
615
//System.out.println("ATTRIBUTEDECL: " + eName + " "
616
//                        + aName + " " + type + " " + valueDefault + " "
617
//                        + value);
618
     MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " "
619
                        + aName + " " + type + " " + valueDefault + " "
620
                        + value, 50);
621
   }
622

    
623
   /**
624
    * SAX Handler that receives notification of internal entity declarations
625
    */
626
   public void internalEntityDecl(String name, String value)
627
                        throws org.xml.sax.SAXException {
628
//System.out.println("INTERNENTITYDECL: " + name + " " + value);
629
     MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value, 50);
630
   }
631

    
632
   /**
633
    * SAX Handler that receives notification of external entity declarations
634
    */
635
   public void externalEntityDecl(String name, String publicId,
636
                        String systemId)
637
                        throws org.xml.sax.SAXException {
638
//System.out.println("EXTERNENTITYDECL: " + name + " " + publicId
639
//                              + " " + systemId);
640
     MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
641
                              + " " + systemId, 50);
642
     // it processes other external entity, not the DTD;
643
     // it doesn't signal for the DTD here
644
     processingDTD = false;
645
   }
646

    
647
   //
648
   // the next section implements the ErrorHandler interface
649
   //
650

    
651
   /**
652
    * SAX Handler that receives notification of fatal parsing errors
653
    */
654
   public void fatalError(SAXParseException exception) throws SAXException {
655
     MetaCatUtil.debugMessage("FATALERROR", 50);
656
     throw (new SAXException("Fatal processing error.", exception));
657
   }
658

    
659
   /**
660
    * SAX Handler that receives notification of recoverable parsing errors
661
    */
662
   public void error(SAXParseException exception) throws SAXException {
663
     MetaCatUtil.debugMessage("ERROR", 50);
664
     throw (new SAXException("Processing error.", exception));
665
   }
666

    
667
   /**
668
    * SAX Handler that receives notification of warnings
669
    */
670
   public void warning(SAXParseException exception) throws SAXException {
671
     MetaCatUtil.debugMessage("WARNING", 50);
672
     throw (new SAXException("Warning.", exception));
673
   }
674

    
675
   //
676
   // Helper, getter and setter methods
677
   //
678

    
679
   /**
680
    * get the document name
681
    */
682
   public String getDocname() {
683
     return docname;
684
   }
685

    
686
   /**
687
    * get the document processing state
688
    */
689
   public boolean processingDTD() {
690
     return processingDTD;
691
   }
692
}
(19-19/48)