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: 2005-09-13 15:08:23 -0700 (Tue, 13 Sep 2005) $'
12
 * '$Revision: 2590 $'
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
    private boolean isRevisionDoc  = false;
121

    
122
    //HandlerTriple stuff
123
    TripleCollection tripleList = new TripleCollection();
124

    
125
    Triple currentTriple = new Triple();
126

    
127
    boolean startParseTriple = false;
128

    
129
    boolean hasTriple = false;
130

    
131
    public static final String ECOGRID = "ecogrid://";
132

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

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

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

    
210
    /** SAX Handler that receives notification of beginning of the document */
211
    public void startDocument() throws SAXException
212
    {
213
        MetaCatUtil.debugMessage("start Document", 50);
214

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

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

    
229
        //if it is data package insert triple into relationtion table;
230
        if (doctype != null
231
                && MetaCatUtil.getOptionList(
232
                        MetaCatUtil.getOption("packagedoctype")).contains(
233
                        doctype) && hasTriple) {
234
            try {
235
                //initial handler and write into relationdb
236
                RelationHandler handler = new RelationHandler(docid, doctype,
237
                        connection, tripleList);
238
            } catch (Exception e) {
239
                MetaCatUtil.debugMessage(
240
                        "Failed to write triples into relation table"
241
                                + e.getMessage(), 30);
242
                throw new SAXException(
243
                        "Failed to write triples into relation table "
244
                                + e.getMessage());
245
            }
246
        }
247
    }
248

    
249
    /** SAX Handler that is called at the start of Namespace */
250
    public void startPrefixMapping(String prefix, String uri)
251
            throws SAXException
252
    {
253
        MetaCatUtil.debugMessage("NAMESPACE", 50);
254

    
255
        namespaces.put(prefix, uri);
256
    }
257

    
258
    /** SAX Handler that is called at the start of each XML element */
259
    public void startElement(String uri, String localName, String qName,
260
            Attributes atts) throws SAXException
261
    {
262
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
263
        // for element <acl....> both qname and local name is "eml"
264
        // uri is namesapce
265
        MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
266
        MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
267
        MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
268

    
269
        DBSAXNode parentNode = null;
270
        DBSAXNode currentNode = null;
271

    
272
        // Get a reference to the parent node for the id
273
        try {
274
            parentNode = (DBSAXNode) nodeStack.peek();
275
        } catch (EmptyStackException e) {
276
            parentNode = null;
277
        }
278

    
279
        // If hit a text node, we need write this text for current's parent
280
        // node
281
        // This will happend if the element is mixted
282
        if (hitTextNode && parentNode != null) {
283
            // write the textbuffer into db for parent node.
284
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
285
            // rest hitTextNode
286
            hitTextNode = false;
287
            // reset textbuffer
288
            textBuffer = null;
289
            textBuffer = new StringBuffer();
290

    
291
        }
292

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

    
328
                if (systemid != null) {
329
                    try {
330
                        // Get dbconnection
331
                        dbConn = DBConnectionPool
332
                                .getDBConnection("DBSAXHandler.startElement");
333
                        serialNumber = dbConn.getCheckOutSerialNumber();
334

    
335
                        Statement stmt = dbConn.createStatement();
336
                        ResultSet rs = stmt
337
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
338
                                        + "WHERE entry_type = 'DTD' "
339
                                        + "AND public_id = '" + doctype + "'");
340
                        boolean hasRow = rs.next();
341
                        if (hasRow) {
342
                            catalogid = rs.getString(1);
343
                        }
344
                        stmt.close();
345
                    }//try
346
                    finally {
347
                        // Return dbconnection
348
                        DBConnectionPool.returnDBConnection(dbConn,
349
                                serialNumber);
350
                    }//finally
351
                }
352

    
353
                //create documentImpl object by the constructor which can
354
                // specify
355
                //the revision
356
                currentDocument = new DocumentImpl(connection, rootNode
357
                        .getNodeID(), docname, doctype, docid, revision,
358
                        action, user, this.pub, catalogid, this.serverCode);
359

    
360
            } catch (Exception ane) {
361
                throw (new SAXException("Error in DBSaxHandler.startElement "
362
                        + action, ane));
363
            }
364
        }
365

    
366
        // Create the current node representation
367
        currentNode = new DBSAXNode(connection, qName, localName, parentNode,
368
                currentDocument.getRootNodeID(), docid, currentDocument
369
                        .getDoctype());
370

    
371
        // Add all of the namespaces
372
        String prefix;
373
        String nsuri;
374
        Enumeration prefixes = namespaces.keys();
375
        while (prefixes.hasMoreElements()) {
376
            prefix = (String) prefixes.nextElement();
377
            nsuri = (String) namespaces.get(prefix);
378
            currentNode.setNamespace(prefix, nsuri, docid);
379
        }
380
        namespaces = null;
381
        namespaces = new Hashtable();
382

    
383
        // Add all of the attributes
384
        for (int i = 0; i < atts.getLength(); i++) {
385
            String attributeName = atts.getQName(i);
386
            String attributeValue = atts.getValue(i);
387
            endNodeId = currentNode.setAttribute(attributeName, attributeValue,
388
                    docid);
389

    
390
            // To handle name space and schema location if the attribute name
391
            // is
392
            // xsi:schemaLocation. If the name space is in not in catalog table
393
            // it will be regeistered.
394
            if (attributeName != null
395
                    && attributeName
396
                            .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
397
                SchemaLocationResolver resolver = new SchemaLocationResolver(
398
                        attributeValue);
399
                resolver.resolveNameSpace();
400

    
401
            }
402
        }
403

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

    
420
    public void runIndexingThread(){
421
        boolean useXMLIndex =
422
            (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
423
        if (useXMLIndex) {
424
            try {
425
                xmlIndex.start();
426
            } catch (NullPointerException e) {
427
                xmlIndex = null;
428
                MetaCatUtil.debugMessage("Error in DBSAXHandler.runIndexingThread() "
429
                        + e.getMessage(), 20);
430
            }
431
        }
432
    }
433
    
434
    /*
435
     * Run a separate thread to build the XML index for this document.  This
436
     * thread is run asynchronously in order to more quickly return control to
437
     * the submitting user.  The run method checks to see if the document has
438
     * been fully inserted before trying to update the xml_index table.
439
     */
440
    public void run()
441
    {
442
        try {
443
            // stop 5 second
444
            Thread.sleep(5000);
445
            //make sure record is done
446
            checkDocumentTable();
447
            // Build the index for this document
448
            currentDocument.buildIndex();
449
        } catch (Exception e) {
450
            MetaCatUtil.debugMessage("Error in DBSAXHandler.run "
451
                    + e.getMessage(), 30);
452
        }
453
    }
454

    
455
    /*
456
     * method to make sure insert is finished before create index table If new
457
     * version of record is in xml_documents every thing will be fine
458
     */
459
    private void checkDocumentTable() throws Exception
460
    {
461

    
462
        DBConnection dbConn = null;
463
        int serialNumber = -1;
464

    
465
        try {
466
            // Opening separate db connection for writing XML Index
467
            dbConn = DBConnectionPool
468
                    .getDBConnection("DBSAXHandler.checkDocumentTable");
469
            serialNumber = dbConn.getCheckOutSerialNumber();
470

    
471
            // the following while loop construct checks to make sure that
472
            // the docid of the document that we are trying to index is already
473
            // in the xml_documents table. if this is not the case, the foreign
474
            // key relationship between xml_documents and xml_index is
475
            // temporarily broken causing multiple problems.
476
            boolean inxmldoc = false;
477
            long startTime = System.currentTimeMillis();
478
            while (!inxmldoc) {
479
                String xmlDocumentsCheck = "select distinct docid from xml_documents"
480
                        + " where docid ='"
481
                        + docid
482
                        + "' and "
483
                        + " rev ='"
484
                        + revision + "'";
485

    
486
                PreparedStatement xmlDocCheck = dbConn
487
                        .prepareStatement(xmlDocumentsCheck);
488
                // Increase usage count
489
                dbConn.increaseUsageCount(1);
490
                xmlDocCheck.execute();
491
                ResultSet doccheckRS = xmlDocCheck.getResultSet();
492
                boolean tableHasRows = doccheckRS.next();
493
                if (tableHasRows) {
494
                    MetaCatUtil.debugMessage(
495
                            "=========== found the correct document", 35);
496
                    inxmldoc = true;
497
                }
498
                doccheckRS.close();
499
                xmlDocCheck.close();
500
                // make sure the while loop will be ended in reseaonable time
501
                long stopTime = System.currentTimeMillis();
502
                if ((stopTime - startTime) > INDEXDELAY) { throw new Exception(
503
                        "Couldn't find the docid for index build in "
504
                                + "reseaonable time!"); }
505
            }//while
506
        } catch (Exception e) {
507
            try {
508
                dbConn.rollback();
509
                //dbconn.close();
510
            } catch (SQLException sqle) {
511
            }
512
            MetaCatUtil.debugMessage("Error in DBSAXHandler.checkDocumentTable "
513
                    + e.getMessage(), 30);
514

    
515
        } finally {
516
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
517
        }//finally
518

    
519
    }
520

    
521
    /** SAX Handler that is called for each XML text node */
522
    public void characters(char[] cbuf, int start, int len) throws SAXException
523
    {
524
        MetaCatUtil.debugMessage("CHARACTERS", 50);
525
        // buffer all text nodes for same element. This is for text was splited
526
        // into different nodes
527
        textBuffer.append(new String(cbuf, start, len));
528
        // set hittextnode true
529
        hitTextNode = true;
530
        // if text buffer .size is greater than max, write it to db.
531
        // so we can save memory
532
        if (textBuffer.length() > MAXDATACHARS) {
533
            MetaCatUtil.debugMessage("Write text into DB in charaters"
534
                    + " when text buffer size is greater than maxmum number",
535
                    50);
536
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
537
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
538
                    currentNode);
539
            textBuffer = null;
540
            textBuffer = new StringBuffer();
541
        }
542
    }
543

    
544
    /**
545
     * SAX Handler that is called for each XML text node that is Ignorable
546
     * white space
547
     */
548
    public void ignorableWhitespace(char[] cbuf, int start, int len)
549
            throws SAXException
550
    {
551
        // When validation is turned "on", white spaces are reported here
552
        // When validation is turned "off" white spaces are not reported here,
553
        // but through characters() callback
554
        MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
555

    
556
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
557
        String data = null;
558
        int leftover = len;
559
        int offset = start;
560
        boolean moredata = true;
561

    
562
        // This loop deals with the case where there are more characters
563
        // than can fit in a single database text field (limit is
564
        // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
565
        // write a series of nodes that are MAXDATACHARS long, and then the
566
        // final node contains the remainder
567
        while (moredata) {
568
            if (leftover > MAXDATACHARS) {
569
                data = new String(cbuf, offset, MAXDATACHARS);
570
                leftover -= MAXDATACHARS;
571
                offset += MAXDATACHARS;
572
            } else {
573
                data = new String(cbuf, offset, leftover);
574
                moredata = false;
575
            }
576

    
577
            // Write the content of the node to the database
578
            endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
579
                    docid);
580
        }
581
    }
582

    
583
    /**
584
     * SAX Handler called once for each processing instruction found: node that
585
     * PI may occur before or after the root element.
586
     */
587
    public void processingInstruction(String target, String data)
588
            throws SAXException
589
    {
590
        MetaCatUtil.debugMessage("PI", 50);
591
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
592
        endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
593
    }
594

    
595
    /** SAX Handler that is called at the end of each XML element */
596
    public void endElement(String uri, String localName, String qName)
597
            throws SAXException
598
    {
599
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
600

    
601
        // write buffered text nodes into db (so no splited)
602
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
603

    
604
        // If before the end element, the parser hit text nodes and store them
605
        // into the buffer, write the buffer to data base. The reason we put
606
        // write database here is for xerces some time split text node
607
        if (hitTextNode) {
608
            MetaCatUtil.debugMessage("Write text into DB in End Element", 50);
609
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
610
                    currentNode);
611

    
612
            //if it is triple parsing process
613
            if (startParseTriple) {
614

    
615
                String content = textBuffer.toString().trim();
616
                if (localName.equals("subject")) { //get the subject content
617
                    currentTriple.setSubject(content);
618
                } else if (localName.equals("relationship")) { //get the
619
                                                               // relationship
620
                                                               // content
621
                    currentTriple.setRelationship(content);
622
                } else if (localName.equals("object")) { //get the object
623
                                                         // content
624
                    currentTriple.setObject(content);
625
                }
626
            }
627

    
628
        }//if
629

    
630
        //set hitText false
631
        hitTextNode = false;
632
        // reset textbuff
633
        textBuffer = null;
634
        textBuffer = new StringBuffer();
635

    
636
        // Get the node from the stack
637
        currentNode = (DBSAXNode) nodeStack.pop();
638
        //finishing parsing single triple
639
        if (startParseTriple && localName.equals("triple")) {
640
            // add trip to triple collection
641
            tripleList.addTriple(currentTriple);
642
            //rest variable
643
            currentTriple = null;
644
            startParseTriple = false;
645
        }
646
    }
647

    
648
    //
649
    // the next section implements the LexicalHandler interface
650
    //
651

    
652
    /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
653
    public void startDTD(String name, String publicId, String systemId)
654
            throws SAXException
655
    {
656
        docname = name;
657
        doctype = publicId;
658
        systemid = systemId;
659

    
660
        processingDTD = true;
661
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
662
        //create a DTD node and write docname,publicid and system id into db
663
        // we don't put the dtd node into node stack
664
        DBSAXNode dtdNode = new DBSAXNode(connection, name, publicId, systemId,
665
                currentNode, currentNode.getRootNodeID(), docid);
666
        MetaCatUtil.debugMessage("Start DTD", 50);
667
        MetaCatUtil.debugMessage("Setting processingDTD to true", 50);
668
        MetaCatUtil.debugMessage("DOCNAME: " + docname, 50);
669
        MetaCatUtil.debugMessage("DOCTYPE: " + doctype, 50);
670
        MetaCatUtil.debugMessage("  SYSID: " + systemid, 50);
671
    }
672

    
673
    /**
674
     * SAX Handler that receives notification of end of DTD
675
     */
676
    public void endDTD() throws SAXException
677
    {
678

    
679
        processingDTD = false;
680
        MetaCatUtil.debugMessage("Setting processingDTD to false", 50);
681
        MetaCatUtil.debugMessage("end DTD", 50);
682
    }
683

    
684
    /**
685
     * SAX Handler that receives notification of comments in the DTD
686
     */
687
    public void comment(char[] ch, int start, int length) throws SAXException
688
    {
689
        MetaCatUtil.debugMessage("COMMENT", 50);
690
        if (!processingDTD) {
691
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
692
            endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
693
                    new String(ch, start, length), docid);
694
        }
695
    }
696

    
697
    /**
698
     * SAX Handler that receives notification of the start of CDATA sections
699
     */
700
    public void startCDATA() throws SAXException
701
    {
702
        MetaCatUtil.debugMessage("start CDATA", 50);
703
    }
704

    
705
    /**
706
     * SAX Handler that receives notification of the end of CDATA sections
707
     */
708
    public void endCDATA() throws SAXException
709
    {
710
        MetaCatUtil.debugMessage("end CDATA", 50);
711
    }
712

    
713
    /**
714
     * SAX Handler that receives notification of the start of entities
715
     */
716
    public void startEntity(String name) throws SAXException
717
    {
718
        MetaCatUtil.debugMessage("start ENTITY: " + name, 50);
719
        //System.out.println("start ENTITY: " + name);
720
        if (name.equals("[dtd]")) {
721
            processingDTD = true;
722
        }
723
    }
724

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

    
737
    /**
738
     * SAX Handler that receives notification of element declarations
739
     */
740
    public void elementDecl(String name, String model)
741
            throws org.xml.sax.SAXException
742
    {
743
        //System.out.println("ELEMENTDECL: " + name + " " + model);
744
        MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model, 50);
745
    }
746

    
747
    /**
748
     * SAX Handler that receives notification of attribute declarations
749
     */
750
    public void attributeDecl(String eName, String aName, String type,
751
            String valueDefault, String value) throws org.xml.sax.SAXException
752
    {
753

    
754
        //System.out.println("ATTRIBUTEDECL: " + eName + " "
755
        //                        + aName + " " + type + " " + valueDefault + " "
756
        //                        + value);
757
        MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " " + aName + " "
758
                + type + " " + valueDefault + " " + value, 50);
759
    }
760

    
761
    /**
762
     * SAX Handler that receives notification of internal entity declarations
763
     */
764
    public void internalEntityDecl(String name, String value)
765
            throws org.xml.sax.SAXException
766
    {
767
        //System.out.println("INTERNENTITYDECL: " + name + " " + value);
768
        MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value, 50);
769
    }
770

    
771
    /**
772
     * SAX Handler that receives notification of external entity declarations
773
     */
774
    public void externalEntityDecl(String name, String publicId, String systemId)
775
            throws org.xml.sax.SAXException
776
    {
777
        //System.out.println("EXTERNENTITYDECL: " + name + " " + publicId
778
        //                              + " " + systemId);
779
        MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
780
                + " " + systemId, 50);
781
        // it processes other external entity, not the DTD;
782
        // it doesn't signal for the DTD here
783
        processingDTD = false;
784
    }
785

    
786
    //
787
    // the next section implements the ErrorHandler interface
788
    //
789

    
790
    /**
791
     * SAX Handler that receives notification of fatal parsing errors
792
     */
793
    public void fatalError(SAXParseException exception) throws SAXException
794
    {
795
        MetaCatUtil.debugMessage("FATALERROR: " + exception.getMessage(), 50);
796
        throw (new SAXException("Fatal processing error.", exception));
797
    }
798

    
799
    /**
800
     * SAX Handler that receives notification of recoverable parsing errors
801
     */
802
    public void error(SAXParseException exception) throws SAXException
803
    {
804
        MetaCatUtil.debugMessage("ERROR: " + exception.getMessage(), 50);
805
        throw (new SAXException("Error in processing EML.", exception));
806
    }
807

    
808
    /**
809
     * SAX Handler that receives notification of warnings
810
     */
811
    public void warning(SAXParseException exception) throws SAXException
812
    {
813
        MetaCatUtil.debugMessage("WARNING: " + exception.getMessage(), 50);
814
        throw (new SAXException("Warning.", exception));
815
    }
816

    
817
    //
818
    // Helper, getter and setter methods
819
    //
820

    
821
    /**
822
     * get the document name
823
     */
824
    public String getDocname()
825
    {
826
        return docname;
827
    }
828

    
829
    /**
830
     * get the document processing state
831
     */
832
    public boolean processingDTD()
833
    {
834
        return processingDTD;
835
    }
836
    
837
    
838
    /**
839
     * get the the is revision doc
840
     * @return
841
     */
842
    public boolean getIsRevisionDoc()
843
    {
844
        return isRevisionDoc;
845
    }
846
    
847
    /**
848
     * Set the the handler is for revisionDoc
849
     * @param isRevisionDoc
850
     */
851
    public void setIsRevisionDoc(boolean isRevisionDoc)
852
    {
853
       this.isRevisionDoc = isRevisionDoc;   
854
    }
855

    
856
    /* Method to write a text buffer for DBSAXNode */
857
    protected long writeTextForDBSAXNode(long previousEndNodeId,
858
            StringBuffer strBuffer, DBSAXNode node) throws SAXException
859
    {
860
        long nodeId = previousEndNodeId;
861
        // Check parameter
862
        if (strBuffer == null || node == null) { return nodeId; }
863
        boolean moredata = true;
864
        String data = null;
865

    
866
        String normalizedData = strBuffer.toString();
867
        strBuffer = new StringBuffer(MetaCatUtil.normalize(normalizedData));
868

    
869
        int bufferSize = strBuffer.length();
870
        int start = 0;
871

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

    
891
                // Write the content of the node to the database
892
                nodeId = node.writeChildNodeToDB("TEXT", null, data, docid);
893
            }//while
894
        }//if
895
        return nodeId;
896
    }
897
}
(23-23/64)