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: jones $'
11
 *     '$Date: 2004-03-30 13:35:19 -0800 (Tue, 30 Mar 2004) $'
12
 * '$Revision: 2076 $'
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.PreparedStatement;
32
import java.sql.ResultSet;
33
import java.sql.SQLException;
34
import java.sql.Statement;
35
import java.util.EmptyStackException;
36
import java.util.Enumeration;
37
import java.util.Hashtable;
38
import java.util.Stack;
39
import java.util.Vector;
40

    
41
import edu.ucsb.nceas.morpho.datapackage.Triple;
42
import edu.ucsb.nceas.morpho.datapackage.TripleCollection;
43

    
44
import org.xml.sax.Attributes;
45
import org.xml.sax.SAXException;
46
import org.xml.sax.SAXParseException;
47
import org.xml.sax.ext.DeclHandler;
48
import org.xml.sax.ext.LexicalHandler;
49
import org.xml.sax.helpers.DefaultHandler;
50

    
51
/**
52
 * A database aware Class implementing callback bethods for the SAX parser to
53
 * call when processing the XML stream and generating events.
54
 */
55
public class DBSAXHandler extends DefaultHandler implements LexicalHandler,
56
        DeclHandler, Runnable
57
{
58

    
59
    protected boolean atFirstElement;
60

    
61
    protected boolean processingDTD;
62

    
63
    protected String docname = null;
64

    
65
    protected String doctype;
66

    
67
    protected String systemid;
68

    
69
    private boolean stackCreated = false;
70

    
71
    protected Stack nodeStack;
72

    
73
    protected Vector nodeIndex;
74

    
75
    protected DBConnection connection = null;
76

    
77
    protected DocumentImpl currentDocument;
78

    
79
    protected DBSAXNode rootNode;
80

    
81
    protected String action = null;
82

    
83
    protected String docid = null;
84

    
85
    protected String revision = null;
86

    
87
    protected String user = null;
88

    
89
    protected String[] groups = null;
90

    
91
    protected String pub = null;
92

    
93
    protected Thread xmlIndex;
94

    
95
    private boolean endDocument = false;
96

    
97
    protected int serverCode = 1;
98

    
99
    protected Hashtable namespaces = new Hashtable();
100

    
101
    protected boolean hitTextNode = false; // a flag to hit text node
102

    
103
    // a buffer to keep all text nodes for same element
104
    // it is for element was splited
105
    protected StringBuffer textBuffer = new StringBuffer();
106

    
107
    protected Stack textBufferStack = new Stack();
108

    
109
    protected static final int MAXDATACHARS = 4000;
110

    
111
    //protected static final int MAXDATACHARS = 50;
112
    protected static final long INDEXDELAY = 10000;
113

    
114
    // methods writeChildNodeToDB, setAttribute, setNamespace,
115
    // writeTextForDBSAXNode will increase endNodeId.
116
    protected long endNodeId = -1; // The end node id for a substree
117
    // DOCTITLE attr cleared from the db
118
    //   private static final int MAXTITLELEN = 1000;
119

    
120
    //HandlerTriple stuff
121
    TripleCollection tripleList = new TripleCollection();
122

    
123
    Triple currentTriple = new Triple();
124

    
125
    boolean startParseTriple = false;
126

    
127
    boolean hasTriple = false;
128

    
129
    /**
130
     * Construct an instance of the handler class
131
     * 
132
     * @param conn the JDBC connection to which information is written
133
     */
134
    private DBSAXHandler(DBConnection conn)
135
    {
136
        this.connection = conn;
137
        this.atFirstElement = true;
138
        this.processingDTD = false;
139

    
140
        // Create the stack for keeping track of node context
141
        // if it doesn't already exist
142
        if (!stackCreated) {
143
            nodeStack = new Stack();
144
            nodeIndex = new Vector();
145
            stackCreated = true;
146
        }
147
    }
148

    
149
    /**
150
     * Construct an instance of the handler class
151
     * 
152
     * @param conn the JDBC connection to which information is written
153
     * @param action - "INSERT" or "UPDATE"
154
     * @param docid to be inserted or updated into JDBC connection
155
     * @param user the user connected to MetaCat servlet and owns the document
156
     * @param groups the groups to which user belongs
157
     * @param pub flag for public "read" access on document
158
     * @param serverCode the serverid from xml_replication on which this
159
     *            document resides.
160
     *  
161
     */
162
/* TODO excise this constructor because not used anywhere in project 
163
    public DBSAXHandler(DBConnection conn, String action, String docid,
164
            String user, String[] groups, String pub, int serverCode)
165
    {
166
        this(conn);
167
        this.action = action;
168
        this.docid = docid;
169
        this.user = user;
170
        this.groups = groups;
171
        this.pub = pub;
172
        this.serverCode = serverCode;
173
        this.xmlIndex = new Thread(this);
174
    }
175
*/
176
    /**
177
     * Construct an instance of the handler class In this constructor, user can
178
     * specify the version need to upadate
179
     * 
180
     * @param conn the JDBC connection to which information is written
181
     * @param action - "INSERT" or "UPDATE"
182
     * @param docid to be inserted or updated into JDBC connection
183
     * @param revision, the user specified the revision need to be update
184
     * @param user the user connected to MetaCat servlet and owns the document
185
     * @param groups the groups to which user belongs
186
     * @param pub flag for public "read" access on document
187
     * @param serverCode the serverid from xml_replication on which this
188
     *            document resides.
189
     *  
190
     */
191
    public DBSAXHandler(DBConnection conn, String action, String docid,
192
            String revision, String user, String[] groups, String pub,
193
            int serverCode)
194
    {
195
        this(conn);
196
        this.action = action;
197
        this.docid = docid;
198
        this.revision = revision;
199
        this.user = user;
200
        this.groups = groups;
201
        this.pub = pub;
202
        this.serverCode = serverCode;
203
        this.xmlIndex = new Thread(this);
204
    }
205

    
206
    /** SAX Handler that receives notification of beginning of the document */
207
    public void startDocument() throws SAXException
208
    {
209
        MetaCatUtil.debugMessage("start Document", 50);
210

    
211
        // Create the document node representation as root
212
        rootNode = new DBSAXNode(connection, this.docid);
213
        // Add the node to the stack, so that any text data can be
214
        // added as it is encountered
215
        nodeStack.push(rootNode);
216
    }
217

    
218
    /** SAX Handler that receives notification of end of the document */
219
    public void endDocument() throws SAXException
220
    {
221
        MetaCatUtil.debugMessage("end Document", 50);
222
        // Starting new thread for writing XML Index.
223
        // It calls the run method of the thread.
224

    
225
        //if it is data package insert triple into relationtion table;
226
        if (doctype != null
227
                && MetaCatUtil.getOptionList(
228
                        MetaCatUtil.getOption("packagedoctype")).contains(
229
                        doctype) && hasTriple) {
230
            try {
231
                //initial handler and write into relationdb
232
                RelationHandler handler = new RelationHandler(docid, doctype,
233
                        connection, tripleList);
234
            } catch (Exception e) {
235
                MetaCatUtil.debugMessage(
236
                        "Failed to write triples into relation table"
237
                                + e.getMessage(), 30);
238
                throw new SAXException(
239
                        "Failed to write triples into relation table "
240
                                + e.getMessage());
241
            }
242
        }
243
        boolean useXMLIndex = 
244
            (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
245
        if (useXMLIndex) {
246
            try {
247
                xmlIndex.start();
248
            } catch (NullPointerException e) {
249
                xmlIndex = null;
250
                throw new SAXException(
251
                        "Problem with starting thread for writing XML Index. "
252
                                + e.getMessage());
253
            }   
254
        }
255
    }
256

    
257
    /** SAX Handler that is called at the start of Namespace */
258
    public void startPrefixMapping(String prefix, String uri)
259
            throws SAXException
260
    {
261
        MetaCatUtil.debugMessage("NAMESPACE", 50);
262

    
263
        namespaces.put(prefix, uri);
264
    }
265

    
266
    /** SAX Handler that is called at the start of each XML element */
267
    public void startElement(String uri, String localName, String qName,
268
            Attributes atts) throws SAXException
269
    {
270
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
271
        // for element <acl....> both qname and local name is "eml"
272
        // uri is namesapce
273
        MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
274
        MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
275
        MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
276

    
277
        DBSAXNode parentNode = null;
278
        DBSAXNode currentNode = null;
279

    
280
        // Get a reference to the parent node for the id
281
        try {
282
            parentNode = (DBSAXNode) nodeStack.peek();
283
        } catch (EmptyStackException e) {
284
            parentNode = null;
285
        }
286

    
287
        // If hit a text node, we need write this text for current's parent
288
        // node
289
        // This will happend if the element is mixted
290
        if (hitTextNode && parentNode != null) {
291
            // write the textbuffer into db for parent node.
292
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
293
            // rest hitTextNode
294
            hitTextNode = false;
295
            // reset textbuffer
296
            textBuffer = null;
297
            textBuffer = new StringBuffer();
298

    
299
        }
300

    
301
        // Document representation that points to the root document node
302
        if (atFirstElement) {
303
            atFirstElement = false;
304
            // If no DOCTYPE declaration: docname = root element
305
            // doctype = root element name or name space
306
            if (docname == null) {
307
                docname = localName;
308
                // if uri isn't null doctype = uri(namespace)
309
                // othewise root element
310
                if (uri != null && !(uri.trim()).equals("")) {
311
                    doctype = uri;
312
                } else {
313
                    doctype = docname;
314
                }
315
                MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
316
                MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
317
            } else if (doctype == null) {
318
                // because docname is not null and it is declared in dtd
319
                // so could not be in schema, no namespace
320
                doctype = docname;
321
                MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
322
            }
323
            rootNode.writeNodename(docname);
324
            try {
325
                // for validated XML Documents store a reference to XML DB
326
                // Catalog
327
                // Because this is select statement and it needn't to roll back
328
                // if
329
                // insert document action fialed.
330
                // In order to decrease DBConnection usage count, we get a new
331
                // dbconnection from pool
332
                String catalogid = null;
333
                DBConnection dbConn = null;
334
                int serialNumber = -1;
335

    
336
                if (systemid != null) {
337
                    try {
338
                        // Get dbconnection
339
                        dbConn = DBConnectionPool
340
                                .getDBConnection("DBSAXHandler.startElement");
341
                        serialNumber = dbConn.getCheckOutSerialNumber();
342

    
343
                        Statement stmt = dbConn.createStatement();
344
                        ResultSet rs = stmt
345
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
346
                                        + "WHERE entry_type = 'DTD' "
347
                                        + "AND public_id = '" + doctype + "'");
348
                        boolean hasRow = rs.next();
349
                        if (hasRow) {
350
                            catalogid = rs.getString(1);
351
                        }
352
                        stmt.close();
353
                    }//try
354
                    finally {
355
                        // Return dbconnection
356
                        DBConnectionPool.returnDBConnection(dbConn,
357
                                serialNumber);
358
                    }//finally
359
                }
360

    
361
                //create documentImpl object by the constructor which can
362
                // specify
363
                //the revision
364
                currentDocument = new DocumentImpl(connection, rootNode
365
                        .getNodeID(), docname, doctype, docid, revision,
366
                        action, user, this.pub, catalogid, this.serverCode);
367

    
368
            } catch (Exception ane) {
369
                throw (new SAXException("Error in DBSaxHandler.startElement "
370
                        + action, ane));
371
            }
372
        }
373

    
374
        // Create the current node representation
375
        currentNode = new DBSAXNode(connection, qName, localName, parentNode,
376
                currentDocument.getRootNodeID(), docid, currentDocument
377
                        .getDoctype());
378

    
379
        // Add all of the namespaces
380
        String prefix;
381
        String nsuri;
382
        Enumeration prefixes = namespaces.keys();
383
        while (prefixes.hasMoreElements()) {
384
            prefix = (String) prefixes.nextElement();
385
            nsuri = (String) namespaces.get(prefix);
386
            currentNode.setNamespace(prefix, nsuri, docid);
387
        }
388
        namespaces = null;
389
        namespaces = new Hashtable();
390

    
391
        // Add all of the attributes
392
        for (int i = 0; i < atts.getLength(); i++) {
393
            String attributeName = atts.getQName(i);
394
            String attributeValue = atts.getValue(i);
395
            endNodeId = currentNode.setAttribute(attributeName, attributeValue,
396
                    docid);
397

    
398
            // To handle name space and schema location if the attribute name
399
            // is
400
            // xsi:schemaLocation. If the name space is in not in catalog table
401
            // it will be regeistered.
402
            if (attributeName != null
403
                    && attributeName
404
                            .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
405
                SchemaLocationResolver resolver = new SchemaLocationResolver(
406
                        attributeValue);
407
                resolver.resolveNameSpace();
408

    
409
            }
410
        }
411

    
412
        // Add the node to the stack, so that any text data can be
413
        // added as it is encountered
414
        nodeStack.push(currentNode);
415
        // Add the node to the vector used by thread for writing XML Index
416
        nodeIndex.addElement(currentNode);
417
        // start parsing triple
418
        if (doctype != null
419
                && MetaCatUtil.getOptionList(
420
                        MetaCatUtil.getOption("packagedoctype")).contains(
421
                        doctype) && localName.equals("triple")) {
422
            startParseTriple = true;
423
            hasTriple = true;
424
            currentTriple = new Triple();
425
        }
426
    }
427

    
428
    /* The run method of xmlIndex thread. It writes XML Index for the document. */
429
    public void run()
430
    {
431
        DBSAXNode currNode = null;
432
        DBSAXNode prevNode = null;
433
        DBConnection dbConn = null;
434
        int serialNumber = -1;
435
        String doctype = currentDocument.getDoctype();
436
        int step = 0;
437
        int counter = 0;
438

    
439
        try {
440
            // stop 5 second
441
            Thread.sleep(5000);
442
            // Opening separate db connection for writing XML Index
443
            dbConn = DBConnectionPool.getDBConnection("DBSAXHandler.run");
444
            serialNumber = dbConn.getCheckOutSerialNumber();
445
            dbConn.setAutoCommit(false);
446
            //make sure record is done
447
            checkDocumentTable();
448
            // Going through the elements of the document and writing its Index
449
            Enumeration nodes = nodeIndex.elements();
450
            while (nodes.hasMoreElements()) {
451
                currNode = (DBSAXNode) nodes.nextElement();
452
                currNode.updateNodeIndex(dbConn, docid, doctype);
453
            }
454
            dbConn.commit();
455

    
456
        } catch (Exception e) {
457
            try {
458
                dbConn.rollback();
459
                //dbconn.close();
460
            } catch (SQLException sqle) {
461
            }
462
            MetaCatUtil.debugMessage("Error in DBSAXHandler.run "
463
                    + e.getMessage(), 30);
464

    
465
        } finally {
466
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
467
        }//finally
468
    }
469

    
470
    /*
471
     * method to make sure insert is finished before create index table If new
472
     * version of record is in xml_documents every thing will be fine
473
     */
474
    private void checkDocumentTable() throws Exception
475
    {
476

    
477
        DBConnection dbConn = null;
478
        int serialNumber = -1;
479

    
480
        try {
481
            // Opening separate db connection for writing XML Index
482
            dbConn = DBConnectionPool
483
                    .getDBConnection("DBSAXHandler.checkDocumentTable");
484
            serialNumber = dbConn.getCheckOutSerialNumber();
485

    
486
            // the following while loop construct checks to make sure that 
487
            // the docid of the document that we are trying to index is already 
488
            // in the xml_documents table. if this is not the case, the foreign 
489
            // key relationship between xml_documents and xml_index is 
490
            // temporarily broken causing multiple problems.
491
            boolean inxmldoc = false;
492
            long startTime = System.currentTimeMillis();
493
            while (!inxmldoc) {
494
                String xmlDocumentsCheck = "select distinct docid from xml_documents"
495
                        + " where docid ='"
496
                        + docid
497
                        + "' and "
498
                        + " rev ='"
499
                        + revision + "'";
500

    
501
                PreparedStatement xmlDocCheck = dbConn
502
                        .prepareStatement(xmlDocumentsCheck);
503
                // Increase usage count
504
                dbConn.increaseUsageCount(1);
505
                xmlDocCheck.execute();
506
                ResultSet doccheckRS = xmlDocCheck.getResultSet();
507
                boolean tableHasRows = doccheckRS.next();
508
                if (tableHasRows) {
509
                    MetaCatUtil.debugMessage(
510
                            "=========== find the correct document", 35);
511
                    inxmldoc = true;
512
                }
513
                doccheckRS.close();
514
                xmlDocCheck.close();
515
                // make sure the while loop will be ended in reseaonable time
516
                long stopTime = System.currentTimeMillis();
517
                if ((stopTime - startTime) > INDEXDELAY) { throw new Exception(
518
                        "Couldn't find the docid for index build in"
519
                                + "reseaonable time!"); }
520
            }//while
521
        } catch (Exception e) {
522
            try {
523
                dbConn.rollback();
524
                //dbconn.close();
525
            } catch (SQLException sqle) {
526
            }
527
            MetaCatUtil.debugMessage("Error in DBSAXHandler.run "
528
                    + e.getMessage(), 30);
529

    
530
        } finally {
531
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
532
        }//finally
533

    
534
    }
535

    
536
    /** SAX Handler that is called for each XML text node */
537
    public void characters(char[] cbuf, int start, int len) throws SAXException
538
    {
539
        MetaCatUtil.debugMessage("CHARACTERS", 50);
540
        // buffer all text nodes for same element. This is for text was splited
541
        // into different nodes
542
        textBuffer.append(new String(cbuf, start, len));
543
        // set hittextnode true
544
        hitTextNode = true;
545
        // if text buffer .size is greater than max, write it to db.
546
        // so we can save memory
547
        if (textBuffer.length() > MAXDATACHARS) {
548
            MetaCatUtil.debugMessage("Write text into DB in charaters"
549
                    + " when text buffer size is greater than maxmum number",
550
                    50);
551
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
552
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
553
                    currentNode);
554
            textBuffer = null;
555
            textBuffer = new StringBuffer();
556
        }
557
    }
558

    
559
    /**
560
     * SAX Handler that is called for each XML text node that is Ignorable
561
     * white space
562
     */
563
    public void ignorableWhitespace(char[] cbuf, int start, int len)
564
            throws SAXException
565
    {
566
        // When validation is turned "on", white spaces are reported here
567
        // When validation is turned "off" white spaces are not reported here,
568
        // but through characters() callback
569
        MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
570

    
571
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
572
        String data = null;
573
        int leftover = len;
574
        int offset = start;
575
        boolean moredata = true;
576

    
577
        // This loop deals with the case where there are more characters
578
        // than can fit in a single database text field (limit is
579
        // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
580
        // write a series of nodes that are MAXDATACHARS long, and then the
581
        // final node contains the remainder
582
        while (moredata) {
583
            if (leftover > MAXDATACHARS) {
584
                data = new String(cbuf, offset, MAXDATACHARS);
585
                leftover -= MAXDATACHARS;
586
                offset += MAXDATACHARS;
587
            } else {
588
                data = new String(cbuf, offset, leftover);
589
                moredata = false;
590
            }
591

    
592
            // Write the content of the node to the database
593
            endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
594
                    docid);
595
        }
596
    }
597

    
598
    /**
599
     * SAX Handler called once for each processing instruction found: node that
600
     * PI may occur before or after the root element.
601
     */
602
    public void processingInstruction(String target, String data)
603
            throws SAXException
604
    {
605
        MetaCatUtil.debugMessage("PI", 50);
606
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
607
        endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
608
    }
609

    
610
    /** SAX Handler that is called at the end of each XML element */
611
    public void endElement(String uri, String localName, String qName)
612
            throws SAXException
613
    {
614
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
615

    
616
        // write buffered text nodes into db (so no splited)
617
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
618

    
619
        // If before the end element, the parser hit text nodes and store them
620
        // into the buffer, write the buffer to data base. The reason we put
621
        // write database here is for xerces some time split text node
622
        if (hitTextNode) {
623
            MetaCatUtil.debugMessage("Write text into DB in End Element", 50);
624
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
625
                    currentNode);
626

    
627
            //if it is triple parsing process
628
            if (startParseTriple) {
629

    
630
                String content = textBuffer.toString().trim();
631
                if (localName.equals("subject")) { //get the subject content
632
                    currentTriple.setSubject(content);
633
                } else if (localName.equals("relationship")) { //get the
634
                                                               // relationship
635
                                                               // content
636
                    currentTriple.setRelationship(content);
637
                } else if (localName.equals("object")) { //get the object
638
                                                         // content
639
                    currentTriple.setObject(content);
640
                }
641
            }
642

    
643
        }//if
644

    
645
        //set hitText false
646
        hitTextNode = false;
647
        // reset textbuff
648
        textBuffer = null;
649
        textBuffer = new StringBuffer();
650

    
651
        // Get the node from the stack
652
        currentNode = (DBSAXNode) nodeStack.pop();
653
        //finishing parsing single triple
654
        if (startParseTriple && localName.equals("triple")) {
655
            // add trip to triple collection
656
            tripleList.addTriple(currentTriple);
657
            //rest variable
658
            currentTriple = null;
659
            startParseTriple = false;
660
        }
661
    }
662

    
663
    //
664
    // the next section implements the LexicalHandler interface
665
    //
666

    
667
    /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
668
    public void startDTD(String name, String publicId, String systemId)
669
            throws SAXException
670
    {
671
        docname = name;
672
        doctype = publicId;
673
        systemid = systemId;
674

    
675
        processingDTD = true;
676
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
677
        //create a DTD node and write docname,publicid and system id into db
678
        // we don't put the dtd node into node stack
679
        DBSAXNode dtdNode = new DBSAXNode(connection, name, publicId, systemId,
680
                currentNode, currentNode.getRootNodeID(), docid);
681
        MetaCatUtil.debugMessage("Start DTD", 50);
682
        MetaCatUtil.debugMessage("Setting processingDTD to true", 50);
683
        MetaCatUtil.debugMessage("DOCNAME: " + docname, 50);
684
        MetaCatUtil.debugMessage("DOCTYPE: " + doctype, 50);
685
        MetaCatUtil.debugMessage("  SYSID: " + systemid, 50);
686
    }
687

    
688
    /**
689
     * SAX Handler that receives notification of end of DTD
690
     */
691
    public void endDTD() throws SAXException
692
    {
693

    
694
        processingDTD = false;
695
        MetaCatUtil.debugMessage("Setting processingDTD to false", 50);
696
        MetaCatUtil.debugMessage("end DTD", 50);
697
    }
698

    
699
    /**
700
     * SAX Handler that receives notification of comments in the DTD
701
     */
702
    public void comment(char[] ch, int start, int length) throws SAXException
703
    {
704
        MetaCatUtil.debugMessage("COMMENT", 50);
705
        if (!processingDTD) {
706
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
707
            endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
708
                    new String(ch, start, length), docid);
709
        }
710
    }
711

    
712
    /**
713
     * SAX Handler that receives notification of the start of CDATA sections
714
     */
715
    public void startCDATA() throws SAXException
716
    {
717
        MetaCatUtil.debugMessage("start CDATA", 50);
718
    }
719

    
720
    /**
721
     * SAX Handler that receives notification of the end of CDATA sections
722
     */
723
    public void endCDATA() throws SAXException
724
    {
725
        MetaCatUtil.debugMessage("end CDATA", 50);
726
    }
727

    
728
    /**
729
     * SAX Handler that receives notification of the start of entities
730
     */
731
    public void startEntity(String name) throws SAXException
732
    {
733
        MetaCatUtil.debugMessage("start ENTITY: " + name, 50);
734
        //System.out.println("start ENTITY: " + name);
735
        if (name.equals("[dtd]")) {
736
            processingDTD = true;
737
        }
738
    }
739

    
740
    /**
741
     * SAX Handler that receives notification of the end of entities
742
     */
743
    public void endEntity(String name) throws SAXException
744
    {
745
        MetaCatUtil.debugMessage("end ENTITY: " + name, 50);
746
        //System.out.println("end ENTITY: " + name);
747
        if (name.equals("[dtd]")) {
748
            processingDTD = false;
749
        }
750
    }
751

    
752
    /**
753
     * SAX Handler that receives notification of element declarations
754
     */
755
    public void elementDecl(String name, String model)
756
            throws org.xml.sax.SAXException
757
    {
758
        //System.out.println("ELEMENTDECL: " + name + " " + model);
759
        MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model, 50);
760
    }
761

    
762
    /**
763
     * SAX Handler that receives notification of attribute declarations
764
     */
765
    public void attributeDecl(String eName, String aName, String type,
766
            String valueDefault, String value) throws org.xml.sax.SAXException
767
    {
768

    
769
        //System.out.println("ATTRIBUTEDECL: " + eName + " "
770
        //                        + aName + " " + type + " " + valueDefault + " "
771
        //                        + value);
772
        MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " " + aName + " "
773
                + type + " " + valueDefault + " " + value, 50);
774
    }
775

    
776
    /**
777
     * SAX Handler that receives notification of internal entity declarations
778
     */
779
    public void internalEntityDecl(String name, String value)
780
            throws org.xml.sax.SAXException
781
    {
782
        //System.out.println("INTERNENTITYDECL: " + name + " " + value);
783
        MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value, 50);
784
    }
785

    
786
    /**
787
     * SAX Handler that receives notification of external entity declarations
788
     */
789
    public void externalEntityDecl(String name, String publicId, String systemId)
790
            throws org.xml.sax.SAXException
791
    {
792
        //System.out.println("EXTERNENTITYDECL: " + name + " " + publicId
793
        //                              + " " + systemId);
794
        MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
795
                + " " + systemId, 50);
796
        // it processes other external entity, not the DTD;
797
        // it doesn't signal for the DTD here
798
        processingDTD = false;
799
    }
800

    
801
    //
802
    // the next section implements the ErrorHandler interface
803
    //
804

    
805
    /**
806
     * SAX Handler that receives notification of fatal parsing errors
807
     */
808
    public void fatalError(SAXParseException exception) throws SAXException
809
    {
810
        MetaCatUtil.debugMessage("FATALERROR: " + exception.getMessage(), 50);
811
        throw (new SAXException("Fatal processing error.", exception));
812
    }
813

    
814
    /**
815
     * SAX Handler that receives notification of recoverable parsing errors
816
     */
817
    public void error(SAXParseException exception) throws SAXException
818
    {
819
        MetaCatUtil.debugMessage("ERROR: " + exception.getMessage(), 50);
820
        throw (new SAXException("Processing error.", exception));
821
    }
822

    
823
    /**
824
     * SAX Handler that receives notification of warnings
825
     */
826
    public void warning(SAXParseException exception) throws SAXException
827
    {
828
        MetaCatUtil.debugMessage("WARNING: " + exception.getMessage(), 50);
829
        throw (new SAXException("Warning.", exception));
830
    }
831

    
832
    //
833
    // Helper, getter and setter methods
834
    //
835

    
836
    /**
837
     * get the document name
838
     */
839
    public String getDocname()
840
    {
841
        return docname;
842
    }
843

    
844
    /**
845
     * get the document processing state
846
     */
847
    public boolean processingDTD()
848
    {
849
        return processingDTD;
850
    }
851

    
852
    /* Method to write a text buffer for DBSAXNode */
853
    protected long writeTextForDBSAXNode(long previousEndNodeId,
854
            StringBuffer strBuffer, DBSAXNode node) throws SAXException
855
    {
856
        long nodeId = previousEndNodeId;
857
        // Check parameter
858
        if (strBuffer == null || node == null) { return nodeId; }
859
        boolean moredata = true;
860
        String data = null;
861
        int bufferSize = strBuffer.length();
862
        int start = 0;
863

    
864
        // if there are some cotent in buffer, write it
865
        if (bufferSize > 0) {
866
            MetaCatUtil.debugMessage("Write text into DB", 50);
867
            // This loop deals with the case where there are more characters
868
            // than can fit in a single database text field (limit is
869
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
870
            // write a series of nodes that are MAXDATACHARS long, and then the
871
            // final node contains the remainder
872
            while (moredata) {
873
                bufferSize = strBuffer.length();
874
                if (bufferSize > MAXDATACHARS) {
875
                    data = strBuffer.substring(start, MAXDATACHARS);
876
                    // cut the stringbuffer part that already written into db
877
                    strBuffer = strBuffer.delete(start, MAXDATACHARS);
878
                } else {
879
                    data = strBuffer.substring(start, bufferSize);
880
                    moredata = false;
881
                }
882

    
883
                // Write the content of the node to the database
884
                nodeId = node.writeChildNodeToDB("TEXT", null, data, docid);
885
            }//while
886
        }//if
887
        return nodeId;
888
    }
889
}
(23-23/61)