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-10-01 21:17:58 -0700 (Sat, 01 Oct 2005) $'
12
 * '$Revision: 2620 $'
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 catalogid = null;
68

    
69
    protected String systemid;
70

    
71
    private boolean stackCreated = false;
72

    
73
    protected Stack nodeStack;
74

    
75
    protected Vector nodeIndex;
76

    
77
    protected DBConnection connection = null;
78

    
79
    protected DocumentImpl currentDocument;
80
    
81
    protected String createDate = null;
82
    
83
    protected String updateDate = null;
84

    
85
    protected DBSAXNode rootNode;
86

    
87
    protected String action = null;
88

    
89
    protected String docid = null;
90

    
91
    protected String revision = null;
92

    
93
    protected String user = null;
94

    
95
    protected String[] groups = null;
96

    
97
    protected String pub = null;
98

    
99
    protected Thread xmlIndex;
100

    
101
    private boolean endDocument = false;
102

    
103
    protected int serverCode = 1;
104

    
105
    protected Hashtable namespaces = new Hashtable();
106

    
107
    protected boolean hitTextNode = false; // a flag to hit text node
108

    
109
    // a buffer to keep all text nodes for same element
110
    // it is for element was splited
111
    protected StringBuffer textBuffer = new StringBuffer();
112

    
113
    protected Stack textBufferStack = new Stack();
114

    
115
    protected static final int MAXDATACHARS = 4000;
116

    
117
    //protected static final int MAXDATACHARS = 50;
118
    protected static final long INDEXDELAY = 10000;
119

    
120
    // methods writeChildNodeToDB, setAttribute, setNamespace,
121
    // writeTextForDBSAXNode will increase endNodeId.
122
    protected long endNodeId = -1; // The end node id for a substree
123
    // DOCTITLE attr cleared from the db
124
    //   private static final int MAXTITLELEN = 1000;
125
    
126
    private boolean isRevisionDoc  = false;
127

    
128
    //HandlerTriple stuff
129
    TripleCollection tripleList = new TripleCollection();
130

    
131
    Triple currentTriple = new Triple();
132

    
133
    boolean startParseTriple = false;
134

    
135
    boolean hasTriple = false;
136

    
137
    public static final String ECOGRID = "ecogrid://";
138

    
139
    /**
140
     * Construct an instance of the handler class
141
     *
142
     * @param conn the JDBC connection to which information is written
143
     */
144
    private DBSAXHandler(DBConnection conn, String createDate, String updateDate)
145
    {
146
        this.connection = conn;
147
        this.atFirstElement = true;
148
        this.processingDTD = false;
149
        this.createDate = createDate;
150
        this.updateDate = updateDate;
151

    
152
        // Create the stack for keeping track of node context
153
        // if it doesn't already exist
154
        if (!stackCreated) {
155
            nodeStack = new Stack();
156
            nodeIndex = new Vector();
157
            stackCreated = true;
158
        }
159
    }
160

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

    
218
    /** SAX Handler that receives notification of beginning of the document */
219
    public void startDocument() throws SAXException
220
    {
221
        MetaCatUtil.debugMessage("start Document", 50);
222

    
223
        // Create the document node representation as root
224
        rootNode = new DBSAXNode(connection, this.docid);
225
        // Add the node to the stack, so that any text data can be
226
        // added as it is encountered
227
        nodeStack.push(rootNode);
228
    }
229

    
230
    /** SAX Handler that receives notification of end of the document */
231
    public void endDocument() throws SAXException
232
    {
233
        MetaCatUtil.debugMessage("end Document", 50);
234
        // Starting new thread for writing XML Index.
235
        // It calls the run method of the thread.
236

    
237
        //if it is data package insert triple into relationtion table;
238
        if (doctype != null
239
                && MetaCatUtil.getOptionList(
240
                        MetaCatUtil.getOption("packagedoctype")).contains(
241
                        doctype) && hasTriple && !isRevisionDoc) {
242
            try {
243
                //initial handler and write into relationdb only for xml-documents
244
                if (!isRevisionDoc)
245
                {
246
                  RelationHandler handler = new RelationHandler(docid, doctype,
247
                        connection, tripleList);
248
                }
249
            } catch (Exception e) {
250
                MetaCatUtil.debugMessage(
251
                        "Failed to write triples into relation table"
252
                                + e.getMessage(), 30);
253
                throw new SAXException(
254
                        "Failed to write triples into relation table "
255
                                + e.getMessage());
256
            }
257
        }
258
    }
259

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

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

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

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

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

    
291
        // If hit a text node, we need write this text for current's parent
292
        // node
293
        // This will happend if the element is mixted
294
        if (hitTextNode && parentNode != null) {
295
            // write the textbuffer into db for parent node.
296
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
297
            // rest hitTextNode
298
            hitTextNode = false;
299
            // reset textbuffer
300
            textBuffer = null;
301
            textBuffer = new StringBuffer();
302
           
303
        }
304
        
305
        // Document representation that points to the root document node
306
        if (atFirstElement) {
307
            atFirstElement = false;
308
            // If no DOCTYPE declaration: docname = root element
309
            // doctype = root element name or name space
310
            if (docname == null) {
311
                docname = localName;
312
                // if uri isn't null doctype = uri(namespace)
313
                // othewise root element
314
                if (uri != null && !(uri.trim()).equals("")) {
315
                    doctype = uri;
316
                } else {
317
                    doctype = docname;
318
                }
319
                MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
320
                MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
321
            } else if (doctype == null) {
322
                // because docname is not null and it is declared in dtd
323
                // so could not be in schema, no namespace
324
                doctype = docname;
325
                MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
326
            }
327
           
328
            rootNode.writeNodename(docname);
329
          
330
            try {
331
                // for validated XML Documents store a reference to XML DB
332
                // Catalog
333
                // Because this is select statement and it needn't to roll back
334
                // if
335
                // insert document action fialed.
336
                // In order to decrease DBConnection usage count, we get a new
337
                // dbconnection from pool
338
               
339
                DBConnection dbConn = null;
340
                int serialNumber = -1;
341
               
342
                if (systemid != null) {
343
                    try {
344
                        // Get dbconnection
345
                        dbConn = DBConnectionPool
346
                                .getDBConnection("DBSAXHandler.startElement");
347
                        serialNumber = dbConn.getCheckOutSerialNumber();
348

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

    
367
                //create documentImpl object by the constructor which can
368
                // specify
369
                //the revision
370
              
371
                if (!isRevisionDoc)
372
                {
373
                  //System.out.println("here!!!!!!!!!!!3");
374
                  currentDocument = new DocumentImpl(connection, rootNode
375
                        .getNodeID(), docname, doctype, docid, revision,
376
                        action, user, this.pub, catalogid, this.serverCode, 
377
                        createDate, updateDate);
378
                  //System.out.println("here!!!!!!!!!!!4");
379
                }
380
               
381

    
382
            } catch (Exception ane) {
383
                ane.printStackTrace();
384
                throw (new SAXException("Error in DBSaxHandler.startElement "
385
                        + action, ane));
386
            }
387
        }
388

    
389
        // Create the current node representation
390
        currentNode = new DBSAXNode(connection, qName, localName, parentNode,
391
                currentDocument.getRootNodeID(), docid, currentDocument
392
                        .getDoctype());
393

    
394
        // Add all of the namespaces
395
        String prefix;
396
        String nsuri;
397
        Enumeration prefixes = namespaces.keys();
398
        while (prefixes.hasMoreElements()) {
399
            prefix = (String) prefixes.nextElement();
400
            nsuri = (String) namespaces.get(prefix);
401
            currentNode.setNamespace(prefix, nsuri, docid);
402
        }
403
        namespaces = null;
404
        namespaces = new Hashtable();
405

    
406
        // Add all of the attributes
407
        for (int i = 0; i < atts.getLength(); i++) {
408
            String attributeName = atts.getQName(i);
409
            String attributeValue = atts.getValue(i);
410
            endNodeId = currentNode.setAttribute(attributeName, attributeValue,
411
                    docid);
412

    
413
            // To handle name space and schema location if the attribute name
414
            // is
415
            // xsi:schemaLocation. If the name space is in not in catalog table
416
            // it will be regeistered.
417
            if (attributeName != null
418
                    && attributeName
419
                            .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
420
                SchemaLocationResolver resolver = new SchemaLocationResolver(
421
                        attributeValue);
422
                resolver.resolveNameSpace();
423

    
424
            }
425
        }
426

    
427
        // Add the node to the stack, so that any text data can be
428
        // added as it is encountered
429
        nodeStack.push(currentNode);
430
        // Add the node to the vector used by thread for writing XML Index
431
        nodeIndex.addElement(currentNode);
432
        // start parsing triple
433
        if (doctype != null
434
                && MetaCatUtil.getOptionList(
435
                        MetaCatUtil.getOption("packagedoctype")).contains(
436
                        doctype) && localName.equals("triple")) {
437
            startParseTriple = true;
438
            hasTriple = true;
439
            currentTriple = new Triple();
440
        }
441
    }
442

    
443
    public void runIndexingThread(){
444
        boolean useXMLIndex =
445
            (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
446
        if (useXMLIndex && !isRevisionDoc) {
447
            try {
448
                xmlIndex.start();
449
            } catch (NullPointerException e) {
450
                xmlIndex = null;
451
                MetaCatUtil.debugMessage("Error in DBSAXHandler.runIndexingThread() "
452
                        + e.getMessage(), 20);
453
            }
454
        }
455
    }
456
    
457
    /*
458
     * Run a separate thread to build the XML index for this document.  This
459
     * thread is run asynchronously in order to more quickly return control to
460
     * the submitting user.  The run method checks to see if the document has
461
     * been fully inserted before trying to update the xml_index table.
462
     */
463
    public void run()
464
    {
465
        try {
466
            if (!isRevisionDoc)
467
            {
468
             // stop 5 second
469
             Thread.sleep(5000);
470
             //make sure record is done
471
             checkDocumentTable();
472
             // Build the index for this document
473
             currentDocument.buildIndex();
474
            }
475
        } catch (Exception e) {
476
            MetaCatUtil.debugMessage("Error in DBSAXHandler.run "
477
                    + e.getMessage(), 30);
478
        }
479
    }
480

    
481
    /*
482
     * method to make sure insert is finished before create index table If new
483
     * version of record is in xml_documents every thing will be fine
484
     */
485
    private void checkDocumentTable() throws Exception
486
    {
487

    
488
        DBConnection dbConn = null;
489
        int serialNumber = -1;
490

    
491
        try {
492
            // Opening separate db connection for writing XML Index
493
            dbConn = DBConnectionPool
494
                    .getDBConnection("DBSAXHandler.checkDocumentTable");
495
            serialNumber = dbConn.getCheckOutSerialNumber();
496

    
497
            // the following while loop construct checks to make sure that
498
            // the docid of the document that we are trying to index is already
499
            // in the xml_documents table. if this is not the case, the foreign
500
            // key relationship between xml_documents and xml_index is
501
            // temporarily broken causing multiple problems.
502
            boolean inxmldoc = false;
503
            long startTime = System.currentTimeMillis();
504
            while (!inxmldoc) {
505
                String xmlDocumentsCheck = "select distinct docid from xml_documents"
506
                        + " where docid ='"
507
                        + docid
508
                        + "' and "
509
                        + " rev ='"
510
                        + revision + "'";
511

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

    
541
        } finally {
542
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
543
        }//finally
544

    
545
    }
546

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

    
570
    /**
571
     * SAX Handler that is called for each XML text node that is Ignorable
572
     * white space
573
     */
574
    public void ignorableWhitespace(char[] cbuf, int start, int len)
575
            throws SAXException
576
    {
577
        // When validation is turned "on", white spaces are reported here
578
        // When validation is turned "off" white spaces are not reported here,
579
        // but through characters() callback
580
        MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
581

    
582
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
583
        String data = null;
584
        int leftover = len;
585
        int offset = start;
586
        boolean moredata = true;
587

    
588
        // This loop deals with the case where there are more characters
589
        // than can fit in a single database text field (limit is
590
        // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
591
        // write a series of nodes that are MAXDATACHARS long, and then the
592
        // final node contains the remainder
593
        while (moredata) {
594
            if (leftover > MAXDATACHARS) {
595
                data = new String(cbuf, offset, MAXDATACHARS);
596
                leftover -= MAXDATACHARS;
597
                offset += MAXDATACHARS;
598
            } else {
599
                data = new String(cbuf, offset, leftover);
600
                moredata = false;
601
            }
602

    
603
            // Write the content of the node to the database
604
            endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
605
                    docid);
606
        }
607
    }
608

    
609
    /**
610
     * SAX Handler called once for each processing instruction found: node that
611
     * PI may occur before or after the root element.
612
     */
613
    public void processingInstruction(String target, String data)
614
            throws SAXException
615
    {
616
        MetaCatUtil.debugMessage("PI", 50);
617
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
618
        endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
619
    }
620

    
621
    /** SAX Handler that is called at the end of each XML element */
622
    public void endElement(String uri, String localName, String qName)
623
            throws SAXException
624
    {
625
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
626

    
627
        // write buffered text nodes into db (so no splited)
628
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
629

    
630
        // If before the end element, the parser hit text nodes and store them
631
        // into the buffer, write the buffer to data base. The reason we put
632
        // write database here is for xerces some time split text node
633
        if (hitTextNode) {
634
            MetaCatUtil.debugMessage("Write text into DB in End Element", 50);
635
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
636
                    currentNode);
637

    
638
            //if it is triple parsing process
639
            if (startParseTriple) {
640

    
641
                String content = textBuffer.toString().trim();
642
                if (localName.equals("subject")) { //get the subject content
643
                    currentTriple.setSubject(content);
644
                } else if (localName.equals("relationship")) { //get the
645
                                                               // relationship
646
                                                               // content
647
                    currentTriple.setRelationship(content);
648
                } else if (localName.equals("object")) { //get the object
649
                                                         // content
650
                    currentTriple.setObject(content);
651
                }
652
            }
653

    
654
        }//if
655

    
656
        //set hitText false
657
        hitTextNode = false;
658
        // reset textbuff
659
        textBuffer = null;
660
        textBuffer = new StringBuffer();
661

    
662
        // Get the node from the stack
663
        currentNode = (DBSAXNode) nodeStack.pop();
664
        //finishing parsing single triple
665
        if (startParseTriple && localName.equals("triple")) {
666
            // add trip to triple collection
667
            tripleList.addTriple(currentTriple);
668
            //rest variable
669
            currentTriple = null;
670
            startParseTriple = false;
671
        }
672
    }
673

    
674
    //
675
    // the next section implements the LexicalHandler interface
676
    //
677

    
678
    /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
679
    public void startDTD(String name, String publicId, String systemId)
680
            throws SAXException
681
    {
682
        docname = name;
683
        doctype = publicId;
684
        systemid = systemId;
685

    
686
        processingDTD = true;
687
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
688
        //create a DTD node and write docname,publicid and system id into db
689
        // we don't put the dtd node into node stack
690
        DBSAXNode dtdNode = new DBSAXNode(connection, name, publicId, systemId,
691
                currentNode, currentNode.getRootNodeID(), docid);
692
        MetaCatUtil.debugMessage("Start DTD", 50);
693
        MetaCatUtil.debugMessage("Setting processingDTD to true", 50);
694
        MetaCatUtil.debugMessage("DOCNAME: " + docname, 50);
695
        MetaCatUtil.debugMessage("DOCTYPE: " + doctype, 50);
696
        MetaCatUtil.debugMessage("  SYSID: " + systemid, 50);
697
    }
698

    
699
    /**
700
     * SAX Handler that receives notification of end of DTD
701
     */
702
    public void endDTD() throws SAXException
703
    {
704

    
705
        processingDTD = false;
706
        MetaCatUtil.debugMessage("Setting processingDTD to false", 50);
707
        MetaCatUtil.debugMessage("end DTD", 50);
708
    }
709

    
710
    /**
711
     * SAX Handler that receives notification of comments in the DTD
712
     */
713
    public void comment(char[] ch, int start, int length) throws SAXException
714
    {
715
        MetaCatUtil.debugMessage("COMMENT", 50);
716
        if (!processingDTD) {
717
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
718
            endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
719
                    new String(ch, start, length), docid);
720
        }
721
    }
722

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

    
731
    /**
732
     * SAX Handler that receives notification of the end of CDATA sections
733
     */
734
    public void endCDATA() throws SAXException
735
    {
736
        MetaCatUtil.debugMessage("end CDATA", 50);
737
    }
738

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

    
751
    /**
752
     * SAX Handler that receives notification of the end of entities
753
     */
754
    public void endEntity(String name) throws SAXException
755
    {
756
        MetaCatUtil.debugMessage("end ENTITY: " + name, 50);
757
        //System.out.println("end ENTITY: " + name);
758
        if (name.equals("[dtd]")) {
759
            processingDTD = false;
760
        }
761
    }
762

    
763
    /**
764
     * SAX Handler that receives notification of element declarations
765
     */
766
    public void elementDecl(String name, String model)
767
            throws org.xml.sax.SAXException
768
    {
769
        //System.out.println("ELEMENTDECL: " + name + " " + model);
770
        MetaCatUtil.debugMessage("ELEMENTDECL: " + name + " " + model, 50);
771
    }
772

    
773
    /**
774
     * SAX Handler that receives notification of attribute declarations
775
     */
776
    public void attributeDecl(String eName, String aName, String type,
777
            String valueDefault, String value) throws org.xml.sax.SAXException
778
    {
779

    
780
        //System.out.println("ATTRIBUTEDECL: " + eName + " "
781
        //                        + aName + " " + type + " " + valueDefault + " "
782
        //                        + value);
783
        MetaCatUtil.debugMessage("ATTRIBUTEDECL: " + eName + " " + aName + " "
784
                + type + " " + valueDefault + " " + value, 50);
785
    }
786

    
787
    /**
788
     * SAX Handler that receives notification of internal entity declarations
789
     */
790
    public void internalEntityDecl(String name, String value)
791
            throws org.xml.sax.SAXException
792
    {
793
        //System.out.println("INTERNENTITYDECL: " + name + " " + value);
794
        MetaCatUtil.debugMessage("INTERNENTITYDECL: " + name + " " + value, 50);
795
    }
796

    
797
    /**
798
     * SAX Handler that receives notification of external entity declarations
799
     */
800
    public void externalEntityDecl(String name, String publicId, String systemId)
801
            throws org.xml.sax.SAXException
802
    {
803
        //System.out.println("EXTERNENTITYDECL: " + name + " " + publicId
804
        //                              + " " + systemId);
805
        MetaCatUtil.debugMessage("EXTERNENTITYDECL: " + name + " " + publicId
806
                + " " + systemId, 50);
807
        // it processes other external entity, not the DTD;
808
        // it doesn't signal for the DTD here
809
        processingDTD = false;
810
    }
811

    
812
    //
813
    // the next section implements the ErrorHandler interface
814
    //
815

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

    
825
    /**
826
     * SAX Handler that receives notification of recoverable parsing errors
827
     */
828
    public void error(SAXParseException exception) throws SAXException
829
    {
830
        MetaCatUtil.debugMessage("ERROR: " + exception.getMessage(), 50);
831
        throw (new SAXException("Error in processing EML.", exception));
832
    }
833

    
834
    /**
835
     * SAX Handler that receives notification of warnings
836
     */
837
    public void warning(SAXParseException exception) throws SAXException
838
    {
839
        MetaCatUtil.debugMessage("WARNING: " + exception.getMessage(), 50);
840
        throw (new SAXException("Warning.", exception));
841
    }
842

    
843
    //
844
    // Helper, getter and setter methods
845
    //
846

    
847
    /**
848
     * get the document name
849
     */
850
    public String getDocname()
851
    {
852
        return docname;
853
    }
854

    
855
    /**
856
     * get the document processing state
857
     */
858
    public boolean processingDTD()
859
    {
860
        return processingDTD;
861
    }
862
    
863
    
864
    /**
865
     * get the the is revision doc
866
     * @return
867
     */
868
    public boolean getIsRevisionDoc()
869
    {
870
        return isRevisionDoc;
871
    }
872
    
873
    /**
874
     * Set the the handler is for revisionDoc
875
     * @param isRevisionDoc
876
     */
877
    public void setIsRevisionDoc(boolean isRevisionDoc)
878
    {
879
       this.isRevisionDoc = isRevisionDoc;   
880
    }
881

    
882
    /* Method to write a text buffer for DBSAXNode */
883
    protected long writeTextForDBSAXNode(long previousEndNodeId,
884
            StringBuffer strBuffer, DBSAXNode node) throws SAXException
885
    {
886
        long nodeId = previousEndNodeId;
887
        // Check parameter
888
        if (strBuffer == null || node == null) { return nodeId; }
889
        boolean moredata = true;
890
        String data = null;
891

    
892
        String normalizedData = strBuffer.toString();
893
        strBuffer = new StringBuffer(MetaCatUtil.normalize(normalizedData));
894

    
895
        int bufferSize = strBuffer.length();
896
        int start = 0;
897

    
898
        // if there are some cotent in buffer, write it
899
        if (bufferSize > 0) {
900
            MetaCatUtil.debugMessage("Write text into DB", 50);
901
            // This loop deals with the case where there are more characters
902
            // than can fit in a single database text field (limit is
903
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
904
            // write a series of nodes that are MAXDATACHARS long, and then the
905
            // final node contains the remainder
906
            while (moredata) {
907
                bufferSize = strBuffer.length();
908
                if (bufferSize > MAXDATACHARS) {
909
                    data = strBuffer.substring(start, MAXDATACHARS);
910
                    // cut the stringbuffer part that already written into db
911
                    strBuffer = strBuffer.delete(start, MAXDATACHARS);
912
                } else {
913
                    data = strBuffer.substring(start, bufferSize);
914
                    moredata = false;
915
                }
916

    
917
                // Write the content of the node to the database
918
                nodeId = node.writeChildNodeToDB("TEXT", null, data, docid);
919
            }//while
920
        }//if
921
        return nodeId;
922
    }
923
    
924
    public long getRootNodeId()
925
    {
926
        return rootNode.getNodeID();
927
    }
928
    
929
    public String getDocumentType()
930
    {
931
        return doctype;
932
    }
933
    
934
    public String getDocumentName()
935
    {
936
        return docname;
937
    }
938
    
939
    public String getCatalogId()
940
    {
941
        return catalogid;
942
    }
943
}
(23-23/64)