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
 *
9
 *   '$Author: daigle $'
10
 *     '$Date: 2008-10-09 09:43:21 -0700 (Thu, 09 Oct 2008) $'
11
 * '$Revision: 4425 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.ResultSet;
31
import java.sql.Statement;
32
import java.util.EmptyStackException;
33
import java.util.Enumeration;
34
import java.util.Hashtable;
35
import java.util.Stack;
36
import java.util.Vector;
37

    
38
import edu.ucsb.nceas.metacat.service.PropertyService;
39
import edu.ucsb.nceas.metacat.service.XMLSchema;
40
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
41
import edu.ucsb.nceas.morpho.datapackage.Triple;
42
import edu.ucsb.nceas.morpho.datapackage.TripleCollection;
43
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
44
import edu.ucsb.nceas.utilities.StringUtil;
45

    
46
import org.apache.log4j.Logger;
47
import org.xml.sax.Attributes;
48
import org.xml.sax.SAXException;
49
import org.xml.sax.SAXParseException;
50
import org.xml.sax.ext.DeclHandler;
51
import org.xml.sax.ext.LexicalHandler;
52
import org.xml.sax.helpers.DefaultHandler;
53

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

    
62
    protected boolean atFirstElement;
63

    
64
    protected boolean processingDTD;
65

    
66
    protected String docname = null;
67

    
68
    protected String doctype;
69
    
70
    protected String catalogid = null;
71

    
72
    protected String systemid;
73

    
74
    private boolean stackCreated = false;
75

    
76
    protected Stack nodeStack;
77

    
78
    protected Vector nodeIndex;
79

    
80
    protected DBConnection connection = null;
81

    
82
    protected DocumentImpl currentDocument;
83
    
84
    protected String createDate = null;
85
    
86
    protected String updateDate = null;
87

    
88
    protected DBSAXNode rootNode;
89

    
90
    protected String action = null;
91

    
92
    protected String docid = null;
93

    
94
    protected String revision = null;
95

    
96
    protected String user = null;
97

    
98
    protected String[] groups = null;
99

    
100
    protected String pub = null;
101

    
102
    private boolean endDocument = false;
103

    
104
    protected int serverCode = 1;
105

    
106
    protected Hashtable namespaces = new Hashtable();
107

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

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

    
114
    protected Stack textBufferStack = new Stack();
115

    
116
    protected static final int MAXDATACHARS = 4000;
117

    
118
    //protected static final int MAXDATACHARS = 50;
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
    protected Vector<XMLSchema> schemaList = new Vector<XMLSchema>();
129

    
130
    //HandlerTriple stuff
131
    TripleCollection tripleList = new TripleCollection();
132

    
133
    Triple currentTriple = new Triple();
134

    
135
    boolean startParseTriple = false;
136

    
137
    boolean hasTriple = false;
138

    
139
    public static final String ECOGRID = "ecogrid://";
140

    
141
    private Logger logMetacat = Logger.getLogger(DBSAXHandler.class);
142

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

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

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

    
221
    /** SAX Handler that receives notification of beginning of the document */
222
    public void startDocument() throws SAXException
223
    {
224
        logMetacat.info("start Document");
225

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

    
233
    /** SAX Handler that receives notification of end of the document */
234
	public void endDocument() throws SAXException {
235
		logMetacat.info("end Document");
236
		// Starting new thread for writing XML Index.
237
		// It calls the run method of the thread.
238

    
239
		try {
240
			// if it is data package insert triple into relationtion table;
241
			if (doctype != null
242
					&& MetaCatUtil.getOptionList(
243
							PropertyService.getProperty("xml.packagedoctype")).contains(
244
							doctype) && hasTriple && !isRevisionDoc) {
245

    
246
				// initial handler and write into relationdb only for
247
				// xml-documents
248
				if (!isRevisionDoc) {
249
					RelationHandler handler = new RelationHandler(docid, doctype,
250
							connection, tripleList);
251
				}
252
			}
253
		} catch (Exception e) {
254
			logMetacat.error("Failed to write triples into relation table"
255
					+ e.getMessage());
256
			throw new SAXException("Failed to write triples into relation table "
257
					+ e.getMessage());
258
		}
259
		
260
		// If we get here, the document and schema parsed okay.  If there are
261
		// any schemas in the schema list, they are new and need to be registered.
262
    	for (XMLSchema xmlSchema : schemaList) {
263
    		String externalFileUri = xmlSchema.getExternalFileUri();
264
    		String fileNamespace = xmlSchema.getFileNamespace();
265
    		SchemaLocationResolver resolver = 
266
    			new SchemaLocationResolver(fileNamespace, externalFileUri);
267
    		resolver.resolveNameSpace();
268
    	}
269
	}
270

    
271
    /** SAX Handler that is called at the start of Namespace */
272
    public void startPrefixMapping(String prefix, String uri)
273
            throws SAXException
274
    {
275
        logMetacat.info("NAMESPACE");
276

    
277
        namespaces.put(prefix, uri);
278
    }
279

    
280
    /** SAX Handler that is called at the start of each XML element */
281
    public void startElement(String uri, String localName, String qName,
282
            Attributes atts) throws SAXException
283
    {
284
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
285
        // for element <acl....> both qname and local name is "eml"
286
        // uri is namesapce
287
        logMetacat.info("Start ELEMENT(qName) " + qName);
288
        logMetacat.info("Start ELEMENT(localName) " + localName);
289
        logMetacat.info("Start ELEMENT(uri) " + uri);
290

    
291
        DBSAXNode parentNode = null;
292
        DBSAXNode currentNode = null;
293

    
294
        // Get a reference to the parent node for the id
295
        try {
296
            
297
            parentNode = (DBSAXNode) nodeStack.peek();
298
        } catch (EmptyStackException e) {
299
            parentNode = null;
300
        }
301

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

    
360
                        Statement stmt = dbConn.createStatement();
361
                        ResultSet rs = stmt
362
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
363
                                        + "WHERE entry_type = 'DTD' "
364
                                        + "AND public_id = '" + doctype + "'");
365
                        boolean hasRow = rs.next();
366
                        if (hasRow) {
367
                            catalogid = rs.getString(1);
368
                        }
369
                        stmt.close();
370
                    }//try
371
                    finally {
372
                        // Return dbconnection
373
                        DBConnectionPool.returnDBConnection(dbConn,
374
                                serialNumber);
375
                    }//finally
376
                }
377

    
378
                //create documentImpl object by the constructor which can
379
                // specify
380
                //the revision
381
              
382
                if (!isRevisionDoc)
383
                {
384
                  currentDocument = new DocumentImpl(connection, rootNode
385
                        .getNodeID(), docname, doctype, docid, revision,
386
                        action, user, this.pub, catalogid, this.serverCode, 
387
                        createDate, updateDate);
388
                }               
389
            } catch (Exception ane) {
390
                ane.printStackTrace();
391
                throw (new SAXException("Error in DBSaxHandler.startElement "
392
                        + action, ane));
393
            }
394
        }
395

    
396
        // Create the current node representation
397
        currentNode = new DBSAXNode(connection, qName, localName,
398
                parentNode, rootNode.getNodeID(), docid, doctype);
399

    
400
        // Add all of the namespaces
401
        String prefix;
402
        String nsuri;
403
        Enumeration prefixes = namespaces.keys();
404
        while (prefixes.hasMoreElements()) {
405
            prefix = (String) prefixes.nextElement();
406
            nsuri = (String) namespaces.get(prefix);
407
            currentNode.setNamespace(prefix, nsuri, docid);
408
        }
409
        namespaces = null;
410
        namespaces = new Hashtable();
411

    
412
        // Add all of the attributes
413
        for (int i = 0; i < atts.getLength(); i++) {
414
            String attributeName = atts.getQName(i);
415
            String attributeValue = atts.getValue(i);
416
            endNodeId = currentNode.setAttribute(attributeName, attributeValue,
417
                    docid);
418

    
419
            // To handle name space and schema location if the attribute name
420
            // is xsi:schemaLocation. If the name space is in not in catalog 
421
            // table it will be registered.
422
            if (attributeName != null
423
                    && attributeName
424
                            .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
425
            	// These schemas will be registered in the end endDocument() method
426
            	// assuming parsing is successful.
427
        		// each namespace could have several schema locations.  parsedUri will
428
        		// hold a list of uri and files.
429
            	attributeValue = StringUtil.replaceTabsNewLines(attributeValue);
430
            	attributeValue = StringUtil.replaceDuplicateSpaces(attributeValue);
431
        		Vector<String> parsedUri = StringUtil.toVector(attributeValue, ' ');
432
        		for (int j = 0; j < parsedUri.size(); j = j + 2 ) {
433
        			if (j + 1 >= parsedUri.size()) {
434
        				throw new SAXException("Odd number of elements found when parsing schema location: " + 	
435
        						attributeValue + ". There should be an even number of uri/files in location.");
436
        			}
437
        			XMLSchema xmlSchema = 
438
        				new XMLSchema(parsedUri.get(j), parsedUri.get(j + 1));
439
        			schemaList.add(xmlSchema);
440
        		}
441
            }
442
        }
443

    
444
        // Add the node to the stack, so that any text data can be
445
		// added as it is encountered
446
		nodeStack.push(currentNode);
447
		// Add the node to the vector used by thread for writing XML Index
448
		nodeIndex.addElement(currentNode);
449
		// start parsing triple
450
		try {
451
			if (doctype != null
452
					&& MetaCatUtil.getOptionList(
453
							PropertyService.getProperty("xml.packagedoctype")).contains(doctype)
454
					&& localName.equals("triple")) {
455
				startParseTriple = true;
456
				hasTriple = true;
457
				currentTriple = new Triple();
458
			}
459
		} catch (PropertyNotFoundException pnfe) {
460
			pnfe.printStackTrace();
461
			throw (new SAXException("Error in DBSaxHandler.startElement " + action, pnfe));
462
		}
463
	}               
464
    
465

    
466
    /** SAX Handler that is called for each XML text node */
467
    public void characters(char[] cbuf, int start, int len) throws SAXException
468
    {
469
        logMetacat.info("CHARACTERS");
470
        // buffer all text nodes for same element. This is for text was splited
471
        // into different nodes
472
        textBuffer.append(new String(cbuf, start, len));
473
        // set hittextnode true
474
        hitTextNode = true;
475
        // if text buffer .size is greater than max, write it to db.
476
        // so we can save memory
477
        if (textBuffer.length() > MAXDATACHARS) {
478
            logMetacat.info("Write text into DB in charaters"
479
                    + " when text buffer size is greater than maxmum number");
480
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
481
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
482
                    currentNode);
483
            textBuffer = null;
484
            textBuffer = new StringBuffer();
485
        }
486
    }
487

    
488
    /**
489
     * SAX Handler that is called for each XML text node that is Ignorable
490
     * white space
491
     */
492
    public void ignorableWhitespace(char[] cbuf, int start, int len)
493
            throws SAXException
494
    {
495
        // When validation is turned "on", white spaces are reported here
496
        // When validation is turned "off" white spaces are not reported here,
497
        // but through characters() callback
498
        logMetacat.info("IGNORABLEWHITESPACE");
499

    
500
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
501
        String data = null;
502
        int leftover = len;
503
        int offset = start;
504
        boolean moredata = true;
505

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

    
521
            // Write the content of the node to the database
522
            endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
523
                    docid);
524
        }
525
    }
526

    
527
    /**
528
     * SAX Handler called once for each processing instruction found: node that
529
     * PI may occur before or after the root element.
530
     */
531
    public void processingInstruction(String target, String data)
532
            throws SAXException
533
    {
534
        logMetacat.info("PI");
535
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
536
        endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
537
    }
538

    
539
    /** SAX Handler that is called at the end of each XML element */
540
    public void endElement(String uri, String localName, String qName)
541
            throws SAXException
542
    {
543
        logMetacat.info("End ELEMENT " + qName);
544

    
545
        // write buffered text nodes into db (so no splited)
546
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
547

    
548
        // If before the end element, the parser hit text nodes and store them
549
        // into the buffer, write the buffer to data base. The reason we put
550
        // write database here is for xerces some time split text node
551
        if (hitTextNode) {
552
            logMetacat.info("Write text into DB in End Element");
553
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
554
                    currentNode);
555

    
556
            //if it is triple parsing process
557
            if (startParseTriple) {
558

    
559
                String content = textBuffer.toString().trim();
560
                if (localName.equals("subject")) { //get the subject content
561
                    currentTriple.setSubject(content);
562
                } else if (localName.equals("relationship")) { //get the
563
                                                               // relationship
564
                                                               // content
565
                    currentTriple.setRelationship(content);
566
                } else if (localName.equals("object")) { //get the object
567
                                                         // content
568
                    currentTriple.setObject(content);
569
                }
570
            }
571

    
572
        }//if
573

    
574
        //set hitText false
575
        hitTextNode = false;
576
        // reset textbuff
577
        textBuffer = null;
578
        textBuffer = new StringBuffer();
579

    
580
        // Get the node from the stack
581
        currentNode = (DBSAXNode) nodeStack.pop();
582
        //finishing parsing single triple
583
        if (startParseTriple && localName.equals("triple")) {
584
            // add trip to triple collection
585
            tripleList.addTriple(currentTriple);
586
            //rest variable
587
            currentTriple = null;
588
            startParseTriple = false;
589
        }
590
    }
591

    
592
    //
593
    // the next section implements the LexicalHandler interface
594
    //
595

    
596
    /** SAX Handler that receives notification of DOCTYPE. Sets the DTD */
597
    public void startDTD(String name, String publicId, String systemId)
598
            throws SAXException
599
    {
600
        docname = name;
601
        doctype = publicId;
602
        systemid = systemId;
603

    
604
        processingDTD = true;
605
        DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
606
        //create a DTD node and write docname,publicid and system id into db
607
        // we don't put the dtd node into node stack
608
        DBSAXNode dtdNode = new DBSAXNode(connection, name, publicId, systemId,
609
                currentNode, currentNode.getRootNodeID(), docid);
610
        logMetacat.info("Start DTD");
611
        logMetacat.info("Setting processingDTD to true");
612
        logMetacat.info("DOCNAME: " + docname);
613
        logMetacat.info("DOCTYPE: " + doctype);
614
        logMetacat.info("  SYSID: " + systemid);
615
    }
616

    
617
    /**
618
     * SAX Handler that receives notification of end of DTD
619
     */
620
    public void endDTD() throws SAXException
621
    {
622

    
623
        processingDTD = false;
624
        logMetacat.info("Setting processingDTD to false");
625
        logMetacat.info("end DTD");
626
    }
627

    
628
    /**
629
     * SAX Handler that receives notification of comments in the DTD
630
     */
631
    public void comment(char[] ch, int start, int length) throws SAXException
632
    {
633
        logMetacat.info("COMMENT");
634
        if (!processingDTD) {
635
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
636
            endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
637
                    new String(ch, start, length), docid);
638
        }
639
    }
640

    
641
    /**
642
     * SAX Handler that receives notification of the start of CDATA sections
643
     */
644
    public void startCDATA() throws SAXException
645
    {
646
        logMetacat.info("start CDATA");
647
    }
648

    
649
    /**
650
     * SAX Handler that receives notification of the end of CDATA sections
651
     */
652
    public void endCDATA() throws SAXException
653
    {
654
        logMetacat.info("end CDATA");
655
    }
656

    
657
    /**
658
     * SAX Handler that receives notification of the start of entities
659
     */
660
    public void startEntity(String name) throws SAXException
661
    {
662
        logMetacat.info("start ENTITY: " + name);
663
        //System.out.println("start ENTITY: " + name);
664
        if (name.equals("[dtd]")) {
665
            processingDTD = true;
666
        }
667
    }
668

    
669
    /**
670
     * SAX Handler that receives notification of the end of entities
671
     */
672
    public void endEntity(String name) throws SAXException
673
    {
674
        logMetacat.info("end ENTITY: " + name);
675
        //System.out.println("end ENTITY: " + name);
676
        if (name.equals("[dtd]")) {
677
            processingDTD = false;
678
        }
679
    }
680

    
681
    /**
682
     * SAX Handler that receives notification of element declarations
683
     */
684
    public void elementDecl(String name, String model)
685
            throws org.xml.sax.SAXException
686
    {
687
        //System.out.println("ELEMENTDECL: " + name + " " + model);
688
        logMetacat.info("ELEMENTDECL: " + name + " " + model);
689
    }
690

    
691
    /**
692
     * SAX Handler that receives notification of attribute declarations
693
     */
694
    public void attributeDecl(String eName, String aName, String type,
695
            String valueDefault, String value) throws org.xml.sax.SAXException
696
    {
697

    
698
        //System.out.println("ATTRIBUTEDECL: " + eName + " "
699
        //                        + aName + " " + type + " " + valueDefault + " "
700
        //                        + value);
701
        logMetacat.info("ATTRIBUTEDECL: " + eName + " " + aName + " "
702
                + type + " " + valueDefault + " " + value);
703
    }
704

    
705
    /**
706
     * SAX Handler that receives notification of internal entity declarations
707
     */
708
    public void internalEntityDecl(String name, String value)
709
            throws org.xml.sax.SAXException
710
    {
711
        //System.out.println("INTERNENTITYDECL: " + name + " " + value);
712
        logMetacat.info("INTERNENTITYDECL: " + name + " " + value);
713
    }
714

    
715
    /**
716
     * SAX Handler that receives notification of external entity declarations
717
     */
718
    public void externalEntityDecl(String name, String publicId, String systemId)
719
            throws org.xml.sax.SAXException
720
    {
721
        //System.out.println("EXTERNENTITYDECL: " + name + " " + publicId
722
        //                              + " " + systemId);
723
        logMetacat.info("EXTERNENTITYDECL: " + name + " " + publicId
724
                + " " + systemId);
725
        // it processes other external entity, not the DTD;
726
        // it doesn't signal for the DTD here
727
        processingDTD = false;
728
    }
729

    
730
    //
731
    // the next section implements the ErrorHandler interface
732
    //
733

    
734
    /**
735
     * SAX Handler that receives notification of fatal parsing errors
736
     */
737
    public void fatalError(SAXParseException exception) throws SAXException
738
    {
739
        logMetacat.fatal("FATALERROR: " + exception.getMessage());
740
        throw (new SAXException("Fatal processing error.", exception));
741
    }
742

    
743
    /**
744
     * SAX Handler that receives notification of recoverable parsing errors
745
     */
746
    public void error(SAXParseException exception) throws SAXException
747
    {
748
        logMetacat.error("ERROR: " + exception.getMessage());
749
        throw (new SAXException("Error in processing EML.", exception));
750
    }
751

    
752
    /**
753
     * SAX Handler that receives notification of warnings
754
     */
755
    public void warning(SAXParseException exception) throws SAXException
756
    {
757
        logMetacat.warn("WARNING: " + exception.getMessage());
758
        throw (new SAXException("Warning.", exception));
759
    }
760

    
761
    //
762
    // Helper, getter and setter methods
763
    //
764

    
765
    /**
766
     * get the document name
767
     */
768
    public String getDocname()
769
    {
770
        return docname;
771
    }
772

    
773
    /**
774
     * get the document processing state
775
     */
776
    public boolean processingDTD()
777
    {
778
        return processingDTD;
779
    }
780
    
781
    
782
    /**
783
     * get the the is revision doc
784
     * @return
785
     */
786
    public boolean getIsRevisionDoc()
787
    {
788
        return isRevisionDoc;
789
    }
790
    
791
    /**
792
     * Set the the handler is for revisionDoc
793
     * @param isRevisionDoc
794
     */
795
    public void setIsRevisionDoc(boolean isRevisionDoc)
796
    {
797
       this.isRevisionDoc = isRevisionDoc;   
798
    }
799

    
800
    /* Method to write a text buffer for DBSAXNode */
801
    protected long writeTextForDBSAXNode(long previousEndNodeId,
802
            StringBuffer strBuffer, DBSAXNode node) throws SAXException
803
    {
804
        long nodeId = previousEndNodeId;
805
        // Check parameter
806
        if (strBuffer == null || node == null) { return nodeId; }
807
        boolean moredata = true;
808
        String data = null;
809

    
810
        String normalizedData = strBuffer.toString();
811
        logMetacat.debug("Before normailize in write process === "+normalizedData);
812
        String afterNormalize = MetaCatUtil.normalize(normalizedData);
813
        logMetacat.debug("After normailize in write process === "+afterNormalize);
814
        strBuffer = new StringBuffer(afterNormalize);;
815

    
816
        int bufferSize = strBuffer.length();
817
        int start = 0;
818

    
819
        // if there are some cotent in buffer, write it
820
        if (bufferSize > 0) {
821
            logMetacat.info("Write text into DB");
822
            // This loop deals with the case where there are more characters
823
            // than can fit in a single database text field (limit is
824
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
825
            // write a series of nodes that are MAXDATACHARS long, and then the
826
            // final node contains the remainder
827
            while (moredata) {
828
                bufferSize = strBuffer.length();
829
                if (bufferSize > MAXDATACHARS) {
830
                    data = strBuffer.substring(start, MAXDATACHARS);
831
                    // cut the stringbuffer part that already written into db
832
                    strBuffer = strBuffer.delete(start, MAXDATACHARS);
833
                } else {
834
                    data = strBuffer.substring(start, bufferSize);
835
                    moredata = false;
836
                }
837

    
838
                // Write the content of the node to the database
839
                nodeId = node.writeChildNodeToDB("TEXT", null, data, docid);
840
            }//while
841
        }//if
842
        return nodeId;
843
    }
844
    
845
    public long getRootNodeId()
846
    {
847
        return rootNode.getNodeID();
848
    }
849
    
850
    public String getDocumentType()
851
    {
852
        return doctype;
853
    }
854
    
855
    public String getDocumentName()
856
    {
857
        return docname;
858
    }
859
    
860
    public String getCatalogId()
861
    {
862
        return catalogid;
863
    }
864
}
(21-21/67)