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: sgarg $'
11
 *     '$Date: 2004-09-16 11:04:35 -0700 (Thu, 16 Sep 2004) $'
12
 * '$Revision: 2289 $'
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
    public static final String ECOGRID = "ecogrid://";
130

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

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

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

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

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

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

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

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

    
265
        namespaces.put(prefix, uri);
266
    }
267

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

    
279
        DBSAXNode parentNode = null;
280
        DBSAXNode currentNode = null;
281

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

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

    
301
        }
302

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

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

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

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

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

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

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

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

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

    
411
            }
412
        }
413

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

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

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

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

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

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

    
479
        DBConnection dbConn = null;
480
        int serialNumber = -1;
481

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

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

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

    
532
        } finally {
533
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
534
        }//finally
535

    
536
    }
537

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

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

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

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

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

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

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

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

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

    
629
            //if it is triple parsing process
630
            if (startParseTriple) {
631

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

    
645
        }//if
646

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

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

    
665
    //
666
    // the next section implements the LexicalHandler interface
667
    //
668

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
803
    //
804
    // the next section implements the ErrorHandler interface
805
    //
806

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

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

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

    
834
    //
835
    // Helper, getter and setter methods
836
    //
837

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

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

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

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

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