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: 2009-08-24 14:34:17 -0700 (Mon, 24 Aug 2009) $'
11
 * '$Revision: 5030 $'
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.database.DBConnection;
39
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
40
import edu.ucsb.nceas.metacat.properties.PropertyService;
41
import edu.ucsb.nceas.metacat.service.XMLSchema;
42
import edu.ucsb.nceas.metacat.util.MetacatUtil;
43
import edu.ucsb.nceas.morpho.datapackage.Triple;
44
import edu.ucsb.nceas.morpho.datapackage.TripleCollection;
45
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
46
import edu.ucsb.nceas.utilities.StringUtil;
47

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

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

    
64
    protected boolean atFirstElement;
65

    
66
    protected boolean processingDTD;
67

    
68
    protected String docname = null;
69

    
70
    protected String doctype;
71
    
72
    protected String catalogid = null;
73

    
74
    protected String systemid;
75

    
76
    private boolean stackCreated = false;
77

    
78
    protected Stack<DBSAXNode> nodeStack;
79

    
80
    protected Vector<DBSAXNode> nodeIndex;
81

    
82
    protected DBConnection connection = null;
83

    
84
    protected DocumentImpl currentDocument;
85
    
86
    protected String createDate = null;
87
    
88
    protected String updateDate = null;
89

    
90
    protected DBSAXNode rootNode;
91

    
92
    protected String action = null;
93

    
94
    protected String docid = null;
95

    
96
    protected String revision = null;
97

    
98
    protected String user = null;
99

    
100
    protected String[] groups = null;
101

    
102
    protected String pub = null;
103

    
104
//    private boolean endDocument = false;
105

    
106
    protected int serverCode = 1;
107

    
108
    protected Hashtable<String,String> namespaces = new Hashtable<String,String>();
109

    
110
    protected boolean hitTextNode = false; // a flag to hit text node
111

    
112
    // a buffer to keep all text nodes for same element
113
    // it is for if element was split
114
    protected StringBuffer textBuffer = new StringBuffer();
115

    
116
//    protected Stack textBufferStack = new Stack();
117

    
118
    protected static final int MAXDATACHARS = 4000;
119

    
120
    //protected static final int MAXDATACHARS = 50;
121

    
122
    // methods writeChildNodeToDB, setAttribute, setNamespace,
123
    // writeTextForDBSAXNode will increase endNodeId.
124
    protected long endNodeId = -1; // The end node id for a substree
125
    // DOCTITLE attr cleared from the db
126
    //   private static final int MAXTITLELEN = 1000;
127
    
128
    private boolean isRevisionDoc  = false;
129
    
130
    protected Vector<XMLSchema> schemaList = new Vector<XMLSchema>();
131

    
132
    //HandlerTriple stuff
133
    TripleCollection tripleList = new TripleCollection();
134

    
135
    Triple currentTriple = new Triple();
136

    
137
    boolean startParseTriple = false;
138

    
139
    boolean hasTriple = false;
140

    
141
    public static final String ECOGRID = "ecogrid://";
142

    
143
    private Logger logMetacat = Logger.getLogger(DBSAXHandler.class);
144

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

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

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

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

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

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

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

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

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

    
279
        namespaces.put(prefix, uri);
280
    }
281

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

    
293
        DBSAXNode parentNode = null;
294
        DBSAXNode currentNode = null;
295

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
573
        }//if
574

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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