Project

General

Profile

« Previous | Next » 

Revision 2161

Added by Jing Tao almost 20 years ago

New class to replace EmlSAXHandler.

View differences:

src/edu/ucsb/nceas/metacat/Eml200SAXHandler.java
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$'
11
 *     '$Date$'
12
 * '$Revision$'
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.io.BufferedReader;
32
import java.io.File;
33
import java.io.FileReader;
34
import java.io.FileWriter;
35
import java.io.IOException;
36
import java.io.Reader;
37
import java.sql.PreparedStatement;
38
import java.sql.ResultSet;
39
import java.sql.SQLException;
40
import java.sql.Statement;
41
import java.util.EmptyStackException;
42
import java.util.Enumeration;
43
import java.util.Hashtable;
44
import java.util.Stack;
45
import java.util.Vector;
46

  
47
import org.xml.sax.Attributes;
48
import org.xml.sax.SAXException;
49

  
50
/**
51
 * A database aware Class implementing callback bethods for the SAX parser to
52
 * call when processing the XML stream and generating events
53
 */
54
public class Eml200SAXHandler extends DBSAXHandler implements
55
        AccessControlInterface
56
{
57

  
58
    private Vector allowRules = new Vector();
59

  
60
    private Vector denyRules = new Vector();
61

  
62
    private String documentId = null;
63

  
64
    private Vector subDocumentIdList = new Vector();
65

  
66
    private boolean processTopLeverAccess = false;
67

  
68
    private boolean processAdditionalAccess = false;
69

  
70
    private boolean processOtherAccess = false;
71

  
72
    private AccessSection accessObject = null;
73

  
74
    private AccessRule accessRule = null;
75

  
76
    private Vector accessObjectList = new Vector(); // store every access rule
77

  
78
    private Hashtable topLevelAccessControlMap = new Hashtable();
79

  
80
    private Hashtable additionalAccessControlMap = new Hashtable();// store
81

  
82
    //subtree access for single
83
    // additionalmetacat
84
    private Vector additionalAccessMapList = new Vector();// store maps for
85

  
86
    // every addionalmetadata
87
    private Vector describesId = new Vector(); // store the ids in
88

  
89
    //additionalmetadata/describes
90
    private Stack subTreeInfoStack = new Stack();
91

  
92
    private Vector subTreeList = new Vector();// store the final subtree
93

  
94
    private Hashtable unChangableSubTreeHash = new Hashtable();
95

  
96
    private Stack currentUnChangedableSubtreeNodeStack = new Stack();
97

  
98
    private boolean startCriticalSubTree = false;
99

  
100
    private boolean firstElementForCriticalSubTree = false;
101

  
102
    private String firstElementNameForCriticalSubTree;
103

  
104
    private boolean needCheckingAccessModule = false;
105

  
106
    private Vector unChangableAccessSubTreeVector = new Vector();
107

  
108
    private Stack currentUnchangableAccessModuleNodeStack = new Stack();
109

  
110
    private AccessSection topAccessSection;
111

  
112
    // we need an another stack to store the access node which we pull out just
113
    // from xml. If a reference happend, we can use the stack the compare nodes
114
    private Stack storedAccessNodeStack = new Stack();
115

  
116
    // vector stored the data file id which will be write into relation table
117
    private Vector onlineDataFileIdVector = new Vector();
118

  
119
    // Indicator of inline data
120
    private boolean handleInlineData = false;
121

  
122
    private Stack inlineDataNodeStack = null;
123

  
124
    private Hashtable inlineDataNameSpace = null;
125

  
126
    private FileWriter inlineDataFileWriter = null;
127

  
128
    private String inlineDataFileName = null;
129

  
130
    private int inLineDataIndex = 0;
131

  
132
    private Vector inlineFileIDList = new Vector();
133

  
134
    // Constant
135
    private static final String EML = "eml";
136

  
137
    private static final String DESCRIBES = "describes";
138

  
139
    private static final String ADDITIONALMETADATA = "additionalMetadata";
140

  
141
    private static final String ORDER = "order";
142

  
143
    private static final String ID = "id";
144

  
145
    private static final String REFERENCES = "references";
146

  
147
    public static final String INLINE = "inline";
148

  
149
    private static final String ONLINE = "online";
150

  
151
    private static final String URL = "url";
152

  
153
    private static final String PERMISSIONERROR = "User try to update a subtree"
154
            + " which it doesn't have write permission!";
155

  
156
    private static final String UPDATEACCESSERROR = "User try to update a "
157
            + "access module which it doesn't have \"ALL\" permission!";
158

  
159
    private static final String TOPLEVEL = "top";
160

  
161
    private static final String SUBTREELEVEL = "subtree";
162

  
163
    private static final String RELATION = "Provides info for";
164

  
165
    /**
166
     * Construct an instance of the handler class In this constructor, user can
167
     * specify the version need to upadate
168
     *
169
     * @param conn the JDBC connection to which information is written
170
     * @param action - "INSERT" or "UPDATE"
171
     * @param docid to be inserted or updated into JDBC connection
172
     * @param revision, the user specified the revision need to be update
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
    public Eml200SAXHandler(DBConnection conn, String action, String docid,
181
            String revision, String user, String[] groups, String pub,
182
            int serverCode) throws SAXException
183
    {
184
        super(conn, action, docid, revision, user, groups, pub, serverCode);
185
        // Get the unchangable subtrees (user doesn't have write permission)
186
        try {
187
            PermissionController control = new PermissionController(docid
188
                    + MetaCatUtil.getOption("accNumSeparator") + revision);
189
            //unChangableSubTreeHash = getUnchangableSubTree(control, user,
190
            // groups);
191

  
192
            //If the action is update and user doesn't have "ALL" permission
193
            // we need to check if user update access subtree
194
            if (action.equals("UPDATE")
195
                    && !control.hasPermission(user, groups,
196
                            AccessControlInterface.ALLSTRING)) {
197
                needCheckingAccessModule = true;
198
                unChangableAccessSubTreeVector = getAccessSubTreeListFromDB();
199
            }
200
        } catch (Exception e) {
201
            throw new SAXException(e.getMessage());
202
        }
203
    }
204

  
205
    /* Pass a permission control and get the list of unchangable subtree */
206
    private Hashtable getUnchangableSubTree(PermissionController controller,
207
            String user, String[] groups) throws Exception
208
    {
209
        Hashtable list = null;
210
        Hashtable result = new Hashtable();
211
        // get unwritable sutree from controller
212
        list = controller.hasUnaccessableSubTree(user, groups,
213
                AccessControlInterface.WRITESTRING);
214
        if (list != null) {
215

  
216
            Enumeration en = list.elements();
217
            while (en.hasMoreElements()) {
218
                // Get a subtree without node record list
219
                SubTree treeWithoutStack = (SubTree) en.nextElement();
220
                String subTreeId = treeWithoutStack.getSubTreeId();
221
                MetaCatUtil.debugMessage(
222
                        "unchangable subtree id: " + subTreeId, 40);
223
                long startNodeId = treeWithoutStack.getStartNodeId();
224
                MetaCatUtil.debugMessage("unchangable subtree startnodeid: "
225
                        + startNodeId, 40);
226
                long endNodeId = treeWithoutStack.getEndNodeId();
227
                MetaCatUtil.debugMessage("unchangable subtree endnodeid: "
228
                        + endNodeId, 40);
229
                // Get a subtree has the nodelist
230
                SubTree tree = new SubTree(docid, subTreeId, startNodeId,
231
                        endNodeId);
232
                // add this tree to the result
233
                result.put(subTreeId, tree);
234

  
235
            }//while
236

  
237
        }//if
238

  
239
        return result;
240
    }
241

  
242
    /*
243
     * Get the subtree node info from xml_accesssubtree table
244
     */
245
    private Vector getAccessSubTreeListFromDB() throws Exception
246
    {
247
        Vector result = new Vector();
248
        PreparedStatement pstmt = null;
249
        ResultSet rs = null;
250
        String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid "
251
                + "FROM xml_accesssubtree WHERE docid like ? "
252
                + "ORDER BY startnodeid ASC";
253

  
254
        try {
255

  
256
            pstmt = connection.prepareStatement(sql);
257
            // Increase DBConnection usage count
258
            connection.increaseUsageCount(1);
259
            // Bind the values to the query
260
            pstmt.setString(1, docid);
261
            pstmt.execute();
262

  
263
            // Get result set
264
            rs = pstmt.getResultSet();
265
            while (rs.next()) {
266
                String level = rs.getString(1);
267
                String sectionId = rs.getString(2);
268
                long startNodeId = rs.getLong(3);
269
                long endNodeId = rs.getLong(4);
270
                // create a new access section
271
                AccessSection accessObj = new AccessSection();
272
                accessObj.setControlLevel(level);
273
                accessObj.setDocId(docid);
274
                accessObj.setSubTreeId(sectionId);
275
                accessObj.setStartNodeId(startNodeId);
276
                accessObj.setEndNodeId(endNodeId);
277
                Stack nodeStack = accessObj.getSubTreeNodeList();
278
                accessObj.setSubTreeNodeStack(nodeStack);
279
                // add this access obj into vector
280
                result.add(accessObj);
281
                // Get the top level access subtree control
282
                if (level != null && level.equals(TOPLEVEL)) {
283
                    topAccessSection = accessObj;
284
                }
285
            }
286
            pstmt.close();
287
        }//try
288
        catch (SQLException e) {
289
            throw new SAXException(
290
                    "EMLSAXHandler.getAccessSubTreeListFromDB(): "
291
                            + e.getMessage());
292
        }//catch
293
        finally {
294
            try {
295
                pstmt.close();
296
            } catch (SQLException ee) {
297
                throw new SAXException(
298
                        "EMLSAXHandler.getAccessSubTreeListFromDB(): "
299
                                + ee.getMessage());
300
            }
301
        }//finally
302
        return result;
303
    }
304

  
305
    /** SAX Handler that is called at the start of each XML element */
306
    public void startElement(String uri, String localName, String qName,
307
            Attributes atts) throws SAXException
308
    {
309
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
310
        // for element <acl....> both qname and local name is "eml"
311
        // uri is namesapce
312
        MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
313
        MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
314
        MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
315

  
316
        DBSAXNode parentNode = null;
317
        DBSAXNode currentNode = null;
318

  
319
        if (!handleInlineData) {
320
            // Get a reference to the parent node for the id
321
            try {
322
                parentNode = (DBSAXNode) nodeStack.peek();
323
            } catch (EmptyStackException e) {
324
                parentNode = null;
325
            }
326

  
327
            //start handle inline data
328
            if (localName.equals(INLINE)) {
329
                handleInlineData = true;
330
                inLineDataIndex++;
331
                //intitialize namespace hash for in line data
332
                inlineDataNameSpace = new Hashtable();
333
                //initialize file writer
334
                String docidWithoutRev = MetaCatUtil.getDocIdFromString(docid);
335
                String seperator = MetaCatUtil.getOption("accNumSeparator");
336
                // the new file name will look like docid.rev.2
337
                inlineDataFileName = docidWithoutRev + seperator + revision
338
                        + seperator + inLineDataIndex;
339
                inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
340
                // put the inline file id into a vector. If upload failed,
341
                // metacat will
342
                // delete the inline data file
343
                inlineFileIDList.add(inlineDataFileName);
344

  
345
            }
346

  
347
            // If hit a text node, we need write this text for current's parent
348
            // node
349
            // This will happend if the element is mixted
350
            if (hitTextNode && parentNode != null) {
351
                //compare text node data for unchangesubtree
352
                if (startCriticalSubTree) {
353
                    compareTextNode(currentUnChangedableSubtreeNodeStack,
354
                            textBuffer, PERMISSIONERROR);
355
                }//if
356

  
357
                //compare top level access module
358
                if (processTopLeverAccess && needCheckingAccessModule) {
359
                    compareTextNode(currentUnchangableAccessModuleNodeStack,
360
                            textBuffer, UPDATEACCESSERROR);
361
                }
362

  
363
                if (needCheckingAccessModule
364
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
365
                    // stored the pull out nodes into storedNode stack
366
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
367
                            null, null, MetaCatUtil.normalize(textBuffer
368
                                    .toString()));
369
                    storedAccessNodeStack.push(nodeElement);
370

  
371
                }
372

  
373
                // write the textbuffer into db for parent node.
374
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
375
                        parentNode);
376
                // rest hitTextNode
377
                hitTextNode = false;
378
                // reset textbuffer
379
                textBuffer = null;
380
                textBuffer = new StringBuffer();
381

  
382
            }
383

  
384
            // Document representation that points to the root document node
385
            if (atFirstElement) {
386
                atFirstElement = false;
387
                // If no DOCTYPE declaration: docname = root element
388
                // doctype = root element name or name space
389
                if (docname == null) {
390
                    docname = localName;
391
                    // if uri isn't null doctype = uri(namespace)
392
                    // othewise root element
393
                    if (uri != null && !(uri.trim()).equals("")) {
394
                        doctype = uri;
395
                    } else {
396
                        doctype = docname;
397
                    }
398
                    MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
399
                    MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
400
                } else if (doctype == null) {
401
                    // because docname is not null and it is declared in dtd
402
                    // so could not be in schema, no namespace
403
                    doctype = docname;
404
                    MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
405
                }
406
                rootNode.writeNodename(docname);
407
                try {
408
                    // for validated XML Documents store a reference to XML DB
409
                    // Catalog
410
                    // Because this is select statement and it needn't to roll
411
                    // back if
412
                    // insert document action fialed.
413
                    // In order to decrease DBConnection usage count, we get a
414
                    // new
415
                    // dbconnection from pool
416
                    String catalogid = null;
417
                    DBConnection dbConn = null;
418
                    int serialNumber = -1;
419

  
420
                    try {
421
                        // Get dbconnection
422
                        dbConn = DBConnectionPool
423
                                .getDBConnection("DBSAXHandler.startElement");
424
                        serialNumber = dbConn.getCheckOutSerialNumber();
425

  
426
                        Statement stmt = dbConn.createStatement();
427
                        ResultSet rs = stmt
428
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
429
                                        + "WHERE entry_type = 'Schema' "
430
                                        + "AND public_id = '" + doctype + "'");
431
                        boolean hasRow = rs.next();
432
                        if (hasRow) {
433
                            catalogid = rs.getString(1);
434
                        }
435
                        stmt.close();
436
                    }//try
437
                    finally {
438
                        // Return dbconnection
439
                        DBConnectionPool.returnDBConnection(dbConn,
440
                                serialNumber);
441
                    }//finally
442

  
443
                    //create documentImpl object by the constructor which can
444
                    // specify
445
                    //the revision
446
                    currentDocument = new DocumentImpl(connection, rootNode
447
                            .getNodeID(), docname, doctype, docid, revision,
448
                            action, user, this.pub, catalogid, this.serverCode);
449

  
450
                } catch (Exception ane) {
451
                    throw (new SAXException(
452
                            "Error in EMLSaxHandler.startElement " + action,
453
                            ane));
454
                }
455
            }
456

  
457
            // Create the current node representation
458
            currentNode = new DBSAXNode(connection, qName, localName,
459
                    parentNode, currentDocument.getRootNodeID(), docid,
460
                    currentDocument.getDoctype());
461
            // Use a local variable to store the element node id
462
            // If this element is a start point of subtree(section), it will be
463
            // stored
464
            // otherwise, it will be discated
465
            long startNodeId = currentNode.getNodeID();
466
            // Add all of the namespaces
467
            String prefix = null;
468
            String nsuri = null;
469
            Enumeration prefixes = namespaces.keys();
470
            while (prefixes.hasMoreElements()) {
471
                prefix = (String) prefixes.nextElement();
472
                nsuri = (String) namespaces.get(prefix);
473
                endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
474
            }
475

  
476
            // Add all of the attributes
477
            for (int i = 0; i < atts.getLength(); i++) {
478
                String attributeName = atts.getQName(i);
479
                String attributeValue = atts.getValue(i);
480
                endNodeId = currentNode.setAttribute(attributeName,
481
                        attributeValue, docid);
482

  
483
                // To handle name space and schema location if the attribute
484
                // name is
485
                // xsi:schemaLocation. If the name space is in not in catalog
486
                // table
487
                // it will be regeistered.
488
                if (attributeName != null
489
                        && attributeName
490
                                .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
491
                    SchemaLocationResolver resolver = new SchemaLocationResolver(
492
                            attributeValue);
493
                    resolver.resolveNameSpace();
494

  
495
                } else if (attributeName != null && attributeName.equals(ID)) {
496

  
497
                    //check unchangedable subtree hash if contains this
498
                    // subtree id
499
                    if (unChangableSubTreeHash.containsKey(attributeValue)) {
500
                        // this subtree couldn't be changed by the user and
501
                        // move it from hash
502
                        SubTree currentUnChangedableSubtree = (SubTree) unChangableSubTreeHash
503
                                .remove(attributeValue);
504
                        currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree
505
                                .getSubTreeNodeStack();
506
                        startCriticalSubTree = true;
507
                        firstElementForCriticalSubTree = true;
508
                    }
509

  
510
                    // handle subtree info
511
                    SubTree subTress = new SubTree();
512
                    // set sub tree id
513
                    subTress.setSubTreeId(attributeValue);
514
                    // set sub tree sstart lement name
515
                    subTress.setStartElementName(currentNode.getTagName());
516
                    // set start node number
517
                    subTress.setStartNodeId(startNodeId);
518
                    // add to stack, but it didn't get end node id yet
519
                    subTreeInfoStack.push(subTress);
520

  
521
                }
522
            }//for
523

  
524
            // handle access stuff
525
            if (localName.equals(ACCESS)) {
526
                // if it is in addtionalmetacat
527
                if (parentNode.getTagName() == ADDITIONALMETADATA) {
528
                    processAdditionalAccess = true;
529

  
530
                } else {
531
                    //make sure the access is top level
532
                    // this mean current node's parent's parent should be "eml"
533
                    DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
534
                                                                    // parent
535
                                                                    // node
536
                    //peek out grandParentNode
537
                    DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
538
                    // put parent node back
539
                    nodeStack.push(tmpNode);
540
                    String grandParentTag = grandParentNode.getTagName();
541
                    if (grandParentTag.equals(EML)) {
542
                        processTopLeverAccess = true;
543
                    } else {
544
                        // process other access embedded into resource level
545
                        // module
546
                        processOtherAccess = true;
547
                    }
548

  
549
                }
550
                // create access object
551
                accessObject = new AccessSection();
552
                // set permission order
553
                String permOrder = currentNode.getAttribute(ORDER);
554
                accessObject.setPermissionOrder(permOrder);
555
                // set access id
556
                String accessId = currentNode.getAttribute(ID);
557
                accessObject.setSubTreeId(accessId);
558
                accessObject.setStartNodeId(startNodeId);
559
                accessObject.setDocId(docid);
560

  
561
                // load top level node stack to
562
                // currentUnchangableAccessModuleNodeStack
563
                if (processTopLeverAccess && needCheckingAccessModule) {
564
                    // get the node stack for
565
                    currentUnchangableAccessModuleNodeStack = topAccessSection
566
                            .getSubTreeNodeStack();
567
                }
568

  
569
            }
570
            // Set up a access rule for allow
571
            else if (parentNode.getTagName() != null
572
                    && (parentNode.getTagName()).equals(ACCESS)
573
                    && localName.equals(ALLOW)) {
574

  
575
                accessRule = new AccessRule();
576

  
577
                //set permission type "allow"
578
                accessRule.setPermissionType(ALLOW);
579

  
580
            }
581
            // set up an access rule for den
582
            else if (parentNode.getTagName() != null
583
                    && (parentNode.getTagName()).equals(ACCESS)
584
                    && localName.equals(DENY)) {
585
                accessRule = new AccessRule();
586
                //set permission type "allow"
587
                accessRule.setPermissionType(DENY);
588
            }
589

  
590
            // Add the node to the stack, so that any text data can be
591
            // added as it is encountered
592
            nodeStack.push(currentNode);
593
            // Add the node to the vector used by thread for writing XML Index
594
            nodeIndex.addElement(currentNode);
595

  
596
            // handle critical subtree
597
            if (startCriticalSubTree && firstElementForCriticalSubTree) {
598
                //store the element name
599
                firstElementNameForCriticalSubTree = qName;
600
                firstElementForCriticalSubTree = false;
601
            }//for first element
602

  
603
            // handle critical subtree
604
            if (startCriticalSubTree) {
605
                compareElementNameSpaceAttributes(
606
                        currentUnChangedableSubtreeNodeStack, namespaces, atts,
607
                        localName, PERMISSIONERROR);
608

  
609
            }
610
            //compare top access level module
611
            if (processTopLeverAccess && needCheckingAccessModule) {
612
                compareElementNameSpaceAttributes(
613
                        currentUnchangableAccessModuleNodeStack, namespaces,
614
                        atts, localName, UPDATEACCESSERROR);
615

  
616
            }
617

  
618
            // store access module element and attributes into stored stack
619
            if (needCheckingAccessModule
620
                    && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
621
                // stored the pull out nodes into storedNode stack
622
                NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
623
                        localName, prefix, MetaCatUtil.normalize(null));
624
                storedAccessNodeStack.push(nodeElement);
625
                for (int i = 0; i < atts.getLength(); i++) {
626
                    String attributeName = atts.getQName(i);
627
                    String attributeValue = atts.getValue(i);
628
                    NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2,
629
                            "ATTRIBUTE", attributeName, null, MetaCatUtil
630
                                    .normalize(attributeValue));
631
                    storedAccessNodeStack.push(nodeAttribute);
632
                }
633

  
634
            }
635

  
636
            // reset name space
637
            namespaces = null;
638
            namespaces = new Hashtable();
639
        }//not inline data
640
        else {
641
            // we don't buffer the inline data in characters() method
642
            // so start character don't need to hand text node.
643

  
644
            // inline data may be the xml format.
645
            StringBuffer inlineElements = new StringBuffer();
646
            inlineElements.append("<").append(qName);
647
            // append attributes
648
            for (int i = 0; i < atts.getLength(); i++) {
649
                String attributeName = atts.getQName(i);
650
                String attributeValue = atts.getValue(i);
651
                inlineElements.append(" ");
652
                inlineElements.append(attributeName);
653
                inlineElements.append("=\"");
654
                inlineElements.append(attributeValue);
655
                inlineElements.append("\"");
656
            }
657
            // append namespace
658
            String prefix = null;
659
            String nsuri = null;
660
            Enumeration prefixes = inlineDataNameSpace.keys();
661
            while (prefixes.hasMoreElements()) {
662
                prefix = (String) prefixes.nextElement();
663
                nsuri = (String) namespaces.get(prefix);
664
                inlineElements.append(" ");
665
                inlineElements.append("xmlns:");
666
                inlineElements.append(prefix);
667
                inlineElements.append("=\"");
668
                inlineElements.append(nsuri);
669
                inlineElements.append("\"");
670
            }
671
            inlineElements.append(">");
672
            //reset inline data name space
673
            inlineDataNameSpace = null;
674
            inlineDataNameSpace = new Hashtable();
675
            //write inline data into file
676
            MetaCatUtil.debugMessage("the inline element data is: "
677
                    + inlineElements.toString(), 50);
678
            writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
679
        }//else
680

  
681
    }
682

  
683
    private void compareElementNameSpaceAttributes(Stack unchangableNodeStack,
684
            Hashtable nameSpaces, Attributes attributes, String localName,
685
            String error) throws SAXException
686
    {
687
        //Get element subtree node stack (element node)
688
        NodeRecord elementNode = null;
689
        try {
690
            elementNode = (NodeRecord) unchangableNodeStack.pop();
691
        } catch (EmptyStackException ee) {
692
            MetaCatUtil
693
                    .debugMessage("Node stack is empty for element data", 35);
694
            throw new SAXException(error);
695
        }
696
        MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
697
        MetaCatUtil.debugMessage("node type from stack: "
698
                + elementNode.getNodeType(), 40);
699
        MetaCatUtil.debugMessage("node name from xml document: " + localName,
700
                40);
701
        MetaCatUtil.debugMessage("node name from stack: "
702
                + elementNode.getNodeName(), 40);
703
        MetaCatUtil.debugMessage("node data from stack: "
704
                + elementNode.getNodeData(), 40);
705
        MetaCatUtil.debugMessage("node id is: " + elementNode.getNodeId(), 40);
706
        // if this node is not element or local name not equal or name space
707
        // not
708
        // equals, throw an exception
709
        if (!elementNode.getNodeType().equals("ELEMENT")
710
                || !localName.equals(elementNode.getNodeName()))
711
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
712
        {
713
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
714
            MetaCatUtil.debugMessage("current node type from xml is ELEMENT",
715
                    40);
716
            MetaCatUtil.debugMessage("node type from stack: "
717
                    + elementNode.getNodeType(), 40);
718
            MetaCatUtil.debugMessage("node name from xml document: "
719
                    + localName, 40);
720
            MetaCatUtil.debugMessage("node name from stack: "
721
                    + elementNode.getNodeName(), 40);
722
            MetaCatUtil.debugMessage("node data from stack: "
723
                    + elementNode.getNodeData(), 40);
724
            MetaCatUtil.debugMessage("node id is: " + elementNode.getNodeId(),
725
                    40);
726
            throw new SAXException(error);
727
        }
728

  
729
        //compare namespace
730
        Enumeration nameEn = nameSpaces.keys();
731
        while (nameEn.hasMoreElements()) {
732
            //Get namespacke node stack (element node)
733
            NodeRecord nameNode = null;
734
            try {
735
                nameNode = (NodeRecord) unchangableNodeStack.pop();
736
            } catch (EmptyStackException ee) {
737
                MetaCatUtil.debugMessage(
738
                        "Node stack is empty for namespace data", 35);
739
                throw new SAXException(error);
740
            }
741

  
742
            String prefixName = (String) nameEn.nextElement();
743
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
744
            if (!nameNode.getNodeType().equals("NAMESPACE")
745
                    || !prefixName.equals(nameNode.getNodeName())
746
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
747
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
748
                MetaCatUtil.debugMessage(
749
                        "current node type from xml is NAMESPACE", 40);
750
                MetaCatUtil.debugMessage("node type from stack: "
751
                        + nameNode.getNodeType(), 40);
752
                MetaCatUtil.debugMessage("current node name from xml is: "
753
                        + prefixName, 40);
754
                MetaCatUtil.debugMessage("node name from stack: "
755
                        + nameNode.getNodeName(), 40);
756
                MetaCatUtil.debugMessage("current node data from xml is: "
757
                        + nameSpaceUri, 40);
758
                MetaCatUtil.debugMessage("node data from stack: "
759
                        + nameNode.getNodeData(), 40);
760
                MetaCatUtil.debugMessage("node id is: " + nameNode.getNodeId(),
761
                        40);
762
                throw new SAXException(error);
763
            }
764

  
765
        }//while
766

  
767
        //compare attributes
768
        for (int i = 0; i < attributes.getLength(); i++) {
769
            NodeRecord attriNode = null;
770
            try {
771
                attriNode = (NodeRecord) unchangableNodeStack.pop();
772

  
773
            } catch (EmptyStackException ee) {
774
                MetaCatUtil.debugMessage(
775
                        "Node stack is empty for attribute data", 35);
776
                throw new SAXException(error);
777
            }
778
            String attributeName = attributes.getQName(i);
779
            String attributeValue = attributes.getValue(i);
780
            MetaCatUtil.debugMessage(
781
                    "current node type from xml is ATTRIBUTE ", 40);
782
            MetaCatUtil.debugMessage("node type from stack: "
783
                    + attriNode.getNodeType(), 40);
784
            MetaCatUtil.debugMessage("current node name from xml is: "
785
                    + attributeName, 40);
786
            MetaCatUtil.debugMessage("node name from stack: "
787
                    + attriNode.getNodeName(), 40);
788
            MetaCatUtil.debugMessage("current node data from xml is: "
789
                    + attributeValue, 40);
790
            MetaCatUtil.debugMessage("node data from stack: "
791
                    + attriNode.getNodeData(), 40);
792
            MetaCatUtil.debugMessage("node id  is: " + attriNode.getNodeId(),
793
                    40);
794

  
795
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
796
                    || !attributeName.equals(attriNode.getNodeName())
797
                    || !attributeValue.equals(attriNode.getNodeData())) {
798
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
799
                MetaCatUtil.debugMessage(
800
                        "current node type from xml is ATTRIBUTE ", 40);
801
                MetaCatUtil.debugMessage("node type from stack: "
802
                        + attriNode.getNodeType(), 40);
803
                MetaCatUtil.debugMessage("current node name from xml is: "
804
                        + attributeName, 40);
805
                MetaCatUtil.debugMessage("node name from stack: "
806
                        + attriNode.getNodeName(), 40);
807
                MetaCatUtil.debugMessage("current node data from xml is: "
808
                        + attributeValue, 40);
809
                MetaCatUtil.debugMessage("node data from stack: "
810
                        + attriNode.getNodeData(), 40);
811
                MetaCatUtil.debugMessage("node is: " + attriNode.getNodeId(),
812
                        40);
813
                throw new SAXException(error);
814
            }
815
        }//for
816

  
817
    }
818

  
819
    /* mehtod to compare current text node and node in db */
820
    private void compareTextNode(Stack nodeStack, StringBuffer text,
821
            String error) throws SAXException
822
    {
823
        NodeRecord node = null;
824
        //get node from current stack
825
        try {
826
            node = (NodeRecord) nodeStack.pop();
827
        } catch (EmptyStackException ee) {
828
            MetaCatUtil.debugMessage(
829
                    "Node stack is empty for text data in startElement", 35);
830
            throw new SAXException(error);
831
        }
832
        MetaCatUtil.debugMessage(
833
                "current node type from xml is TEXT in start element", 40);
834
        MetaCatUtil.debugMessage("node type from stack: " + node.getNodeType(),
835
                40);
836
        MetaCatUtil.debugMessage("current node data from xml is: "
837
                + text.toString(), 40);
838
        MetaCatUtil.debugMessage("node data from stack: " + node.getNodeData(),
839
                40);
840
        MetaCatUtil.debugMessage("node name from stack: " + node.getNodeName(),
841
                40);
842
        MetaCatUtil.debugMessage("node is: " + node.getNodeId(), 40);
843
        if (!node.getNodeType().equals("TEXT")
844
                || !(text.toString()).equals(node.getNodeData())) {
845
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
846
            MetaCatUtil.debugMessage(
847
                    "current node type from xml is TEXT in start element", 40);
848
            MetaCatUtil.debugMessage("node type from stack: "
849
                    + node.getNodeType(), 40);
850
            MetaCatUtil.debugMessage("current node data from xml is: "
851
                    + text.toString(), 40);
852
            MetaCatUtil.debugMessage("node data from stack: "
853
                    + node.getNodeData(), 40);
854
            MetaCatUtil.debugMessage("node name from stack: "
855
                    + node.getNodeName(), 40);
856
            MetaCatUtil.debugMessage("node is: " + node.getNodeId(), 40);
857
            throw new SAXException(error);
858
        }//if
859
    }
860

  
861
    /** SAX Handler that is called for each XML text node */
862
    public void characters(char[] cbuf, int start, int len) throws SAXException
863
    {
864
        MetaCatUtil.debugMessage("CHARACTERS", 50);
865
        if (!handleInlineData) {
866
            // buffer all text nodes for same element. This is for text was
867
            // splited
868
            // into different nodes
869
            textBuffer.append(new String(cbuf, start, len));
870
            // set hittextnode true
871
            hitTextNode = true;
872
            // if text buffer .size is greater than max, write it to db.
873
            // so we can save memory
874
            if (textBuffer.length() > MAXDATACHARS) {
875
                MetaCatUtil
876
                        .debugMessage(
877
                                "Write text into DB in charaters"
878
                                        + " when text buffer size is greater than maxmum number",
879
                                50);
880
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
881
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
882
                        currentNode);
883
                textBuffer = null;
884
                textBuffer = new StringBuffer();
885
            }
886
        } else {
887
            // this is inline data and write file system directly
888
            // we don't need to buffered it.
889
            StringBuffer inlineText = new StringBuffer();
890
            inlineText.append(new String(cbuf, start, len));
891
            MetaCatUtil.debugMessage(
892
                    "The inline text data write into file system: "
893
                            + inlineText.toString(), 50);
894
            writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
895
        }
896
    }
897

  
898
    /** SAX Handler that is called at the end of each XML element */
899
    public void endElement(String uri, String localName, String qName)
900
            throws SAXException
901
    {
902
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
903

  
904
        if (localName.equals(INLINE) && handleInlineData) {
905
            // Get the node from the stack
906
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
907
            String currentTag = currentNode.getTagName();
908
            MetaCatUtil.debugMessage("End of inline data", 35);
909
            // close file writer
910
            try {
911
                inlineDataFileWriter.close();
912
                handleInlineData = false;
913
            } catch (IOException ioe) {
914
                throw new SAXException(ioe.getMessage());
915
            }
916

  
917
            //check if user changed inine data or not if user doesn't have
918
            // write permission
919
            if (startCriticalSubTree) {
920
                NodeRecord node = null;
921
                String inlineData;
922
                try {
923
                    node = (NodeRecord) currentUnChangedableSubtreeNodeStack
924
                            .pop();
925
                    // get file name from db
926
                    String fileName = node.getNodeData();
927
                    MetaCatUtil.debugMessage("in handle inline data", 35);
928
                    MetaCatUtil.debugMessage(
929
                            "the inline data file name from node is: "
930
                                    + fileName, 40);
931
                    if (!compareInlineDataFiles(fileName, inlineDataFileName)) {
932
                        MetaCatUtil.debugMessage(
933
                                "inline data was changed by a user"
934
                                        + " who doesn't have permission", 30);
935
                        throw new SAXException(PERMISSIONERROR);
936
                    }
937
                } catch (EmptyStackException ee) {
938
                    MetaCatUtil.debugMessage(
939
                            "the stack is empty for text data", 32);
940
                    throw new SAXException(PERMISSIONERROR);
941
                } catch (McdbException eee) {
942
                    throw new SAXException(eee.getMessage());
943
                } finally {
944
                    // delete the inline data file already in file system
945
                    deleteInlineDataFile(inlineDataFileName);
946
                }
947

  
948
            }//if
949
            // write put inline data file name into text buffer (without path)
950
            textBuffer = new StringBuffer(inlineDataFileName);
951
            // write file name into db
952
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
953
                    currentNode);
954
            // reset textbuff
955
            textBuffer = null;
956
            textBuffer = new StringBuffer();
957
            return;
958
        }
959

  
960
        if (!handleInlineData) {
961
            // Get the node from the stack
962
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
963
            String currentTag = currentNode.getTagName();
964

  
965
            // If before the end element, the parser hit text nodes and store
966
            // them
967
            // into the buffer, write the buffer to data base. The reason we
968
            // put
969
            // write database here is for xerces some time split text node
970
            if (hitTextNode) {
971
                // get access value
972
                String data = null;
973
                // add principal
974
                if (currentTag.equals(PRINCIPAL) && accessRule != null) {
975
                    data = (textBuffer.toString()).trim();
976
                    accessRule.addPrincipal(data);
977

  
978
                } else if (currentTag.equals(PERMISSION) && accessRule != null) {
979
                    data = (textBuffer.toString()).trim();
980
                    // we conbine different a permission into one value
981
                    int permission = accessRule.getPermission();
982
                    // add permision
983
                    if (data.toUpperCase().equals(READSTRING)) {
984
                        permission = permission | READ;
985
                    } else if (data.toUpperCase().equals(WRITESTRING)) {
986
                        permission = permission | WRITE;
987
                    } else if (data.toUpperCase().equals(CHMODSTRING)) {
988
                        permission = permission | CHMOD;
989
                    } else if (data.toUpperCase().equals(ALLSTRING)) {
990
                        permission = permission | ALL;
991
                    }
992
                    accessRule.setPermission(permission);
993
                }
994
                // put additionalmetadata/describes into vector
995
                else if (currentTag.equals(DESCRIBES)) {
996
                    data = (textBuffer.toString()).trim();
997
                    describesId.add(data);
998
                } else if (currentTag.equals(REFERENCES)
999
                        && (processTopLeverAccess || processAdditionalAccess || processOtherAccess)) {
1000
                    // get reference
1001
                    data = (textBuffer.toString()).trim();
1002
                    // put reference id into accessSection
1003
                    accessObject.setReferences(data);
1004

  
1005
                } else if (currentTag.equals(URL)) {
1006
                    //handle online data, make sure its'parent is online
1007
                    DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1008
                    if (parentNode != null && parentNode.getTagName() != null
1009
                            && parentNode.getTagName().equals(ONLINE)) {
1010
                        // if online data is in local metacat, add it to the
1011
                        // vector
1012
                        data = (textBuffer.toString()).trim();
1013
                        if (data != null
1014
                                && (data.indexOf(MetaCatUtil
1015
                                        .getOption("httpserver")) != -1 || data
1016
                                        .indexOf(MetaCatUtil
1017
                                                .getOption("server")) != -1)) {
1018
                            // Get docid from url
1019
                            String dataId = MetaCatUtil
1020
                                    .getDocIdWithRevFromOnlineURL(data);
1021
                            // add to vector
1022
                            onlineDataFileIdVector.add(dataId);
1023
                        }//if
1024
                    }//if
1025
                }//else if
1026
                // write text to db if it is not inline data
1027
                //if (!localName.equals(INLINE))
1028
                {
1029
                    MetaCatUtil.debugMessage(
1030
                            "Write text into DB in End Element", 50);
1031
                    //compare text node if need
1032
                    if (startCriticalSubTree) {
1033
                        compareTextNode(currentUnChangedableSubtreeNodeStack,
1034
                                textBuffer, PERMISSIONERROR);
1035
                    }//if
1036
                    //compare top level access module
1037
                    if (processTopLeverAccess && needCheckingAccessModule) {
1038
                        compareTextNode(
1039
                                currentUnchangableAccessModuleNodeStack,
1040
                                textBuffer, UPDATEACCESSERROR);
1041
                    }
1042
                    // write text node into db
1043
                    endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1044
                            currentNode);
1045
                }
1046
                if (needCheckingAccessModule
1047
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1048
                    // stored the pull out nodes into storedNode stack
1049
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1050
                            null, null, MetaCatUtil.normalize(textBuffer
1051
                                    .toString()));
1052
                    storedAccessNodeStack.push(nodeElement);
1053

  
1054
                }
1055
            }//if
1056

  
1057
            //end crtical subtree(user doesn't have permission to write)
1058
            //When reach the first element and stack is empty
1059
            if (localName.equals(firstElementNameForCriticalSubTree)
1060
                    && currentUnChangedableSubtreeNodeStack.isEmpty()) {
1061
                startCriticalSubTree = false;
1062
            }
1063

  
1064
            //set hitText false
1065
            hitTextNode = false;
1066
            // reset textbuff
1067
            textBuffer = null;
1068
            textBuffer = new StringBuffer();
1069

  
1070
            // hand sub stree stuff
1071
            if (!subTreeInfoStack.empty()) {
1072
                SubTree tree = (SubTree) subTreeInfoStack.peek();// get last
1073
                                                                 // subtree
1074
                if (tree != null && tree.getStartElementName() != null
1075
                        && (tree.getStartElementName()).equals(currentTag)) {
1076
                    // find the end of sub tree and set the end node id
1077
                    tree.setEndNodeId(endNodeId);
1078
                    // add the subtree into the final store palace
1079
                    subTreeList.add(tree);
1080
                    // get rid of it from stack
1081
                    subTreeInfoStack.pop();
1082
                }//if
1083
            }//if
1084

  
1085
            // access stuff
1086
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
1087
                // finish parser a ccess rule and assign it to new one
1088
                AccessRule newRule = accessRule;
1089
                //add the new rule to access section object
1090
                accessObject.addAccessRule(newRule);
1091
                // reset access rule
1092
                accessRule = null;
1093
            } else if (currentTag.equals(ACCESS)) {
1094
                // finish parse a access setction and assign it to new one
1095

  
1096
                accessObject.setEndNodeId(endNodeId);
1097
                AccessSection newAccessObject = accessObject;
1098

  
1099
                if (newAccessObject != null) {
1100

  
1101
                    // add the accessSection into a vector to store it
1102
                    // if it is not a reference, need to store it
1103
                    if (newAccessObject.getReferences() == null) {
1104

  
1105
                        newAccessObject
1106
                                .setStoredTmpNodeStack(storedAccessNodeStack);
1107
                        accessObjectList.add(newAccessObject);
1108
                    }
1109
                    if (processTopLeverAccess) {
1110

  
1111
                        // top level access control will handle whole document
1112
                        // -docid
1113
                        topLevelAccessControlMap.put(docid, newAccessObject);
1114
                        // reset processtopleveraccess tag
1115

  
1116
                    }//if
1117
                    else if (processAdditionalAccess) {
1118
                        // for additional control
1119
                        // put everything in describes value and access object
1120
                        // into hash
1121
                        for (int i = 0; i < describesId.size(); i++) {
1122

  
1123
                            String subId = (String) describesId.elementAt(i);
1124
                            if (subId != null) {
1125
                                additionalAccessControlMap.put(subId,
1126
                                        newAccessObject);
1127
                            }//if
1128
                        }//for
1129
                        // add this hashtable in to vector
1130

  
1131
                        additionalAccessMapList.add(additionalAccessControlMap);
1132
                        // reset this hashtable in order to store another
1133
                        // additional
1134
                        //accesscontrol
1135
                        additionalAccessControlMap = null;
1136
                        additionalAccessControlMap = new Hashtable();
1137
                    }//if
1138

  
1139
                }//if
1140
                //check if access node stack is empty after parsing top access
1141
                //module
1142

  
1143
                if (needCheckingAccessModule && processTopLeverAccess
1144
                        && !currentUnchangableAccessModuleNodeStack.isEmpty()) {
1145

  
1146
                    MetaCatUtil.debugMessage(
1147
                            "Access node stack is not empty after "
1148
                                    + "parsing access subtree", 40);
1149
                    throw new SAXException(UPDATEACCESSERROR);
1150

  
1151
                }
1152
                //reset access section object
1153

  
1154
                accessObject = null;
1155

  
1156
                // reset tmp stored node stack
1157
                storedAccessNodeStack = null;
1158
                storedAccessNodeStack = new Stack();
1159

  
1160
                // reset flag
1161
                processAdditionalAccess = false;
1162
                processTopLeverAccess = false;
1163
                processOtherAccess = false;
1164

  
1165
            } else if (currentTag.equals(ADDITIONALMETADATA)) {
1166
                //reset describesId
1167
                describesId = null;
1168
                describesId = new Vector();
1169
            }
1170
        } else {
1171
            // this is in inline part
1172
            StringBuffer endElement = new StringBuffer();
1173
            endElement.append("</");
1174
            endElement.append(qName);
1175
            endElement.append(">");
1176
            MetaCatUtil.debugMessage("inline endElement: "
1177
                    + endElement.toString(), 50);
1178
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1179
        }
1180
    }
1181

  
1182
    /**
1183
     * SAX Handler that receives notification of comments in the DTD
1184
     */
1185
    public void comment(char[] ch, int start, int length) throws SAXException
1186
    {
1187
        MetaCatUtil.debugMessage("COMMENT", 50);
1188
        if (!handleInlineData) {
1189
            if (!processingDTD) {
1190
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1191
                String str = new String(ch, start, length);
1192

  
1193
                //compare comment if need
1194
                if (startCriticalSubTree) {
1195
                    compareCommentNode(currentUnChangedableSubtreeNodeStack,
1196
                            str, PERMISSIONERROR);
1197
                }//if
1198
                //compare top level access module
1199
                if (processTopLeverAccess && needCheckingAccessModule) {
1200
                    compareCommentNode(currentUnchangableAccessModuleNodeStack,
1201
                            str, UPDATEACCESSERROR);
1202
                }
1203
                endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
1204
                        str, docid);
1205
                if (needCheckingAccessModule
1206
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1207
                    // stored the pull out nodes into storedNode stack
1208
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2,
1209
                            "COMMENT", null, null, MetaCatUtil.normalize(str));
1210
                    storedAccessNodeStack.push(nodeElement);
1211

  
1212
                }
1213
            }
1214
        } else {
1215
            // inline data comment
1216
            StringBuffer inlineComment = new StringBuffer();
1217
            inlineComment.append("<!--");
1218
            inlineComment.append(new String(ch, start, length));
1219
            inlineComment.append("-->");
1220
            MetaCatUtil.debugMessage("inline data comment: "
1221
                    + inlineComment.toString(), 50);
1222
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1223
        }
1224
    }
1225

  
1226
    /* Comparet comment from xml and db */
1227
    private void compareCommentNode(Stack nodeStack, String string, String error)
1228
            throws SAXException
1229
    {
1230
        NodeRecord node = null;
1231
        try {
1232
            node = (NodeRecord) nodeStack.pop();
1233
        } catch (EmptyStackException ee) {
1234
            MetaCatUtil.debugMessage("the stack is empty for comment data", 32);
1235
            throw new SAXException(error);
1236
        }
1237
        MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
1238
        MetaCatUtil.debugMessage("node type from stack: " + node.getNodeType(),
1239
                40);
1240
        MetaCatUtil
1241
                .debugMessage("current node data from xml is: " + string, 40);
1242
        MetaCatUtil.debugMessage("node data from stack: " + node.getNodeData(),
1243
                40);
1244
        MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(), 40);
1245
        // if not consistent terminate program and throw a exception
1246
        if (!node.getNodeType().equals("COMMENT")
1247
                || !string.equals(node.getNodeData())) {
1248
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1249
            MetaCatUtil.debugMessage("current node type from xml is COMMENT",
1250
                    40);
1251
            MetaCatUtil.debugMessage("node type from stack: "
1252
                    + node.getNodeType(), 40);
1253
            MetaCatUtil.debugMessage(
1254
                    "current node data from xml is: " + string, 40);
1255
            MetaCatUtil.debugMessage("node data from stack: "
1256
                    + node.getNodeData(), 40);
1257
            MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(),
1258
                    40);
1259
            throw new SAXException(error);
1260
        }//if
1261
    }
1262

  
1263
    /**
1264
     * SAX Handler called once for each processing instruction found: node that
1265
     * PI may occur before or after the root element.
1266
     */
1267
    public void processingInstruction(String target, String data)
1268
            throws SAXException
1269
    {
1270
        MetaCatUtil.debugMessage("PI", 50);
1271
        if (!handleInlineData) {
1272
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1273
            endNodeId = currentNode.writeChildNodeToDB("PI", target, data,
1274
                    docid);
1275
        } else {
1276
            StringBuffer inlinePI = new StringBuffer();
1277
            inlinePI.append("<?");
1278
            inlinePI.append(target);
1279
            inlinePI.append(" ");
1280
            inlinePI.append(data);
1281
            inlinePI.append("?>");
1282
            MetaCatUtil.debugMessage("inline data pi is: "
1283
                    + inlinePI.toString(), 50);
1284
            writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1285
        }
1286
    }
1287

  
1288
    /** SAX Handler that is called at the start of Namespace */
1289
    public void startPrefixMapping(String prefix, String uri)
1290
            throws SAXException
1291
    {
1292
        MetaCatUtil.debugMessage("NAMESPACE", 50);
1293
        if (!handleInlineData) {
1294
            namespaces.put(prefix, uri);
1295
        } else {
1296
            inlineDataNameSpace.put(prefix, uri);
1297
        }
1298
    }
1299

  
1300
    /**
1301
     * SAX Handler that is called for each XML text node that is Ignorable
1302
     * white space
1303
     */
1304
    public void ignorableWhitespace(char[] cbuf, int start, int len)
1305
            throws SAXException
1306
    {
1307
        // When validation is turned "on", white spaces are reported here
1308
        // When validation is turned "off" white spaces are not reported here,
1309
        // but through characters() callback
1310
        MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
1311
        if (!handleInlineData) {
1312
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1313
            String data = null;
1314
            int leftover = len;
1315
            int offset = start;
1316
            boolean moredata = true;
1317

  
1318
            // This loop deals with the case where there are more characters
1319
            // than can fit in a single database text field (limit is
1320
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
1321
            // write a series of nodes that are MAXDATACHARS long, and then the
1322
            // final node contains the remainder
1323
            while (moredata) {
1324
                if (leftover > MAXDATACHARS) {
1325
                    data = new String(cbuf, offset, MAXDATACHARS);
1326
                    leftover -= MAXDATACHARS;
1327
                    offset += MAXDATACHARS;
1328
                } else {
1329
                    data = new String(cbuf, offset, leftover);
1330
                    moredata = false;
1331
                }
1332

  
1333
                //compare whitespace if need
1334
                if (startCriticalSubTree) {
1335
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1336
                            data, PERMISSIONERROR);
1337
                }//if
1338

  
1339
                //compare whitespace in access top module
1340
                if (processTopLeverAccess && needCheckingAccessModule) {
1341
                    compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1342
                            data, UPDATEACCESSERROR);
1343
                }
1344
                // Write the content of the node to the database
1345
                if (needCheckingAccessModule
1346
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1347
                    // stored the pull out nodes into storedNode stack
1348
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1349
                            null, null, MetaCatUtil.normalize(data));
1350
                    storedAccessNodeStack.push(nodeElement);
1351

  
1352
                }
1353
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1354
                        docid);
1355
            }
1356
        } else {
1357
            //This is inline data write to file directly
1358
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1359
                    start, len));
1360
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1361
        }
1362

  
1363
    }
1364

  
1365
    /* Compare whitespace from xml and db */
1366
    private void compareWhiteSpace(Stack nodeStack, String string, String error)
1367
            throws SAXException
1368
    {
1369
        NodeRecord node = null;
1370
        try {
1371
            node = (NodeRecord) nodeStack.pop();
1372
        } catch (EmptyStackException ee) {
1373
            MetaCatUtil.debugMessage("the stack is empty for whitespace data",
1374
                    32);
1375
            throw new SAXException(error);
1376
        }
1377
        if (!node.getNodeType().equals("TEXT")
1378
                || !string.equals(node.getNodeData())) {
1379
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1380
            MetaCatUtil.debugMessage(
1381
                    "current node type from xml is WHITESPACE TEXT", 40);
1382
            MetaCatUtil.debugMessage("node type from stack: "
1383
                    + node.getNodeType(), 40);
1384
            MetaCatUtil.debugMessage(
1385
                    "current node data from xml is: " + string, 40);
1386
            MetaCatUtil.debugMessage("node data from stack: "
1387
                    + node.getNodeData(), 40);
1388
            MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(),
1389
                    40);
1390
            throw new SAXException(error);
1391
        }//if
1392
    }
1393

  
1394
    /** SAX Handler that receives notification of end of the document */
1395
    public void endDocument() throws SAXException
1396
    {
1397
        MetaCatUtil.debugMessage("end Document", 50);
1398
        // There are some unchangable subtree didn't be compare
1399
        // This maybe cause user change the subtree id
1400
        if (!unChangableSubTreeHash.isEmpty()) {
1401
            MetaCatUtil.debugMessage("The unChangealbe subtree is not empty",
1402
                    40);
1403
            throw new SAXException(PERMISSIONERROR);
1404
        }
1405

  
1406
        // write access rule to db
1407
        writeAccessRuleToDB();
1408

  
1409
        //delete relation table
1410
        deleteRelations();
1411
        //write relations
1412
        for (int i = 0; i < onlineDataFileIdVector.size(); i++) {
1413
            String id = (String) onlineDataFileIdVector.elementAt(i);
1414
            writeOnlineDataFileIdIntoRelationTable(id);
1415
        }
1416

  
1417
        // Starting new thread for writing XML Index.
1418
        // It calls the run method of the thread.
1419
        boolean useXMLIndex = (new Boolean(MetaCatUtil.getOption("usexmlindex")))
1420
                .booleanValue();
1421
        if (useXMLIndex) {
1422
            try {
1423
                xmlIndex.start();
1424
            } catch (NullPointerException e) {
1425
                xmlIndex = null;
1426
                throw new SAXException(
1427
                        "Problem with starting thread for writing XML Index. "
1428
                                + e.getMessage());
1429
            }
1430
        }
1431
    }
1432

  
1433
    /* The method to write all access rule into db */
1434
    private void writeAccessRuleToDB() throws SAXException
1435
    {
1436
        //Delete old permssion
1437
        deletePermissionsInAccessTable(docid);
1438
        //write top leve access rule
1439
        writeTopLevelAccessRuleToDB();
1440
        //write additional access rule
1441
        //writeAddtionalAccessRuleToDB();
1442
    }//writeAccessRuleToDB
1443

  
1444
    /* The method to write top level access rule into db. */
1445
    private void writeTopLevelAccessRuleToDB() throws SAXException
1446
    {
1447

  
1448
        // for top document level
1449
        Object accessSection = topLevelAccessControlMap.get(docid);
1450
        boolean top = true;
1451
        String subSectionId = null;
1452
        if (accessSection != null) {
1453
            AccessSection accessSectionObj = (AccessSection) accessSection;
1454

  
1455
            // if accessSection is not null and is not reference
1456
            if (accessSectionObj.getReferences() == null) {
1457
                // write the top level access module into xml_accesssubtree to
1458
                // store info
1459
                // and then when update to check if the user can update it or
1460
                // not
1461
                deleteAccessSubTreeRecord(docid);
1462
                writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1463

  
1464
                //write access section into xml_access table
1465
                writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1466
                // write relative online data file into xml_access too.
1467
                /*
1468
                 * for (int i= 0; i <onlineDataFileIdVector.size(); i++) {
1469
                 * String id = (String)onlineDataFileIdVector.elementAt(i);
1470
                 * writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj,
1471
                 * id);
1472
                 */
1473

  
1474
            } else {
1475

  
1476
                // this is a reference and go trough the vector which contains
1477
                // all
1478
                // access object
1479
                String referenceId = accessSectionObj.getReferences();
1480
                boolean findAccessObject = false;
1481
                MetaCatUtil.debugMessage("referered id for top access: "
1482
                        + referenceId, 35);
1483
                for (int i = 0; i < accessObjectList.size(); i++) {
1484
                    AccessSection accessObj = (AccessSection) accessObjectList
1485
                            .elementAt(i);
1486
                    String accessObjId = accessObj.getSubTreeId();
1487
                    if (referenceId != null && accessObj != null
1488
                            && referenceId.equals(accessObjId)) {
1489
                        // make sure the user didn't change any thing in this
1490
                        // access moduel
1491
                        // too if user doesn't have all permission
1492
                        if (needCheckingAccessModule) {
1493

  
1494
                            Stack newStack = accessObj.getStoredTmpNodeStack();
1495
                            //revise order
1496
                            newStack = MetaCatUtil.reviseStack(newStack);
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff