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-18 11:58:12 -0800 (Tue, 18 Feb 2003) $'
12
 * '$Revision: 1411 $'
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
   protected boolean	atFirstElement;
54
   private boolean	processingDTD;
55
   protected String 	docname = null;
56
   protected String 	doctype;
57
   protected String 	systemid;
58
   private boolean 	stackCreated = false;
59
   protected Stack 	  nodeStack;
60
   protected Vector   nodeIndex;
61
   protected DBConnection	  connection = null;
62
   protected DocumentImpl currentDocument;
63
   protected DBSAXNode    rootNode;
64
   protected String   action = null;
65
   protected String   docid = null;
66
   protected String   revision = null;
67
   protected String   user = null;
68
   protected String[] groups = null;
69
   protected String   pub = null;
70
   protected Thread   xmlIndex;
71
   private boolean endDocument = false;
72
   protected int serverCode = 1;
73
   protected Hashtable namespaces = new Hashtable();
74
   protected boolean hitTextNode = false; // a flag to hit text node
75
   // a buffer to keep all text nodes for same element
76
   // it is for element was splited
77
   protected StringBuffer textBuffer = new StringBuffer();
78
   protected Stack textBufferStack = new Stack();
79

    
80
   protected static final int MAXDATACHARS = 4000;
81
   protected static final long INDEXDELAY = 10000;
82
// DOCTITLE attr cleared from the db
83
//   private static final int MAXTITLELEN = 1000;
84

    
85
   /** Construct an instance of the handler class
86
    *
87
    * @param conn the JDBC connection to which information is written
88
    */
89
   public DBSAXHandler(DBConnection conn) {
90
     this.connection = conn;
91
     this.atFirstElement = true;
92
     this.processingDTD = false;
93

    
94
     // Create the stack for keeping track of node context
95
     // if it doesn't already exist
96
     if (!stackCreated) {
97
       nodeStack = new Stack();
98
       nodeIndex = new Vector();
99
       stackCreated = true;
100
     }
101
   }
102

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

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

    
156
   /** SAX Handler that receives notification of beginning of the document */
157
   public void startDocument() throws SAXException {
158
     MetaCatUtil.debugMessage("start Document", 50);
159

    
160
     // Create the document node representation as root
161
     rootNode = new DBSAXNode(connection, this.docid);
162
     // Add the node to the stack, so that any text data can be
163
     // added as it is encountered
164
     nodeStack.push(rootNode);
165
   }
166

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

    
182
   /** SAX Handler that is called at the start of Namespace */
183
   public void startPrefixMapping(String prefix, String uri)
184
                                          throws SAXException
185
   {
186
    MetaCatUtil.debugMessage("NAMESPACE", 50);
187

    
188
    namespaces.put(prefix, uri);
189
   }
190

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

    
205
     // Get a reference to the parent node for the id
206
     try {
207
       parentNode = (DBSAXNode)nodeStack.peek();
208
     } catch (EmptyStackException e) {
209
       parentNode = null;
210
     }
211
     
212
     // If hit a text node, we need write this text for current's parent node
213
     // This will happend if the element is mixted
214
     if (hitTextNode && parentNode != null)
215
     {
216
       // write the textbuffer into db for parent node.
217
        writeTextForDBSAXNode(textBuffer, parentNode);
218
        // rest hitTextNode
219
        hitTextNode =false;
220
        // reset textbuffer
221
        textBuffer = null;
222
        textBuffer = new StringBuffer();
223
       
224
     }
225

    
226
     // Document representation that points to the root document node
227
     if (atFirstElement) 
228
     {
229
       atFirstElement = false;
230
       // If no DOCTYPE declaration: docname = root element
231
       // doctype = root element name or name space
232
       if (docname == null) 
233
       {
234
         docname = localName;
235
         // if uri isn't null doctype = uri(namespace)
236
         // othewise root element
237
         if (uri != null && !(uri.trim()).equals(""))
238
         {
239
           doctype = uri;
240
         }
241
         else
242
         {
243
           doctype = docname;
244
         }
245
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
246
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
247
       } 
248
       else if (doctype == null) 
249
       {
250
         // because docname is not null and it is declared in dtd
251
         // so could not be in schema, no namespace
252
         doctype = docname;
253
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
254
       }
255
       rootNode.writeNodename(docname);
256
       try {
257
         // for validated XML Documents store a reference to XML DB Catalog
258
         // Because this is select statement and it needn't to roll back if
259
         // insert document action fialed.
260
         // In order to decrease DBConnection usage count, we get a new
261
         // dbconnection from pool
262
         String catalogid = null;
263
         DBConnection dbConn = null;
264
         int serialNumber = -1;
265

    
266
         if ( systemid != null ) {
267
           try
268
           {
269
            // Get dbconnection
270
            dbConn=DBConnectionPool.getDBConnection
271
                                          ("DBSAXHandler.startElement");
272
            serialNumber=dbConn.getCheckOutSerialNumber();
273

    
274
            Statement stmt = dbConn.createStatement();
275
            ResultSet rs = stmt.executeQuery(
276
                          "SELECT catalog_id FROM xml_catalog " +
277
                          "WHERE entry_type = 'DTD' " +
278
                          "AND public_id = '" + doctype + "'");
279
            boolean hasRow = rs.next();
280
            if ( hasRow ) {
281
              catalogid = rs.getString(1);
282
            }
283
            stmt.close();
284
           }//try
285
           finally
286
           {
287
             // Return dbconnection
288
             DBConnectionPool.returnDBConnection(dbConn, serialNumber);
289
           }//finally
290
         }
291

    
292
         //create documentImpl object by the constructor which can specify
293
         //the revision
294
         currentDocument = new DocumentImpl(connection, rootNode.getNodeID(),
295
                               docname, doctype, docid, revision, action, user,
296
                               this.pub, catalogid, this.serverCode);
297

    
298

    
299
       } catch (Exception ane) {
300
         throw (new SAXException("Error in DBSaxHandler.startElement " +
301
                                 action, ane));
302
       }
303
     }
304

    
305
     // Create the current node representation
306
     currentNode = new DBSAXNode(connection, qName, localName, parentNode,
307
                                 currentDocument.getRootNodeID(),docid,
308
                                 currentDocument.getDoctype());
309

    
310
     // Add all of the namespaces
311
     String prefix;
312
     String nsuri;
313
     Enumeration prefixes = namespaces.keys();
314
     while ( prefixes.hasMoreElements() ) {
315
       prefix = (String)prefixes.nextElement();
316
       nsuri = (String)namespaces.get(prefix);
317
       currentNode.setNamespace(prefix, nsuri, docid);
318
     }
319
     namespaces = null;
320
     namespaces = new Hashtable();
321

    
322
     // Add all of the attributes
323
     for (int i=0; i<atts.getLength(); i++) 
324
     {
325
       String attributeName = atts.getQName(i);
326
       String attributeValue = atts.getValue(i);
327
       currentNode.setAttribute(attributeName, attributeValue, docid);
328
       
329
       // To handle name space and schema location if the attribute name is
330
       // xsi:schemaLocation. If the name space is in not in catalog table
331
       // it will be regeistered.
332
       if (attributeName != null && 
333
           attributeName.indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1)
334
       {
335
         SchemaLocationResolver resolver = 
336
                                  new SchemaLocationResolver(attributeValue);
337
         resolver.resolveNameSpace();
338
         
339
       }
340
     }
341

    
342
     // Add the node to the stack, so that any text data can be
343
     // added as it is encountered
344
     nodeStack.push(currentNode);
345
     // Add the node to the vector used by thread for writing XML Index
346
     nodeIndex.addElement(currentNode);
347

    
348
  }
349

    
350
  /* The run method of xmlIndex thread. It writes XML Index for the document. */
351
  public void run () {
352
    DBSAXNode currNode = null;
353
    DBSAXNode prevNode = null;
354
    DBConnection dbConn = null;
355
    int serialNumber = -1;
356
    String doctype = currentDocument.getDoctype();
357
    int step = 0;
358
    int counter = 0;
359

    
360
    try {
361

    
362
      // Opening separate db connection for writing XML Index
363
      dbConn=DBConnectionPool.getDBConnection("DBSAXHandler.run");
364
      serialNumber=dbConn.getCheckOutSerialNumber();
365
      dbConn.setAutoCommit(false);
366

    
367
      //the following while loop construct checks to make sure that the docid
368
      //of the document that we are trying to index is already
369
      //in the xml_documents table.  if this is not the case, the foreign
370
      //key relationship between xml_documents and xml_index is temporarily
371
      //broken causing multiple problems.
372
      boolean inxmldoc = false;
373
      long startTime = System.currentTimeMillis();
374
      while(!inxmldoc)
375
      {
376
        String xmlDocumentsCheck = "select distinct docid from xml_documents";
377
        PreparedStatement xmlDocCheck =
378
                                 dbConn.prepareStatement(xmlDocumentsCheck);
379
        // Increase usage count
380
        dbConn.increaseUsageCount(1);
381
        xmlDocCheck.execute();
382
        ResultSet doccheckRS = xmlDocCheck.getResultSet();
383
        boolean tableHasRows = doccheckRS.next();
384
        Vector docids = new Vector();
385
        while(tableHasRows)
386
        {
387
          docids.add(doccheckRS.getString(1).trim());
388
          tableHasRows = doccheckRS.next();
389
        }
390

    
391
        for(int i=0; i<docids.size(); i++)
392
        {
393
          String d = ((String)docids.elementAt(i)).trim();
394
          if(docid.trim().equals(d))
395
          {
396
            inxmldoc = true;
397
          }
398
        }
399
        doccheckRS.close();
400
        xmlDocCheck.close();
401
        // make sure the while loop will be ended in reseaonable time
402
        long stopTime = System.currentTimeMillis();
403
        if ((stopTime - startTime) > INDEXDELAY)
404
        {
405
          throw new Exception("Couldn't find the docid for index build in" +
406
                              "reseaonable time!");
407
        }
408
      }
409

    
410
      // Going through the elements of the document and writing its Index
411
      Enumeration nodes = nodeIndex.elements();
412
      while ( nodes.hasMoreElements() ) {
413
        currNode = (DBSAXNode)nodes.nextElement();
414
        currNode.updateNodeIndex(dbConn, docid, doctype);
415
      }
416

    
417

    
418
      dbConn.commit();
419

    
420
      //if this is a package file
421
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
422
      Vector packagedoctypes = new Vector();
423

    
424
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
425

    
426
      if ( packagedoctypes.contains(doctype) )
427
      {
428
        // write the package info to xml_relation table
429
        RelationHandler rth = new RelationHandler(docid, dbConn);
430
        // from the relations get the access file id for that package
431
        String aclid = rth.getAccessFileID(docid);
432
        // if there are access file, write ACL for that package
433
        if ( aclid != null ) {
434
          runAccessControlList(dbConn, aclid);
435
        }
436

    
437
      }
438

    
439
   
440

    
441
    } catch (Exception e) {
442
      try {
443
        dbConn.rollback();
444
        //dbconn.close();
445
      } catch (SQLException sqle) {}
446
      MetaCatUtil.debugMessage("Error in DBSAXHandler.run " + 
447
                                e.getMessage(), 30);
448
      
449
    }
450
    finally
451
    {
452
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
453
    }//finally
454
  }
455

    
456
  // It runs in xmlIndex thread. It writes ACL for a package.
457
  private void runAccessControlList (DBConnection conn, String aclid)
458
                                                throws Exception
459
  {
460
    // read the access file from xml_nodes
461
    // parse the access file and store the access info into xml_access
462
    AccessControlList aclobj =
463
    new AccessControlList(conn, aclid, //new StringReader(xml),
464
                          user, groups, serverCode);
465
    conn.commit();
466
  }
467

    
468

    
469
  /** SAX Handler that is called for each XML text node */
470
  public void characters(char[] cbuf, int start, int len) throws SAXException 
471
  {
472
     MetaCatUtil.debugMessage("CHARACTERS", 50);
473
     // buffer all text nodes for same element. This is for text was splited
474
     // into different nodes
475
     textBuffer.append(new String(cbuf, start,len));
476
     // set hittextnode true
477
     hitTextNode = true;
478
  }
479

    
480
   /**
481
    * SAX Handler that is called for each XML text node that is
482
    * Ignorable white space
483
    */
484
   public void ignorableWhitespace(char[] cbuf, int start, int len)
485
               throws SAXException {
486
     // When validation is turned "on", white spaces are reported here
487
     // When validation is turned "off" white spaces are not reported here,
488
     // but through characters() callback
489
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
490

    
491

    
492
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
493
     String data = null;
494
     int leftover = len;
495
     int offset = start;
496
     boolean moredata = true;
497

    
498
     // This loop deals with the case where there are more characters
499
     // than can fit in a single database text field (limit is
500
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
501
     // write a series of nodes that are MAXDATACHARS long, and then the
502
     // final node contains the remainder
503
     while (moredata) {
504
       if (leftover > MAXDATACHARS) {
505
         data = new String(cbuf, offset, MAXDATACHARS);
506
         leftover -= MAXDATACHARS;
507
         offset += MAXDATACHARS;
508
       } else {
509
         data = new String(cbuf, offset, leftover);
510
         moredata = false;
511
       }
512

    
513
       // Write the content of the node to the database
514
       currentNode.writeChildNodeToDB("TEXT", null, data, docid);
515
     }
516
   }
517

    
518
   /**
519
    * SAX Handler called once for each processing instruction found:
520
    * node that PI may occur before or after the root element.
521
    */
522
   public void processingInstruction(String target, String data)
523
          throws SAXException {
524
     MetaCatUtil.debugMessage("PI", 50);
525
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
526
     currentNode.writeChildNodeToDB("PI", target, data, docid);
527
   }
528

    
529
   /** SAX Handler that is called at the end of each XML element */
530
   public void endElement(String uri, String localName,
531
                          String qName) throws SAXException {
532
     MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
533
     
534
     // write buffered text nodes into db (so no splited)
535
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
536
      
537
     // If before the end element, the parser hit text nodes and store them
538
     // into the buffer, write the buffer to data base. The reason we put
539
     // write database here is for xerces some time split text node
540
     if (hitTextNode)
541
     {
542
       MetaCatUtil.debugMessage("Write text into DB in End Element", 50);
543
       writeTextForDBSAXNode(textBuffer, currentNode);
544
     }//if
545
     
546
     //set hitText false
547
     hitTextNode = false;
548
     // reset textbuff
549
     textBuffer = null;
550
     textBuffer = new StringBuffer();
551

    
552
     // Get the node from the stack
553
     currentNode = (DBSAXNode)nodeStack.pop();
554
   }
555

    
556
   //
557
   // the next section implements the LexicalHandler interface
558
   //
559

    
560
   /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
561
   public void startDTD(String name, String publicId, String systemId)
562
               throws SAXException {
563
     docname = name;
564
     doctype = publicId;
565
     systemid = systemId;
566

    
567
     processingDTD = true;
568

    
569
     MetaCatUtil.debugMessage("Start DTD", 50);
570
     MetaCatUtil.debugMessage("Setting processingDTD to true", 50);
571
     MetaCatUtil.debugMessage("DOCNAME: " + docname, 50);
572
     MetaCatUtil.debugMessage("DOCTYPE: " + doctype, 50);
573
     MetaCatUtil.debugMessage("  SYSID: " + systemid, 50);
574
   }
575

    
576
   /**
577
    * SAX Handler that receives notification of end of DTD
578
    */
579
   public void endDTD() throws SAXException {
580

    
581
     processingDTD = false;
582
     MetaCatUtil.debugMessage("Setting processingDTD to false", 50);
583
     MetaCatUtil.debugMessage("end DTD", 50);
584
   }
585

    
586
   /**
587
    * SAX Handler that receives notification of comments in the DTD
588
    */
589
   public void comment(char[] ch, int start, int length) throws SAXException {
590
     MetaCatUtil.debugMessage("COMMENT", 50);
591
     if ( !processingDTD ) {
592
       DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
593
       currentNode.writeChildNodeToDB("COMMENT", null, new String(ch), docid);
594
     }
595
   }
596

    
597
   /**
598
    * SAX Handler that receives notification of the start of CDATA sections
599
    */
600
   public void startCDATA() throws SAXException {
601
     MetaCatUtil.debugMessage("start CDATA", 50);
602
   }
603

    
604
   /**
605
    * SAX Handler that receives notification of the end of CDATA sections
606
    */
607
   public void endCDATA() throws SAXException {
608
     MetaCatUtil.debugMessage("end CDATA", 50);
609
   }
610

    
611
   /**
612
    * SAX Handler that receives notification of the start of entities
613
    */
614
   public void startEntity(String name) throws SAXException {
615
     MetaCatUtil.debugMessage("start ENTITY: " + name, 50);
616
//System.out.println("start ENTITY: " + name);
617
     if (name.equals("[dtd]")) {
618
       processingDTD = true;
619
     }
620
   }
621

    
622
   /**
623
    * SAX Handler that receives notification of the end of entities
624
    */
625
   public void endEntity(String name) throws SAXException {
626
     MetaCatUtil.debugMessage("end ENTITY: " + name, 50);
627
//System.out.println("end ENTITY: " + name);
628
     if (name.equals("[dtd]")) {
629
       processingDTD = false;
630
     }
631
   }
632

    
633
   /**
634
    * SAX Handler that receives notification of element declarations
635
    */
636
   public void elementDecl(String name, String model)
637
                        throws org.xml.sax.SAXException {
638
//System.out.println("ELEMENTDECL: " + name + " " + model);
639
     MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model, 50);
640
   }
641

    
642
   /**
643
    * SAX Handler that receives notification of attribute declarations
644
    */
645
   public void attributeDecl(String eName, String aName,
646
                        String type, String valueDefault, String value)
647
                        throws org.xml.sax.SAXException {
648

    
649
//System.out.println("ATTRIBUTEDECL: " + eName + " "
650
//                        + aName + " " + type + " " + valueDefault + " "
651
//                        + value);
652
     MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " "
653
                        + aName + " " + type + " " + valueDefault + " "
654
                        + value, 50);
655
   }
656

    
657
   /**
658
    * SAX Handler that receives notification of internal entity declarations
659
    */
660
   public void internalEntityDecl(String name, String value)
661
                        throws org.xml.sax.SAXException {
662
//System.out.println("INTERNENTITYDECL: " + name + " " + value);
663
     MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value, 50);
664
   }
665

    
666
   /**
667
    * SAX Handler that receives notification of external entity declarations
668
    */
669
   public void externalEntityDecl(String name, String publicId,
670
                        String systemId)
671
                        throws org.xml.sax.SAXException {
672
//System.out.println("EXTERNENTITYDECL: " + name + " " + publicId
673
//                              + " " + systemId);
674
     MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
675
                              + " " + systemId, 50);
676
     // it processes other external entity, not the DTD;
677
     // it doesn't signal for the DTD here
678
     processingDTD = false;
679
   }
680

    
681
   //
682
   // the next section implements the ErrorHandler interface
683
   //
684

    
685
   /**
686
    * SAX Handler that receives notification of fatal parsing errors
687
    */
688
   public void fatalError(SAXParseException exception) throws SAXException {
689
     MetaCatUtil.debugMessage("FATALERROR", 50);
690
     throw (new SAXException("Fatal processing error.", exception));
691
   }
692

    
693
   /**
694
    * SAX Handler that receives notification of recoverable parsing errors
695
    */
696
   public void error(SAXParseException exception) throws SAXException {
697
     MetaCatUtil.debugMessage("ERROR", 50);
698
     throw (new SAXException("Processing error.", exception));
699
   }
700

    
701
   /**
702
    * SAX Handler that receives notification of warnings
703
    */
704
   public void warning(SAXParseException exception) throws SAXException {
705
     MetaCatUtil.debugMessage("WARNING", 50);
706
     throw (new SAXException("Warning.", exception));
707
   }
708

    
709
   //
710
   // Helper, getter and setter methods
711
   //
712

    
713
   /**
714
    * get the document name
715
    */
716
   public String getDocname() {
717
     return docname;
718
   }
719

    
720
   /**
721
    * get the document processing state
722
    */
723
   public boolean processingDTD() {
724
     return processingDTD;
725
   }
726
   
727
   /* Method to write a text buffer for DBSAXNode*/
728
   protected void writeTextForDBSAXNode(StringBuffer strBuffer, DBSAXNode node)
729
                                      throws SAXException
730
   {
731
     // Check parameter
732
     if ( strBuffer == null || node == null)
733
     {
734
       return;
735
     }
736
     boolean moredata = true;
737
     String data = null;
738
     int bufferSize = strBuffer.length();
739
     int start = 0;
740
    
741
     // if there are some cotent in buffer, write it
742
     if (bufferSize > 0)
743
     {
744
       MetaCatUtil.debugMessage("Write text into DB", 50);
745
       // This loop deals with the case where there are more characters
746
       // than can fit in a single database text field (limit is
747
       // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
748
       // write a series of nodes that are MAXDATACHARS long, and then the
749
       // final node contains the remainder
750
       while (moredata) 
751
       {
752
          bufferSize = strBuffer.length();
753
          if (bufferSize > MAXDATACHARS) 
754
         {
755
            data = strBuffer.substring(start, MAXDATACHARS);
756
            // cut the stringbuffer part that already written into db
757
            strBuffer = strBuffer.delete(start, MAXDATACHARS);
758
          } 
759
          else 
760
          {
761
            data = strBuffer.substring(start, bufferSize);
762
            moredata = false;
763
          }
764
       
765
          // Write the content of the node to the database
766
          node.writeChildNodeToDB("TEXT", null, data, docid);
767
        }//while
768
     }//if
769
   }
770
}
(21-21/52)