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: sgarg $'
11
 *     '$Date: 2004-09-09 15:48:41 -0700 (Thu, 09 Sep 2004) $'
12
 * '$Revision: 2267 $'
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 Eml210SAXHandler 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 onlineDataFileIdInRelationVector = new Vector();
118

    
119
    // vector stored the data file id which will be write top access rules to
120
   // access table
121
    private Vector onlineDataFileIdInTopAccessVector = new Vector();
122

    
123
    // Indicator of inline data
124
    private boolean handleInlineData = false;
125

    
126
    private Stack inlineDataNodeStack = null;
127

    
128
    private Hashtable inlineDataNameSpace = null;
129

    
130
    private FileWriter inlineDataFileWriter = null;
131

    
132
    private String inlineDataFileName = null;
133

    
134
    private int inLineDataIndex = 0;
135

    
136
    private Vector inlineFileIDList = new Vector();
137

    
138

    
139
    // Constant
140
    private static final String EML = "eml";
141

    
142
    private static final String DESCRIBES = "describes";
143

    
144
    private static final String ADDITIONALMETADATA = "additionalMetadata";
145

    
146
    private static final String ORDER = "order";
147

    
148
    private static final String ID = "id";
149

    
150
    private static final String REFERENCES = "references";
151

    
152
    public static final String INLINE = "inline";
153

    
154
    private static final String ONLINE = "online";
155

    
156
    private static final String URL = "url";
157

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

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

    
164
    private static final String TOPLEVEL = "top";
165

    
166
    private static final String SUBTREELEVEL = "subtree";
167

    
168
    private static final String RELATION = "Provides info for";
169

    
170
    /**
171
     * Construct an instance of the handler class In this constructor, user can
172
     * specify the version need to upadate
173
     *
174
     * @param conn the JDBC connection to which information is written
175
     * @param action - "INSERT" or "UPDATE"
176
     * @param docid to be inserted or updated into JDBC connection
177
     * @param revision, the user specified the revision need to be update
178
     * @param user the user connected to MetaCat servlet and owns the document
179
     * @param groups the groups to which user belongs
180
     * @param pub flag for public "read" access on document
181
     * @param serverCode the serverid from xml_replication on which this
182
     *            document resides.
183
     *
184
     */
185
    public Eml210SAXHandler(DBConnection conn, String action, String docid,
186
            String revision, String user, String[] groups, String pub,
187
            int serverCode) throws SAXException
188
    {
189
        super(conn, action, docid, revision, user, groups, pub, serverCode);
190
        // Get the unchangable subtrees (user doesn't have write permission)
191
        try {
192
            PermissionController control = new PermissionController(docid
193
                    + MetaCatUtil.getOption("accNumSeparator") + revision);
194
            //unChangableSubTreeHash = getUnchangableSubTree(control, user,
195
            // groups);
196

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

    
210
    /* Pass a permission control and get the list of unchangable subtree */
211
    private Hashtable getUnchangableSubTree(PermissionController controller,
212
            String user, String[] groups) throws Exception
213
    {
214
        Hashtable list = null;
215
        Hashtable result = new Hashtable();
216
        // get unwritable sutree from controller
217
        list = null;
218
        // changed after old code removal
219
        //controller.hasUnaccessableSubTree(user, groups,
220
        //        AccessControlInterface.WRITESTRING);
221
        if (list != null) {
222

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

    
242
            }//while
243

    
244
        }//if
245

    
246
        return result;
247
    }
248

    
249
    /*
250
     * Get the subtree node info from xml_accesssubtree table
251
     */
252
    private Vector getAccessSubTreeListFromDB() throws Exception
253
    {
254
        Vector result = new Vector();
255
        PreparedStatement pstmt = null;
256
        ResultSet rs = null;
257
        String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid "
258
                + "FROM xml_accesssubtree WHERE docid like ? "
259
                + "ORDER BY startnodeid ASC";
260

    
261
        try {
262

    
263
            pstmt = connection.prepareStatement(sql);
264
            // Increase DBConnection usage count
265
            connection.increaseUsageCount(1);
266
            // Bind the values to the query
267
            pstmt.setString(1, docid);
268
            pstmt.execute();
269

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

    
312
    /** SAX Handler that is called at the start of each XML element */
313
    public void startElement(String uri, String localName, String qName,
314
            Attributes atts) throws SAXException
315
    {
316
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
317
        // for element <acl....> both qname and local name is "eml"
318
        // uri is namesapce
319
        MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
320
        MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
321
        MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
322

    
323
        DBSAXNode parentNode = null;
324
        DBSAXNode currentNode = null;
325

    
326
        if (!handleInlineData) {
327
            // Get a reference to the parent node for the id
328
            try {
329
                parentNode = (DBSAXNode) nodeStack.peek();
330
            } catch (EmptyStackException e) {
331
                parentNode = null;
332
            }
333

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

    
352
            }
353

    
354
            // If hit a text node, we need write this text for current's parent
355
            // node
356
            // This will happend if the element is mixted
357
            if (hitTextNode && parentNode != null) {
358
                //compare text node data for unchangesubtree
359
                if (startCriticalSubTree) {
360
                    compareTextNode(currentUnChangedableSubtreeNodeStack,
361
                            textBuffer, PERMISSIONERROR);
362
                }//if
363

    
364
                //compare top level access module
365
                if (processTopLeverAccess && needCheckingAccessModule) {
366
                    compareTextNode(currentUnchangableAccessModuleNodeStack,
367
                            textBuffer, UPDATEACCESSERROR);
368
                }
369

    
370
                if (needCheckingAccessModule
371
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
372
                    // stored the pull out nodes into storedNode stack
373
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
374
                            null, null, MetaCatUtil.normalize(textBuffer
375
                                    .toString()));
376
                    storedAccessNodeStack.push(nodeElement);
377

    
378
                }
379

    
380
                // write the textbuffer into db for parent node.
381
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
382
                        parentNode);
383
                // rest hitTextNode
384
                hitTextNode = false;
385
                // reset textbuffer
386
                textBuffer = null;
387
                textBuffer = new StringBuffer();
388

    
389
            }
390

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

    
427
                    try {
428
                        // Get dbconnection
429
                        dbConn = DBConnectionPool
430
                                .getDBConnection("DBSAXHandler.startElement");
431
                        serialNumber = dbConn.getCheckOutSerialNumber();
432

    
433
                        Statement stmt = dbConn.createStatement();
434
                        ResultSet rs = stmt
435
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
436
                                        + "WHERE entry_type = 'Schema' "
437
                                        + "AND public_id = '" + doctype + "'");
438
                        boolean hasRow = rs.next();
439
                        if (hasRow) {
440
                            catalogid = rs.getString(1);
441
                        }
442
                        stmt.close();
443
                    }//try
444
                    finally {
445
                        // Return dbconnection
446
                        DBConnectionPool.returnDBConnection(dbConn,
447
                                serialNumber);
448
                    }//finally
449

    
450
                    //create documentImpl object by the constructor which can
451
                    // specify
452
                    //the revision
453
                    currentDocument = new DocumentImpl(connection, rootNode
454
                            .getNodeID(), docname, doctype, docid, revision,
455
                            action, user, this.pub, catalogid, this.serverCode);
456

    
457
                } catch (Exception ane) {
458
                    throw (new SAXException(
459
                            "Error in EMLSaxHandler.startElement " + action,
460
                            ane));
461
                }
462
            }
463

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

    
483
            // Add all of the attributes
484
            for (int i = 0; i < atts.getLength(); i++) {
485
                String attributeName = atts.getQName(i);
486
                String attributeValue = atts.getValue(i);
487
                endNodeId = currentNode.setAttribute(attributeName,
488
                        attributeValue, docid);
489

    
490
                // To handle name space and schema location if the attribute
491
                // name is
492
                // xsi:schemaLocation. If the name space is in not in catalog
493
                // table
494
                // it will be regeistered.
495
                if (attributeName != null
496
                        && attributeName
497
                                .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
498
                    SchemaLocationResolver resolver = new SchemaLocationResolver(
499
                            attributeValue);
500
                    resolver.resolveNameSpace();
501

    
502
                } else if (attributeName != null && attributeName.equals(ID)) {
503

    
504
                    //check unchangedable subtree hash if contains this
505
                    // subtree id
506
                    if (unChangableSubTreeHash.containsKey(attributeValue)) {
507
                        // this subtree couldn't be changed by the user and
508
                        // move it from hash
509
                        SubTree currentUnChangedableSubtree = (SubTree) unChangableSubTreeHash
510
                                .remove(attributeValue);
511
                        currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree
512
                                .getSubTreeNodeStack();
513
                        startCriticalSubTree = true;
514
                        firstElementForCriticalSubTree = true;
515
                    }
516

    
517
                    // handle subtree info
518
                    SubTree subTress = new SubTree();
519
                    // set sub tree id
520
                    subTress.setSubTreeId(attributeValue);
521
                    // set sub tree sstart lement name
522
                    subTress.setStartElementName(currentNode.getTagName());
523
                    // set start node number
524
                    subTress.setStartNodeId(startNodeId);
525
                    // add to stack, but it didn't get end node id yet
526
                    subTreeInfoStack.push(subTress);
527

    
528
                }
529
            }//for
530

    
531
            // handle access stuff
532
            if (localName.equals(ACCESS)) {
533
                // if it is in addtionalmetacat
534
                if (parentNode.getTagName() == ADDITIONALMETADATA) {
535
                    processAdditionalAccess = true;
536

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

    
556
                }
557
                // create access object
558
                accessObject = new AccessSection();
559
                // set permission order
560
                String permOrder = currentNode.getAttribute(ORDER);
561
                accessObject.setPermissionOrder(permOrder);
562
                // set access id
563
                String accessId = currentNode.getAttribute(ID);
564
                accessObject.setSubTreeId(accessId);
565
                accessObject.setStartNodeId(startNodeId);
566
                accessObject.setDocId(docid);
567

    
568
                // load top level node stack to
569
                // currentUnchangableAccessModuleNodeStack
570
                if (processTopLeverAccess && needCheckingAccessModule) {
571
                    // get the node stack for
572
                    currentUnchangableAccessModuleNodeStack = topAccessSection
573
                            .getSubTreeNodeStack();
574
                }
575

    
576
            }
577
            // Set up a access rule for allow
578
            else if (parentNode.getTagName() != null
579
                    && (parentNode.getTagName()).equals(ACCESS)
580
                    && localName.equals(ALLOW)) {
581

    
582
                accessRule = new AccessRule();
583

    
584
                //set permission type "allow"
585
                accessRule.setPermissionType(ALLOW);
586

    
587
            }
588
            // set up an access rule for den
589
            else if (parentNode.getTagName() != null
590
                    && (parentNode.getTagName()).equals(ACCESS)
591
                    && localName.equals(DENY)) {
592
                accessRule = new AccessRule();
593
                //set permission type "allow"
594
                accessRule.setPermissionType(DENY);
595
            }
596

    
597
            // Add the node to the stack, so that any text data can be
598
            // added as it is encountered
599
            nodeStack.push(currentNode);
600
            // Add the node to the vector used by thread for writing XML Index
601
            nodeIndex.addElement(currentNode);
602

    
603
            // handle critical subtree
604
            if (startCriticalSubTree && firstElementForCriticalSubTree) {
605
                //store the element name
606
                firstElementNameForCriticalSubTree = qName;
607
                firstElementForCriticalSubTree = false;
608
            }//for first element
609

    
610
            // handle critical subtree
611
            if (startCriticalSubTree) {
612
                compareElementNameSpaceAttributes(
613
                        currentUnChangedableSubtreeNodeStack, namespaces, atts,
614
                        localName, PERMISSIONERROR);
615

    
616
            }
617
            //compare top access level module
618
            if (processTopLeverAccess && needCheckingAccessModule) {
619
                compareElementNameSpaceAttributes(
620
                        currentUnchangableAccessModuleNodeStack, namespaces,
621
                        atts, localName, UPDATEACCESSERROR);
622

    
623
            }
624

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

    
641
            }
642

    
643
            // reset name space
644
            namespaces = null;
645
            namespaces = new Hashtable();
646
        }//not inline data
647
        else {
648
            // we don't buffer the inline data in characters() method
649
            // so start character don't need to hand text node.
650

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

    
688
    }
689

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

    
736
        //compare namespace
737
        Enumeration nameEn = nameSpaces.keys();
738
        while (nameEn.hasMoreElements()) {
739
            //Get namespacke node stack (element node)
740
            NodeRecord nameNode = null;
741
            try {
742
                nameNode = (NodeRecord) unchangableNodeStack.pop();
743
            } catch (EmptyStackException ee) {
744
                MetaCatUtil.debugMessage(
745
                        "Node stack is empty for namespace data", 35);
746
                throw new SAXException(error);
747
            }
748

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

    
772
        }//while
773

    
774
        //compare attributes
775
        for (int i = 0; i < attributes.getLength(); i++) {
776
            NodeRecord attriNode = null;
777
            try {
778
                attriNode = (NodeRecord) unchangableNodeStack.pop();
779

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

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

    
824
    }
825

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

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

    
905
    /** SAX Handler that is called at the end of each XML element */
906
    public void endElement(String uri, String localName, String qName)
907
            throws SAXException
908
    {
909
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
910

    
911
        if (localName.equals(INLINE) && handleInlineData) {
912
            // Get the node from the stack
913
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
914
            String currentTag = currentNode.getTagName();
915
            MetaCatUtil.debugMessage("End of inline data", 35);
916
            // close file writer
917
            try {
918
                inlineDataFileWriter.close();
919
                handleInlineData = false;
920
            } catch (IOException ioe) {
921
                throw new SAXException(ioe.getMessage());
922
            }
923

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

    
955
            }//if
956
            // write put inline data file name into text buffer (without path)
957
            textBuffer = new StringBuffer(inlineDataFileName);
958
            // write file name into db
959
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
960
                    currentNode);
961
            // reset textbuff
962
            textBuffer = null;
963
            textBuffer = new StringBuffer();
964
            return;
965
        }
966

    
967
        if (!handleInlineData) {
968
            // Get the node from the stack
969
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
970
            String currentTag = currentNode.getTagName();
971

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

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

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

    
1062
                }
1063
            }//if
1064

    
1065
            //end crtical subtree(user doesn't have permission to write)
1066
            //When reach the first element and stack is empty
1067
            if (localName.equals(firstElementNameForCriticalSubTree)
1068
                    && currentUnChangedableSubtreeNodeStack.isEmpty()) {
1069
                startCriticalSubTree = false;
1070
            }
1071

    
1072
            //set hitText false
1073
            hitTextNode = false;
1074
            // reset textbuff
1075
            textBuffer = null;
1076
            textBuffer = new StringBuffer();
1077

    
1078
            // hand sub stree stuff
1079
            if (!subTreeInfoStack.empty()) {
1080
                SubTree tree = (SubTree) subTreeInfoStack.peek();// get last
1081
                                                                 // subtree
1082
                if (tree != null && tree.getStartElementName() != null
1083
                        && (tree.getStartElementName()).equals(currentTag)) {
1084
                    // find the end of sub tree and set the end node id
1085
                    tree.setEndNodeId(endNodeId);
1086
                    // add the subtree into the final store palace
1087
                    subTreeList.add(tree);
1088
                    // get rid of it from stack
1089
                    subTreeInfoStack.pop();
1090
                }//if
1091
            }//if
1092

    
1093
            // access stuff
1094
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
1095
                // finish parser a ccess rule and assign it to new one
1096
                AccessRule newRule = accessRule;
1097
                //add the new rule to access section object
1098
                accessObject.addAccessRule(newRule);
1099
                // reset access rule
1100
                accessRule = null;
1101
            } else if (currentTag.equals(ACCESS)) {
1102
                // finish parse a access setction and assign it to new one
1103

    
1104
                accessObject.setEndNodeId(endNodeId);
1105
                AccessSection newAccessObject = accessObject;
1106

    
1107
                if (newAccessObject != null) {
1108

    
1109
                    // add the accessSection into a vector to store it
1110
                    // if it is not a reference, need to store it
1111
                    if (newAccessObject.getReferences() == null) {
1112

    
1113
                        newAccessObject
1114
                                .setStoredTmpNodeStack(storedAccessNodeStack);
1115
                        accessObjectList.add(newAccessObject);
1116
                    }
1117
                    if (processTopLeverAccess) {
1118

    
1119
                        // top level access control will handle whole document
1120
                        // -docid
1121
                        topLevelAccessControlMap.put(docid, newAccessObject);
1122
                        // reset processtopleveraccess tag
1123

    
1124
                    }//if
1125
                    else if (processAdditionalAccess) {
1126
                        // for additional control
1127
                        // put everything in describes value and access object
1128
                        // into hash
1129
                        for (int i = 0; i < describesId.size(); i++) {
1130

    
1131
                            String subId = (String) describesId.elementAt(i);
1132
                            if (subId != null) {
1133
                                additionalAccessControlMap.put(subId,
1134
                                        newAccessObject);
1135
                            }//if
1136
                        }//for
1137
                        // add this hashtable in to vector
1138

    
1139
                        additionalAccessMapList.add(additionalAccessControlMap);
1140
                        // reset this hashtable in order to store another
1141
                        // additional
1142
                        //accesscontrol
1143
                        additionalAccessControlMap = null;
1144
                        additionalAccessControlMap = new Hashtable();
1145
                    }//if
1146

    
1147
                }//if
1148
                //check if access node stack is empty after parsing top access
1149
                //module
1150

    
1151
                if (needCheckingAccessModule && processTopLeverAccess
1152
                        && !currentUnchangableAccessModuleNodeStack.isEmpty()) {
1153

    
1154
                    MetaCatUtil.debugMessage(
1155
                            "Access node stack is not empty after "
1156
                                    + "parsing access subtree", 40);
1157
                    throw new SAXException(UPDATEACCESSERROR);
1158

    
1159
                }
1160
                //reset access section object
1161

    
1162
                accessObject = null;
1163

    
1164
                // reset tmp stored node stack
1165
                storedAccessNodeStack = null;
1166
                storedAccessNodeStack = new Stack();
1167

    
1168
                // reset flag
1169
                processAdditionalAccess = false;
1170
                processTopLeverAccess = false;
1171
                processOtherAccess = false;
1172

    
1173
            } else if (currentTag.equals(ADDITIONALMETADATA)) {
1174
                //reset describesId
1175
                describesId = null;
1176
                describesId = new Vector();
1177
            }
1178
        } else {
1179
            // this is in inline part
1180
            StringBuffer endElement = new StringBuffer();
1181
            endElement.append("</");
1182
            endElement.append(qName);
1183
            endElement.append(">");
1184
            MetaCatUtil.debugMessage("inline endElement: "
1185
                    + endElement.toString(), 50);
1186
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1187
        }
1188
    }
1189

    
1190
    /**
1191
     * SAX Handler that receives notification of comments in the DTD
1192
     */
1193
    public void comment(char[] ch, int start, int length) throws SAXException
1194
    {
1195
        MetaCatUtil.debugMessage("COMMENT", 50);
1196
        if (!handleInlineData) {
1197
            if (!processingDTD) {
1198
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1199
                String str = new String(ch, start, length);
1200

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

    
1220
                }
1221
            }
1222
        } else {
1223
            // inline data comment
1224
            StringBuffer inlineComment = new StringBuffer();
1225
            inlineComment.append("<!--");
1226
            inlineComment.append(new String(ch, start, length));
1227
            inlineComment.append("-->");
1228
            MetaCatUtil.debugMessage("inline data comment: "
1229
                    + inlineComment.toString(), 50);
1230
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1231
        }
1232
    }
1233

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

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

    
1296
    /** SAX Handler that is called at the start of Namespace */
1297
    public void startPrefixMapping(String prefix, String uri)
1298
            throws SAXException
1299
    {
1300
        MetaCatUtil.debugMessage("NAMESPACE", 50);
1301
        if (!handleInlineData) {
1302
            namespaces.put(prefix, uri);
1303
        } else {
1304
            inlineDataNameSpace.put(prefix, uri);
1305
        }
1306
    }
1307

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

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

    
1341
                //compare whitespace if need
1342
                if (startCriticalSubTree) {
1343
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1344
                            data, PERMISSIONERROR);
1345
                }//if
1346

    
1347
                //compare whitespace in access top module
1348
                if (processTopLeverAccess && needCheckingAccessModule) {
1349
                    compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1350
                            data, UPDATEACCESSERROR);
1351
                }
1352
                // Write the content of the node to the database
1353
                if (needCheckingAccessModule
1354
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1355
                    // stored the pull out nodes into storedNode stack
1356
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1357
                            null, null, MetaCatUtil.normalize(data));
1358
                    storedAccessNodeStack.push(nodeElement);
1359

    
1360
                }
1361
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1362
                        docid);
1363
            }
1364
        } else {
1365
            //This is inline data write to file directly
1366
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1367
                    start, len));
1368
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1369
        }
1370

    
1371
    }
1372

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

    
1402
    /** SAX Handler that receives notification of end of the document */
1403
    public void endDocument() throws SAXException
1404
    {
1405
        MetaCatUtil.debugMessage("end Document", 50);
1406
        // There are some unchangable subtree didn't be compare
1407
        // This maybe cause user change the subtree id
1408
        if (!unChangableSubTreeHash.isEmpty()) {
1409
            MetaCatUtil.debugMessage("The unChangealbe subtree is not empty",
1410
                    40);
1411
            throw new SAXException(PERMISSIONERROR);
1412
        }
1413

    
1414
        // write access rule to db
1415
        writeAccessRuleToDB();
1416

    
1417
        //delete relation table
1418
        deleteRelations();
1419
        //write relations
1420
        for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1421
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1422
            writeOnlineDataFileIdIntoRelationTable(id);
1423
        }
1424

    
1425
        // Starting new thread for writing XML Index.
1426
        // It calls the run method of the thread.
1427
        boolean useXMLIndex = (new Boolean(MetaCatUtil.getOption("usexmlindex")))
1428
                .booleanValue();
1429
        if (useXMLIndex) {
1430
            try {
1431
                xmlIndex.start();
1432
            } catch (NullPointerException e) {
1433
                xmlIndex = null;
1434
                throw new SAXException(
1435
                        "Problem with starting thread for writing XML Index. "
1436
                                + e.getMessage());
1437
            }
1438
        }
1439
    }
1440

    
1441
    /* The method to write all access rule into db */
1442
    private void writeAccessRuleToDB() throws SAXException
1443
    {
1444
        //Delete old permssion
1445
        deletePermissionsInAccessTable(docid);
1446
        //write top leve access rule
1447
        writeTopLevelAccessRuleToDB();
1448
        //write additional access rule
1449
        //writeAddtionalAccessRuleToDB();
1450
    }//writeAccessRuleToDB
1451

    
1452
    /* The method to write top level access rule into db. */
1453
    private void writeTopLevelAccessRuleToDB() throws SAXException
1454
    {
1455

    
1456
        // for top document level
1457
        Object accessSection = topLevelAccessControlMap.get(docid);
1458
        boolean top = true;
1459
        String subSectionId = null;
1460
        if (accessSection != null) {
1461
            AccessSection accessSectionObj = (AccessSection) accessSection;
1462

    
1463
            // if accessSection is not null and is not reference
1464
            if (accessSectionObj.getReferences() == null) {
1465
                // write the top level access module into xml_accesssubtree to
1466
                // store info
1467
                // and then when update to check if the user can update it or
1468
                // not
1469
                deleteAccessSubTreeRecord(docid);
1470
                writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1471

    
1472
                //write access section into xml_access table
1473
                writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1474
                // write online data file into xml_access too.
1475
                for (int i= 0; i <onlineDataFileIdInTopAccessVector.size(); i++)
1476
                {
1477
                  String id = (String)
1478
                               onlineDataFileIdInTopAccessVector.elementAt(i);
1479
                  writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1480
                }
1481

    
1482

    
1483
            } else {
1484

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

    
1503
                            Stack newStack = accessObj.getStoredTmpNodeStack();
1504
                            //revise order
1505
                            newStack = MetaCatUtil.reviseStack(newStack);
1506
                            // go throught the vector of
1507
                            // unChangableAccessSubtreevector
1508
                            // and find the one whose id is as same as
1509
                            // referenceid
1510
                            AccessSection oldAccessObj = getAccessSectionFromUnchangableAccessVector(referenceId);
1511
                            //if oldAccessObj is null something is wrong
1512
                            if (oldAccessObj == null) {
1513
                                throw new SAXException(UPDATEACCESSERROR);
1514
                            }//if
1515
                            else {
1516
                                // Get the node stack from old access obj
1517
                                Stack oldStack = oldAccessObj
1518
                                        .getSubTreeNodeStack();
1519
                                comparingNodeStacks(newStack, oldStack);
1520
                            }//else
1521
                        }//if
1522
                        // write accessobject into db
1523
                        writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1524
                        // write online data file into xml_access too.
1525
                        for (int j= 0; j <onlineDataFileIdInTopAccessVector.size(); j++)
1526
                        {
1527
                          String id = (String)
1528
                              onlineDataFileIdInTopAccessVector.elementAt(j);
1529
                           writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1530
                        }
1531

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

    
1552
        }//if
1553
        else {
1554
            // couldn't find a access section object
1555
            MetaCatUtil.debugMessage(
1556
                    "couldn't find access control for document: " + docid, 35);
1557
        }
1558

    
1559
    }//writeTopLevelAccessRuletoDB
1560

    
1561
    /* Given a subtree id and find the responding access section */
1562
    private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1563
    {
1564
        AccessSection result = null;
1565
        // Makse sure the id
1566
        if (id == null || id.equals("")) { return result; }
1567
        // go throught vector and find the list
1568
        for (int i = 0; i < unChangableAccessSubTreeVector.size(); i++) {
1569
            AccessSection accessObj = (AccessSection) unChangableAccessSubTreeVector
1570
                    .elementAt(i);
1571
            if (accessObj.getSubTreeId() != null
1572
                    && (accessObj.getSubTreeId()).equals(id)) {
1573
                result = accessObj;
1574
            }//if
1575
        }//for
1576
        return result;
1577
    }//getAccessSectionFromUnchangableAccessVector
1578

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

    
1611
        // now stack1 is empty and we should make sure stack2 is empty too
1612
        if (!stack2.isEmpty()) {
1613
            MetaCatUtil.debugMessage(
1614
                    "stack2 still have some elements while stack "
1615
                            + "is empty! ", 30);
1616
            throw new SAXException(UPDATEACCESSERROR);
1617
        }//if
1618
    }//comparingNodeStacks
1619

    
1620
    /* The method to write addtional access rule into db. */
1621
    private void writeAddtionalAccessRuleToDB() throws SAXException
1622
    {
1623

    
1624
        PreparedStatement pstmt = null;
1625
        boolean topLevel = false;
1626
        // go through the vector which contains the additional access control
1627
        //hashtable. Each hashtable has info for one additonalmetadata
1628
        // container
1629
        for (int j = 0; j < additionalAccessMapList.size(); j++) {
1630

    
1631
            Hashtable accessControlMap = (Hashtable) additionalAccessMapList
1632
                    .elementAt(j);
1633
            // additional access rule
1634
            Enumeration en = accessControlMap.keys();
1635

    
1636
            while (en.hasMoreElements()) {
1637
                try {
1638
                    // Get subsection id
1639
                    String subSectionId = (String) en.nextElement();
1640
                    MetaCatUtil.debugMessage(
1641
                            "sub section id in additional access mapping"
1642
                                    + "(go through): " + subSectionId, 35);
1643

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

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

    
1696
                    MetaCatUtil.debugMessage(
1697
                            "error in EmlSAXHandler.writeAddtionalAccess"
1698
                                    + ": " + e.getMessage(), 30);
1699
                    throw new SAXException(e.getMessage());
1700
                }
1701
            }//while
1702
        }//for
1703
    }//writeAccessRuletoDB
1704

    
1705
    /* Write a gaven access rule into db */
1706
    private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1707
            boolean topLevel, String subSectionId) throws SAXException
1708
    {
1709
        if (accessSection == null) { throw new SAXException(
1710
                "The access object is null"); }
1711

    
1712
        String permOrder = accessSection.getPermissionOrder();
1713
        String sql = null;
1714
        PreparedStatement pstmt = null;
1715
        if (topLevel) {
1716
            sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1717
                    + "perm_type, perm_order, accessfileid) VALUES "
1718
                    + " (?, ?, ?, ?, ?, ?)";
1719
        } else {
1720
            sql = "INSERT INTO xml_access (docid,principal_name, "
1721
                    + "permission, perm_type, perm_order, accessfileid, subtreeid, "
1722
                    + " startnodeid, endnodeid) VALUES"
1723
                    + " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1724
        }
1725
        try {
1726

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

    
1769
            }
1770

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

    
1808
    }//writeGivenAccessRuleIntoDB
1809

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

    
1825
        try {
1826

    
1827
            pstmt = connection.prepareStatement(sql);
1828
            // Increase DBConnection usage count
1829
            connection.increaseUsageCount(1);
1830
            // Bind the values to the query
1831
            pstmt.setString(1, dataId);
1832
            MetaCatUtil.debugMessage("Docid in accesstable: " + docid, 35);
1833
            pstmt.setString(6, docid);
1834
            MetaCatUtil.debugMessage("Accessfileid in accesstable: " + docid,
1835
                    35);
1836
            pstmt.setString(5, permOrder);
1837
            MetaCatUtil.debugMessage("PermOder in accesstable: " + permOrder,
1838
                    35);
1839
            // if it is not top level, set subsection id
1840

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

    
1878
    }//writeAccessRuleForRalatedDataFileIntoDB
1879

    
1880
    /* Delete from db all permission for resources related to @aclid if any. */
1881
    private void deletePermissionsInAccessTable(String aclid)
1882
            throws SAXException
1883
    {
1884
        Statement stmt = null;
1885
        try {
1886
            // delete all acl records for resources related to @aclid if any
1887
            stmt = connection.createStatement();
1888
            // Increase DBConnection usage count
1889
            connection.increaseUsageCount(1);
1890
            stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
1891
                    + aclid + "'");
1892

    
1893
        } catch (SQLException e) {
1894
            throw new SAXException(e.getMessage());
1895
        } finally {
1896
            try {
1897
                stmt.close();
1898
            } catch (SQLException ee) {
1899
                throw new SAXException(ee.getMessage());
1900
            }
1901
        }
1902
    }//deletePermissionsInAccessTable
1903

    
1904
    /*
1905
     * In order to make sure only usr has "all" permission can update access
1906
     * subtree in eml document we need to keep access subtree info in
1907
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1908
     */
1909
    private void writeAccessSubTreeIntoDB(AccessSection accessSection,
1910
            String level) throws SAXException
1911
    {
1912
        if (accessSection == null) { throw new SAXException(
1913
                "The access object is null"); }
1914

    
1915
        String sql = null;
1916
        PreparedStatement pstmt = null;
1917
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1918
                + "subtreeid, startnodeid, endnodeid) VALUES "
1919
                + " (?, ?, ?, ?, ?, ?)";
1920
        try {
1921

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

    
1962
    }//writeAccessSubtreeIntoDB
1963

    
1964
    /* Delete every access subtree record from xml_accesssubtree. */
1965
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
1966
    {
1967
        Statement stmt = null;
1968
        try {
1969
            // delete all acl records for resources related to @aclid if any
1970
            stmt = connection.createStatement();
1971
            // Increase DBConnection usage count
1972
            connection.increaseUsageCount(1);
1973
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
1974
                    + docId + "'");
1975

    
1976
        } catch (SQLException e) {
1977
            throw new SAXException(e.getMessage());
1978
        } finally {
1979
            try {
1980
                stmt.close();
1981
            } catch (SQLException ee) {
1982
                throw new SAXException(ee.getMessage());
1983
            }
1984
        }
1985
    }//deleteAccessSubTreeRecord
1986

    
1987
    // open a file writer for writing inline data to file
1988
    private FileWriter createInlineDataFileWriter(String fileName)
1989
            throws SAXException
1990
    {
1991
        FileWriter writer = null;
1992
        String path = MetaCatUtil.getOption("inlinedatafilepath");
1993
        /*
1994
         * File inlineDataDirectory = new File(path);
1995
         */
1996
        String newFile = path + "/" + fileName;
1997
        MetaCatUtil.debugMessage("inline file name: " + newFile, 30);
1998
        try {
1999
            // true means append
2000
            writer = new FileWriter(newFile, true);
2001
        } catch (IOException ioe) {
2002
            throw new SAXException(ioe.getMessage());
2003
        }
2004
        return writer;
2005
    }
2006

    
2007
    // write inline data into file system and return file name(without path)
2008
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2009
            throws SAXException
2010
    {
2011
        try {
2012
            writer.write(data.toString());
2013
            writer.flush();
2014
        } catch (Exception e) {
2015
            throw new SAXException(e.getMessage());
2016
        }
2017
    }
2018

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

    
2044
            // at the end oldstring will be null
2045
            while (oldString != null) {
2046
                oldString = oldStringReader.readLine();
2047
                newString = newStringReader.readLine();
2048
                if (!oldString.equals(newString)) {
2049
                    same = false;
2050
                    break;
2051
                }
2052
            }
2053

    
2054
            // if oldString is null but newString is not null, they are same
2055
            if (same) {
2056
                if (newString != null) {
2057
                    same = false;
2058
                }
2059
            }
2060

    
2061
        } catch (Exception e) {
2062
            throw new McdbException(e.getMessage());
2063
        }
2064
        MetaCatUtil.debugMessage("the inline data retrieve from file: " + data,
2065
                50);
2066
        return same;
2067
    }
2068

    
2069
    // if xml file failed to upload, we need to call this method to delete
2070
    // the inline data already in file system
2071
    public void deleteInlineFiles()
2072
    {
2073
        if (!inlineFileIDList.isEmpty()) {
2074
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2075
                String fileName = (String) inlineFileIDList.elementAt(i);
2076
                deleteInlineDataFile(fileName);
2077
            }
2078
        }
2079
    }
2080

    
2081
    /* delete the inline data file */
2082
    private void deleteInlineDataFile(String fileName)
2083
    {
2084

    
2085
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2086
        File inlineDataDirectory = new File(path);
2087
        File newFile = new File(inlineDataDirectory, fileName);
2088
        newFile.delete();
2089

    
2090
    }
2091

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

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

    
2143
    /* Write an online data file id into xml_relation table. The dataId shouldnot
2144
     * have the revision
2145
     */
2146
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2147
            throws SAXException
2148
    {
2149
        PreparedStatement pStmt = null;
2150
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2151
                + "relationship, object) values (?, ?, ?, ?, ?)";
2152
        try {
2153
            pStmt = connection.prepareStatement(sql);
2154
            //bind variable
2155
            pStmt.setString(1, docid);
2156
            pStmt.setString(2, DocumentImpl.EML2_1_0NAMESPACE);
2157
            pStmt.setString(3, docid);
2158
            pStmt.setString(4, RELATION);
2159
            pStmt.setString(5, dataId);
2160
            //execute query
2161
            pStmt.execute();
2162
            pStmt.close();
2163
        }//try
2164
        catch (SQLException e) {
2165
            throw new SAXException(
2166
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2167
                            + e.getMessage());
2168
        }//catch
2169
        finally {
2170
            try {
2171
                pStmt.close();
2172
            }//try
2173
            catch (SQLException ee) {
2174
                throw new SAXException(
2175
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2176
                                + ee.getMessage());
2177
            }//catch
2178
        }//finally
2179

    
2180
    }//writeOnlineDataFileIdIntoRelationTable
2181

    
2182
    /*
2183
     * This method will handle data file in online url. If the data file is in
2184
     * ecogrid protocol, then the datafile identifier(without rev)should be put
2185
     * into onlineDataFileRelationVector. The  docid in this vector will be
2186
     * insert into xml_relation table in endDocument().
2187
     * If the data file doesn't exsit in xml_documents or
2188
     * xml_revision table, or the user has all permission to the data file if
2189
     * the docid already existed, the data file id (without rev)will be put into
2190
     * onlineDataFileTopAccessVector. The top access rules specified in this eml
2191
     * document will apply to the data file.
2192
     * NEED to do:
2193
     * We should also need to implement http and ftp. Those
2194
     * external files should be download and assign a data file id to it.
2195
     */
2196
    private void handleOnlineUrlDataFile(String url) throws SAXException
2197
    {
2198
      MetaCatUtil.debugMessage("The url is "+ url, 10);
2199
      // if the url is not a ecogrid protocol, null will be getten
2200
      String accessionNumber =
2201
                 MetaCatUtil.getAccessionNumberFromEcogridIdentifier(url);
2202
      if (accessionNumber != null)
2203
      {
2204
        // handle ecogrid protocol
2205
        // get rid of revision number to get the docid.
2206
        String docid = MetaCatUtil.getDocIdFromAccessionNumber(accessionNumber);
2207
        onlineDataFileIdInRelationVector.add(docid);
2208
        try
2209
        {
2210

    
2211
          if (!AccessionNumber.accNumberUsed(docid))
2212
          {
2213
            onlineDataFileIdInTopAccessVector.add(docid);
2214
          }
2215
          PermissionController controller = new
2216
              PermissionController(accessionNumber);
2217
          if (controller.hasPermission(
2218
              user, groups, AccessControlInterface.ALLSTRING))
2219
          {
2220
            onlineDataFileIdInTopAccessVector.add(docid);
2221
          }
2222
        }//try
2223
        catch(Exception e)
2224
        {
2225
          MetaCatUtil.debugMessage("Eorr in " +
2226
                                "Eml210SAXHanlder.handleOnlineUrlDataFile is " +
2227
                                 e.getMessage(), 30);
2228
          throw new SAXException(e.getMessage());
2229
        }
2230
      }
2231
    }
2232

    
2233
}
(35-35/63)