Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author: jones $'
11
 *     '$Date: 2004-03-30 13:36:49 -0800 (Tue, 30 Mar 2004) $'
12
 * '$Revision: 2077 $'
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 EmlSAXHandler 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 EmlSAXHandler(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);
1497
                            // go throught the vector of
1498
                            // unChangableAccessSubtreevector
1499
                            // and find the one whose id is as same as
1500
                            // referenceid
1501
                            AccessSection oldAccessObj = getAccessSectionFromUnchangableAccessVector(referenceId);
1502
                            //if oldAccessObj is null something is wrong
1503
                            if (oldAccessObj == null) {
1504
                                throw new SAXException(UPDATEACCESSERROR);
1505
                            }//if
1506
                            else {
1507
                                // Get the node stack from old access obj
1508
                                Stack oldStack = oldAccessObj
1509
                                        .getSubTreeNodeStack();
1510
                                comparingNodeStacks(newStack, oldStack);
1511
                            }//else
1512
                        }//if
1513
                        // write accessobject into db
1514
                        writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1515
                        // add access rule for related on line data id too.
1516
                        /*
1517
                         * for (int j= 0; j <onlineDataFileIdVector.size();
1518
                         * j++) { String id =
1519
                         * (String)onlineDataFileIdVector.elementAt(j);
1520
                         * writeAccessRuleForRalatedDataFileIntoDB(accessObj,
1521
                         * id);
1522
                         */
1523

    
1524
                        //write the reference access into xml_accesssubtree
1525
                        // too
1526
                        // write the top level access module into
1527
                        // xml_accesssubtree to store info
1528
                        // and then when update to check if the user can update
1529
                        // it or not
1530
                        deleteAccessSubTreeRecord(docid);
1531
                        writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1532
                        writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1533
                        findAccessObject = true;
1534
                        break;
1535
                    }
1536
                }//for
1537
                // if we couldn't find an access subtree id for this reference
1538
                // id
1539
                if (!findAccessObject) { throw new SAXException(
1540
                        "The referenceid: " + referenceId
1541
                                + " is not access subtree"); }//if
1542
            }//else
1543

    
1544
        }//if
1545
        else {
1546
            // couldn't find a access section object
1547
            MetaCatUtil.debugMessage(
1548
                    "couldn't find access control for document: " + docid, 35);
1549
        }
1550

    
1551
    }//writeTopLevelAccessRuletoDB
1552

    
1553
    /* Given a subtree id and find the responding access section */
1554
    private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1555
    {
1556
        AccessSection result = null;
1557
        // Makse sure the id
1558
        if (id == null || id.equals("")) { return result; }
1559
        // go throught vector and find the list
1560
        for (int i = 0; i < unChangableAccessSubTreeVector.size(); i++) {
1561
            AccessSection accessObj = (AccessSection) unChangableAccessSubTreeVector
1562
                    .elementAt(i);
1563
            if (accessObj.getSubTreeId() != null
1564
                    && (accessObj.getSubTreeId()).equals(id)) {
1565
                result = accessObj;
1566
            }//if
1567
        }//for
1568
        return result;
1569
    }//getAccessSectionFromUnchangableAccessVector
1570

    
1571
    /* Compare two node stacks to see if they are same */
1572
    private void comparingNodeStacks(Stack stack1, Stack stack2)
1573
            throws SAXException
1574
    {
1575
        // make sure stack1 and stack2 are not empty
1576
        if (stack1.isEmpty() || stack2.isEmpty()) {
1577
            MetaCatUtil.debugMessage("Because stack is empty!", 35);
1578
            throw new SAXException(UPDATEACCESSERROR);
1579
        }
1580
        // go throw two stacks and compare every element
1581
        while (!stack1.isEmpty()) {
1582
            // Pop an element from stack1
1583
            NodeRecord record1 = (NodeRecord) stack1.pop();
1584
            // Pop an element from stack2(stack 2 maybe empty)
1585
            NodeRecord record2 = null;
1586
            try {
1587
                record2 = (NodeRecord) stack2.pop();
1588
            } catch (EmptyStackException ee) {
1589
                MetaCatUtil.debugMessage(
1590
                        "Node stack2 is empty but stack1 isn't!", 35);
1591
                throw new SAXException(UPDATEACCESSERROR);
1592
            }
1593
            // if two records are not same throw a exception
1594
            if (!record1.contentEquals(record2)) {
1595
                MetaCatUtil
1596
                        .debugMessage(
1597
                                "Two records from new and old stack are not "
1598
                                        + "same!", 30);
1599
                throw new SAXException(UPDATEACCESSERROR);
1600
            }//if
1601
        }//while
1602

    
1603
        // now stack1 is empty and we should make sure stack2 is empty too
1604
        if (!stack2.isEmpty()) {
1605
            MetaCatUtil.debugMessage(
1606
                    "stack2 still have some elements while stack "
1607
                            + "is empty! ", 30);
1608
            throw new SAXException(UPDATEACCESSERROR);
1609
        }//if
1610
    }//comparingNodeStacks
1611

    
1612
    /* The method to write addtional access rule into db. */
1613
    private void writeAddtionalAccessRuleToDB() throws SAXException
1614
    {
1615

    
1616
        PreparedStatement pstmt = null;
1617
        boolean topLevel = false;
1618
        // go through the vector which contains the additional access control
1619
        //hashtable. Each hashtable has info for one additonalmetadata
1620
        // container
1621
        for (int j = 0; j < additionalAccessMapList.size(); j++) {
1622

    
1623
            Hashtable accessControlMap = (Hashtable) additionalAccessMapList
1624
                    .elementAt(j);
1625
            // additional access rule
1626
            Enumeration en = accessControlMap.keys();
1627

    
1628
            while (en.hasMoreElements()) {
1629
                try {
1630
                    // Get subsection id
1631
                    String subSectionId = (String) en.nextElement();
1632
                    MetaCatUtil.debugMessage(
1633
                            "sub section id in additional access mapping"
1634
                                    + "(go through): " + subSectionId, 35);
1635

    
1636
                    if (subSectionId == null) { 
1637
                    // if id is null, terminate the program
1638
                    throw new SAXException("subtree id is null"); }
1639
                    // Get AccessSection Object
1640
                    Object accessSectionObj = accessControlMap
1641
                            .get(subSectionId);
1642
                    if (accessSectionObj == null) {
1643
                        // if accesssection is null, terminate the program
1644
                        throw new SAXException("access subtree is null");
1645
                    } else {
1646
                        AccessSection accessControlObj = (AccessSection) accessSectionObj;
1647
                        // if the access section is not references, write it to
1648
                        // db
1649
                        if (accessControlObj.getReferences() == null) {
1650
                            writeGivenAccessRuleIntoDB(accessControlObj,
1651
                                    topLevel, subSectionId);
1652
                        } else {
1653
                            // this is a reference and go trough the vector
1654
                            // which contains all
1655
                            // access object
1656
                            String referenceId = accessControlObj
1657
                                    .getReferences();
1658

    
1659
                            boolean findAccessObject = false;
1660
                            MetaCatUtil.debugMessage(
1661
                                    "referered id for additional access "
1662
                                            + "mapping(go through): "
1663
                                            + referenceId, 35);
1664
                            for (int i = 0; i < accessObjectList.size(); i++) {
1665
                                AccessSection accessObj = (AccessSection) accessObjectList
1666
                                        .elementAt(i);
1667
                                String accessObjId = accessObj.getSubTreeId();
1668
                                MetaCatUtil.debugMessage(
1669
                                        "access obj id in the list(go through): "
1670
                                                + accessObjId, 35);
1671
                                if (referenceId != null && accessObj != null
1672
                                        && referenceId.equals(accessObjId)) {
1673
                                    writeGivenAccessRuleIntoDB(accessObj,
1674
                                            topLevel, subSectionId);
1675
                                    findAccessObject = true;
1676
                                }//if
1677
                            }//for
1678
                            // if we couldn't find an access subtree id for
1679
                            // this reference id
1680
                            if (!findAccessObject) { throw new SAXException(
1681
                                    "The referenceid: " + referenceId
1682
                                            + " is not access subtree"); }//if
1683
                        }//else
1684
                    }//else
1685
                }//try
1686
                catch (Exception e) {
1687

    
1688
                    MetaCatUtil.debugMessage(
1689
                            "error in EmlSAXHandler.writeAddtionalAccess"
1690
                                    + ": " + e.getMessage(), 30);
1691
                    throw new SAXException(e.getMessage());
1692
                }
1693
            }//while
1694
        }//for
1695
    }//writeAccessRuletoDB
1696

    
1697
    /* Write a gaven access rule into db */
1698
    private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1699
            boolean topLevel, String subSectionId) throws SAXException
1700
    {
1701
        if (accessSection == null) { throw new SAXException(
1702
                "The access object is null"); }
1703

    
1704
        String permOrder = accessSection.getPermissionOrder();
1705
        String sql = null;
1706
        PreparedStatement pstmt = null;
1707
        if (topLevel) {
1708
            sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1709
                    + "perm_type, perm_order, accessfileid) VALUES "
1710
                    + " (?, ?, ?, ?, ?, ?)";
1711
        } else {
1712
            sql = "INSERT INTO xml_access (docid,principal_name, "
1713
                    + "permission, perm_type, perm_order, accessfileid, subtreeid, "
1714
                    + " startnodeid, endnodeid) VALUES"
1715
                    + " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1716
        }
1717
        try {
1718

    
1719
            pstmt = connection.prepareStatement(sql);
1720
            // Increase DBConnection usage count
1721
            connection.increaseUsageCount(1);
1722
            // Bind the values to the query
1723
            pstmt.setString(1, docid);
1724
            MetaCatUtil.debugMessage("Docid in accesstable: " + docid, 35);
1725
            pstmt.setString(6, docid);
1726
            MetaCatUtil.debugMessage("Accessfileid in accesstable: " + docid,
1727
                    35);
1728
            pstmt.setString(5, permOrder);
1729
            MetaCatUtil.debugMessage("PermOder in accesstable: " + permOrder,
1730
                    35);
1731
            // if it is not top level, set subsection id
1732
            if (!topLevel) {
1733
                long startNodeId = 0;
1734
                long endNodeId = 0;
1735
                // for subtree should specify the
1736
                if (subSectionId == null) { throw new SAXException(
1737
                        "The subsection is null"); }
1738
                // go through the substree list vector and found the start node
1739
                // id
1740
                // and stop node id for this subtree id
1741
                for (int i = 0; i < subTreeList.size(); i++) {
1742
                    SubTree tree = (SubTree) subTreeList.elementAt(i);
1743
                    String subTreeId = tree.getSubTreeId();
1744
                    if (subSectionId.equals(subTreeId)) {
1745
                        startNodeId = tree.getStartNodeId();
1746
                        endNodeId = tree.getEndNodeId();
1747
                    }//if
1748
                }//for
1749
                if (startNodeId == 0 || endNodeId == 0) { throw new SAXException(
1750
                        "Could find the subtree" + "for this id: "
1751
                                + subSectionId); }
1752
                pstmt.setString(7, subSectionId);
1753
                MetaCatUtil.debugMessage("SubSectionId in accesstable: "
1754
                        + subSectionId, 35);
1755
                pstmt.setLong(8, startNodeId);
1756
                MetaCatUtil
1757
                        .debugMessage("Start node id is: " + startNodeId, 35);
1758
                pstmt.setLong(9, endNodeId);
1759
                MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1760

    
1761
            }
1762

    
1763
            Vector accessRules = accessSection.getAccessRules();
1764
            // go through every rule
1765
            for (int i = 0; i < accessRules.size(); i++) {
1766
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1767
                String permType = rule.getPermissionType();
1768
                int permission = rule.getPermission();
1769
                pstmt.setInt(3, permission);
1770
                MetaCatUtil.debugMessage("permission in accesstable: "
1771
                        + permission, 35);
1772
                pstmt.setString(4, permType);
1773
                MetaCatUtil.debugMessage(
1774
                        "Permtype in accesstable: " + permType, 35);
1775
                // go through every principle in rule
1776
                Vector nameVector = rule.getPrincipal();
1777
                for (int j = 0; j < nameVector.size(); j++) {
1778
                    String prName = (String) nameVector.elementAt(j);
1779
                    pstmt.setString(2, prName);
1780
                    MetaCatUtil.debugMessage("Principal in accesstable: "
1781
                            + prName, 35);
1782
                    pstmt.execute();
1783
                }//for
1784
            }//for
1785
            pstmt.close();
1786
        }//try
1787
        catch (SQLException e) {
1788
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1789
                    + e.getMessage());
1790
        }//catch
1791
        finally {
1792
            try {
1793
                pstmt.close();
1794
            } catch (SQLException ee) {
1795
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1796
                        + ee.getMessage());
1797
            }
1798
        }//finally
1799

    
1800
    }//writeGivenAccessRuleIntoDB
1801

    
1802
    /* Write a gaven access rule into db */
1803
    private void writeAccessRuleForRalatedDataFileIntoDB(
1804
            AccessSection accessSection, String dataId) throws SAXException
1805
    {
1806
        if (accessSection == null) { throw new SAXException(
1807
                "The access object is null"); }
1808
        // get rid of rev from dataId
1809
        dataId = MetaCatUtil.getDocIdFromString(dataId);
1810
        String permOrder = accessSection.getPermissionOrder();
1811
        String sql = null;
1812
        PreparedStatement pstmt = null;
1813
        sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1814
                + "perm_type, perm_order, accessfileid) VALUES "
1815
                + " (?, ?, ?, ?, ?, ?)";
1816

    
1817
        try {
1818

    
1819
            pstmt = connection.prepareStatement(sql);
1820
            // Increase DBConnection usage count
1821
            connection.increaseUsageCount(1);
1822
            // Bind the values to the query
1823
            pstmt.setString(1, dataId);
1824
            MetaCatUtil.debugMessage("Docid in accesstable: " + docid, 35);
1825
            pstmt.setString(6, docid);
1826
            MetaCatUtil.debugMessage("Accessfileid in accesstable: " + docid,
1827
                    35);
1828
            pstmt.setString(5, permOrder);
1829
            MetaCatUtil.debugMessage("PermOder in accesstable: " + permOrder,
1830
                    35);
1831
            // if it is not top level, set subsection id
1832

    
1833
            Vector accessRules = accessSection.getAccessRules();
1834
            // go through every rule
1835
            for (int i = 0; i < accessRules.size(); i++) {
1836
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1837
                String permType = rule.getPermissionType();
1838
                int permission = rule.getPermission();
1839
                pstmt.setInt(3, permission);
1840
                MetaCatUtil.debugMessage("permission in accesstable: "
1841
                        + permission, 35);
1842
                pstmt.setString(4, permType);
1843
                MetaCatUtil.debugMessage(
1844
                        "Permtype in accesstable: " + permType, 35);
1845
                // go through every principle in rule
1846
                Vector nameVector = rule.getPrincipal();
1847
                for (int j = 0; j < nameVector.size(); j++) {
1848
                    String prName = (String) nameVector.elementAt(j);
1849
                    pstmt.setString(2, prName);
1850
                    MetaCatUtil.debugMessage("Principal in accesstable: "
1851
                            + prName, 35);
1852
                    pstmt.execute();
1853
                }//for
1854
            }//for
1855
            pstmt.close();
1856
        }//try
1857
        catch (SQLException e) {
1858
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1859
                    + e.getMessage());
1860
        }//catch
1861
        finally {
1862
            try {
1863
                pstmt.close();
1864
            } catch (SQLException ee) {
1865
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1866
                        + ee.getMessage());
1867
            }
1868
        }//finally
1869

    
1870
    }//writeAccessRuleForRalatedDataFileIntoDB
1871

    
1872
    /* Delete from db all permission for resources related to @aclid if any. */
1873
    private void deletePermissionsInAccessTable(String aclid)
1874
            throws SAXException
1875
    {
1876
        Statement stmt = null;
1877
        try {
1878
            // delete all acl records for resources related to @aclid if any
1879
            stmt = connection.createStatement();
1880
            // Increase DBConnection usage count
1881
            connection.increaseUsageCount(1);
1882
            stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
1883
                    + aclid + "'");
1884

    
1885
        } catch (SQLException e) {
1886
            throw new SAXException(e.getMessage());
1887
        } finally {
1888
            try {
1889
                stmt.close();
1890
            } catch (SQLException ee) {
1891
                throw new SAXException(ee.getMessage());
1892
            }
1893
        }
1894
    }//deletePermissionsInAccessTable
1895

    
1896
    /*
1897
     * In order to make sure only usr has "all" permission can update access
1898
     * subtree in eml document we need to keep access subtree info in
1899
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1900
     */
1901
    private void writeAccessSubTreeIntoDB(AccessSection accessSection,
1902
            String level) throws SAXException
1903
    {
1904
        if (accessSection == null) { throw new SAXException(
1905
                "The access object is null"); }
1906

    
1907
        String sql = null;
1908
        PreparedStatement pstmt = null;
1909
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1910
                + "subtreeid, startnodeid, endnodeid) VALUES "
1911
                + " (?, ?, ?, ?, ?, ?)";
1912
        try {
1913

    
1914
            pstmt = connection.prepareStatement(sql);
1915
            // Increase DBConnection usage count
1916
            connection.increaseUsageCount(1);
1917
            long startNodeId = accessSection.getStartNodeId();
1918
            long endNodeId = accessSection.getEndNodeId();
1919
            String sectionId = accessSection.getSubTreeId();
1920
            // Bind the values to the query
1921
            pstmt.setString(1, docid);
1922
            MetaCatUtil.debugMessage("Docid in access-subtreetable: " + docid,
1923
                    35);
1924
            pstmt.setString(2, revision);
1925
            MetaCatUtil.debugMessage("rev in accesssubtreetable: " + revision,
1926
                    35);
1927
            pstmt.setString(3, level);
1928
            MetaCatUtil.debugMessage("contorl level in access-subtree table: "
1929
                    + level, 35);
1930
            pstmt.setString(4, sectionId);
1931
            MetaCatUtil.debugMessage("Subtree id in access-subtree table: "
1932
                    + sectionId, 35);
1933
            pstmt.setLong(5, startNodeId);
1934
            MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
1935
            pstmt.setLong(6, endNodeId);
1936
            MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1937
            pstmt.execute();
1938
            pstmt.close();
1939
        }//try
1940
        catch (SQLException e) {
1941
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1942
                    + e.getMessage());
1943
        }//catch
1944
        finally {
1945
            try {
1946
                pstmt.close();
1947
            } catch (SQLException ee) {
1948
                throw new SAXException(
1949
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1950
                                + ee.getMessage());
1951
            }
1952
        }//finally
1953

    
1954
    }//writeAccessSubtreeIntoDB
1955

    
1956
    /* Delete every access subtree record from xml_accesssubtree. */
1957
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
1958
    {
1959
        Statement stmt = null;
1960
        try {
1961
            // delete all acl records for resources related to @aclid if any
1962
            stmt = connection.createStatement();
1963
            // Increase DBConnection usage count
1964
            connection.increaseUsageCount(1);
1965
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
1966
                    + docId + "'");
1967

    
1968
        } catch (SQLException e) {
1969
            throw new SAXException(e.getMessage());
1970
        } finally {
1971
            try {
1972
                stmt.close();
1973
            } catch (SQLException ee) {
1974
                throw new SAXException(ee.getMessage());
1975
            }
1976
        }
1977
    }//deleteAccessSubTreeRecord
1978

    
1979
    // open a file writer for writing inline data to file
1980
    private FileWriter createInlineDataFileWriter(String fileName)
1981
            throws SAXException
1982
    {
1983
        FileWriter writer = null;
1984
        String path = MetaCatUtil.getOption("inlinedatafilepath");
1985
        /*
1986
         * File inlineDataDirectory = new File(path);
1987
         */
1988
        String newFile = path + "/" + fileName;
1989
        MetaCatUtil.debugMessage("inline file name: " + newFile, 30);
1990
        try {
1991
            // true means append
1992
            writer = new FileWriter(newFile, true);
1993
        } catch (IOException ioe) {
1994
            throw new SAXException(ioe.getMessage());
1995
        }
1996
        return writer;
1997
    }
1998

    
1999
    // write inline data into file system and return file name(without path)
2000
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2001
            throws SAXException
2002
    {
2003
        try {
2004
            writer.write(data.toString());
2005
            writer.flush();
2006
        } catch (Exception e) {
2007
            throw new SAXException(e.getMessage());
2008
        }
2009
    }
2010

    
2011
    /*
2012
     * In eml2, the inline data wouldn't store in db, it store in file system
2013
     * The db stores file name(without path). We got the old file name from db
2014
     * and compare to the new in line data file
2015
     */
2016
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2017
            throws McdbException
2018
    {
2019
        // this method need to be testing
2020
        boolean same = true;
2021
        String data = null;
2022
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2023
        // the new file name will look like path/docid.rev.2
2024
        File inlineDataDirectory = new File(path);
2025
        File oldDataFile = new File(inlineDataDirectory, oldFileName);
2026
        File newDataFile = new File(inlineDataDirectory, newFileName);
2027
        try {
2028
            FileReader oldFileReader = new FileReader(oldDataFile);
2029
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2030
            FileReader newFileReader = new FileReader(newDataFile);
2031
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2032
            // read first line of data
2033
            String oldString = oldStringReader.readLine();
2034
            String newString = newStringReader.readLine();
2035

    
2036
            // at the end oldstring will be null
2037
            while (oldString != null) {
2038
                oldString = oldStringReader.readLine();
2039
                newString = newStringReader.readLine();
2040
                if (!oldString.equals(newString)) {
2041
                    same = false;
2042
                    break;
2043
                }
2044
            }
2045

    
2046
            // if oldString is null but newString is not null, they are same
2047
            if (same) {
2048
                if (newString != null) {
2049
                    same = false;
2050
                }
2051
            }
2052

    
2053
        } catch (Exception e) {
2054
            throw new McdbException(e.getMessage());
2055
        }
2056
        MetaCatUtil.debugMessage("the inline data retrieve from file: " + data,
2057
                50);
2058
        return same;
2059
    }
2060

    
2061
    // if xml file failed to upload, we need to call this method to delete
2062
    // the inline data already in file system
2063
    public void deleteInlineFiles()
2064
    {
2065
        if (!inlineFileIDList.isEmpty()) {
2066
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2067
                String fileName = (String) inlineFileIDList.elementAt(i);
2068
                deleteInlineDataFile(fileName);
2069
            }
2070
        }
2071
    }
2072

    
2073
    /* delete the inline data file */
2074
    private void deleteInlineDataFile(String fileName)
2075
    {
2076

    
2077
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2078
        File inlineDataDirectory = new File(path);
2079
        File newFile = new File(inlineDataDirectory, fileName);
2080
        newFile.delete();
2081

    
2082
    }
2083

    
2084
    /*
2085
     * In eml2, the inline data wouldn't store in db, it store in file system
2086
     * The db stores file name(without path).
2087
     */
2088
    public static Reader readInlineDataFromFileSystem(String fileName)
2089
            throws McdbException
2090
    {
2091
        //BufferedReader stringReader = null;
2092
        FileReader fileReader = null;
2093
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2094
        // the new file name will look like path/docid.rev.2
2095
        File inlineDataDirectory = new File(path);
2096
        File dataFile = new File(inlineDataDirectory, fileName);
2097
        try {
2098
            fileReader = new FileReader(dataFile);
2099
            //stringReader = new BufferedReader(fileReader);
2100
        } catch (Exception e) {
2101
            throw new McdbException(e.getMessage());
2102
        }
2103
        // return stringReader;
2104
        return fileReader;
2105
    }
2106

    
2107
    /* Delete relations */
2108
    private void deleteRelations() throws SAXException
2109
    {
2110
        PreparedStatement pStmt = null;
2111
        String sql = "DELETE FROM xml_relation where docid =?";
2112
        try {
2113
            pStmt = connection.prepareStatement(sql);
2114
            //bind variable
2115
            pStmt.setString(1, docid);
2116
            //execute query
2117
            pStmt.execute();
2118
            pStmt.close();
2119
        }//try
2120
        catch (SQLException e) {
2121
            throw new SAXException("EMLSAXHandler.deleteRelations(): "
2122
                    + e.getMessage());
2123
        }//catch
2124
        finally {
2125
            try {
2126
                pStmt.close();
2127
            }//try
2128
            catch (SQLException ee) {
2129
                throw new SAXException("EMLSAXHandler.deleteRelations: "
2130
                        + ee.getMessage());
2131
            }//catch
2132
        }//finally
2133
    }
2134

    
2135
    /* Write an online data file id into xml_relation table */
2136
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2137
            throws SAXException
2138
    {
2139
        // Get rid of rev
2140
        dataId = MetaCatUtil.getDocIdFromString(dataId);
2141
        PreparedStatement pStmt = null;
2142
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2143
                + "relationship, object) values (?, ?, ?, ?, ?)";
2144
        try {
2145
            pStmt = connection.prepareStatement(sql);
2146
            //bind variable
2147
            pStmt.setString(1, docid);
2148
            pStmt.setString(2, DocumentImpl.EMLNAMESPACE);
2149
            pStmt.setString(3, docid);
2150
            pStmt.setString(4, RELATION);
2151
            pStmt.setString(5, dataId);
2152
            //execute query
2153
            pStmt.execute();
2154
            pStmt.close();
2155
        }//try
2156
        catch (SQLException e) {
2157
            throw new SAXException(
2158
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2159
                            + e.getMessage());
2160
        }//catch
2161
        finally {
2162
            try {
2163
                pStmt.close();
2164
            }//try
2165
            catch (SQLException ee) {
2166
                throw new SAXException(
2167
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2168
                                + ee.getMessage());
2169
            }//catch
2170
        }//finally
2171

    
2172
    }//writeOnlineDataFileIdIntoRelationTable
2173

    
2174
}
(34-34/61)