Project

General

Profile

1 2169 sgarg
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28
29
package edu.ucsb.nceas.metacat;
30
31
import java.io.BufferedReader;
32
import java.io.File;
33
import java.io.FileReader;
34
import java.io.FileWriter;
35
import java.io.IOException;
36
import java.io.Reader;
37
import java.sql.PreparedStatement;
38
import java.sql.ResultSet;
39
import java.sql.SQLException;
40
import java.sql.Statement;
41
import java.util.EmptyStackException;
42
import java.util.Enumeration;
43
import java.util.Hashtable;
44
import java.util.Stack;
45
import java.util.Vector;
46
47
import org.xml.sax.Attributes;
48
import org.xml.sax.SAXException;
49
50
/**
51
 * A database aware Class implementing callback bethods for the SAX parser to
52
 * call when processing the XML stream and generating events
53
 */
54
public class 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 = controller.hasUnaccessableSubTree(user, groups,
218
                AccessControlInterface.WRITESTRING);
219
        if (list != null) {
220
221
            Enumeration en = list.elements();
222
            while (en.hasMoreElements()) {
223
                // Get a subtree without node record list
224
                SubTree treeWithoutStack = (SubTree) en.nextElement();
225
                String subTreeId = treeWithoutStack.getSubTreeId();
226
                MetaCatUtil.debugMessage(
227
                        "unchangable subtree id: " + subTreeId, 40);
228
                long startNodeId = treeWithoutStack.getStartNodeId();
229
                MetaCatUtil.debugMessage("unchangable subtree startnodeid: "
230
                        + startNodeId, 40);
231
                long endNodeId = treeWithoutStack.getEndNodeId();
232
                MetaCatUtil.debugMessage("unchangable subtree endnodeid: "
233
                        + endNodeId, 40);
234
                // Get a subtree has the nodelist
235
                SubTree tree = new SubTree(docid, subTreeId, startNodeId,
236
                        endNodeId);
237
                // add this tree to the result
238
                result.put(subTreeId, tree);
239
240
            }//while
241
242
        }//if
243
244
        return result;
245
    }
246
247
    /*
248
     * Get the subtree node info from xml_accesssubtree table
249
     */
250
    private Vector getAccessSubTreeListFromDB() throws Exception
251
    {
252
        Vector result = new Vector();
253
        PreparedStatement pstmt = null;
254
        ResultSet rs = null;
255
        String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid "
256
                + "FROM xml_accesssubtree WHERE docid like ? "
257
                + "ORDER BY startnodeid ASC";
258
259
        try {
260
261
            pstmt = connection.prepareStatement(sql);
262
            // Increase DBConnection usage count
263
            connection.increaseUsageCount(1);
264
            // Bind the values to the query
265
            pstmt.setString(1, docid);
266
            pstmt.execute();
267
268
            // Get result set
269
            rs = pstmt.getResultSet();
270
            while (rs.next()) {
271
                String level = rs.getString(1);
272
                String sectionId = rs.getString(2);
273
                long startNodeId = rs.getLong(3);
274
                long endNodeId = rs.getLong(4);
275
                // create a new access section
276
                AccessSection accessObj = new AccessSection();
277
                accessObj.setControlLevel(level);
278
                accessObj.setDocId(docid);
279
                accessObj.setSubTreeId(sectionId);
280
                accessObj.setStartNodeId(startNodeId);
281
                accessObj.setEndNodeId(endNodeId);
282
                Stack nodeStack = accessObj.getSubTreeNodeList();
283
                accessObj.setSubTreeNodeStack(nodeStack);
284
                // add this access obj into vector
285
                result.add(accessObj);
286
                // Get the top level access subtree control
287
                if (level != null && level.equals(TOPLEVEL)) {
288
                    topAccessSection = accessObj;
289
                }
290
            }
291
            pstmt.close();
292
        }//try
293
        catch (SQLException e) {
294
            throw new SAXException(
295
                    "EMLSAXHandler.getAccessSubTreeListFromDB(): "
296
                            + e.getMessage());
297
        }//catch
298
        finally {
299
            try {
300
                pstmt.close();
301
            } catch (SQLException ee) {
302
                throw new SAXException(
303
                        "EMLSAXHandler.getAccessSubTreeListFromDB(): "
304
                                + ee.getMessage());
305
            }
306
        }//finally
307
        return result;
308
    }
309
310
    /** SAX Handler that is called at the start of each XML element */
311
    public void startElement(String uri, String localName, String qName,
312
            Attributes atts) throws SAXException
313
    {
314
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
315
        // for element <acl....> both qname and local name is "eml"
316
        // uri is namesapce
317
        MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
318
        MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
319
        MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
320
321
        DBSAXNode parentNode = null;
322
        DBSAXNode currentNode = null;
323
324
        if (!handleInlineData) {
325
            // Get a reference to the parent node for the id
326
            try {
327
                parentNode = (DBSAXNode) nodeStack.peek();
328
            } catch (EmptyStackException e) {
329
                parentNode = null;
330
            }
331
332
            //start handle inline data
333
            if (localName.equals(INLINE)) {
334
                handleInlineData = true;
335
                inLineDataIndex++;
336
                //intitialize namespace hash for in line data
337
                inlineDataNameSpace = new Hashtable();
338
                //initialize file writer
339
                String docidWithoutRev = MetaCatUtil.getDocIdFromString(docid);
340
                String seperator = MetaCatUtil.getOption("accNumSeparator");
341
                // the new file name will look like docid.rev.2
342
                inlineDataFileName = docidWithoutRev + seperator + revision
343
                        + seperator + inLineDataIndex;
344
                inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
345
                // put the inline file id into a vector. If upload failed,
346
                // metacat will
347
                // delete the inline data file
348
                inlineFileIDList.add(inlineDataFileName);
349
350
            }
351
352
            // If hit a text node, we need write this text for current's parent
353
            // node
354
            // This will happend if the element is mixted
355
            if (hitTextNode && parentNode != null) {
356
                //compare text node data for unchangesubtree
357
                if (startCriticalSubTree) {
358
                    compareTextNode(currentUnChangedableSubtreeNodeStack,
359
                            textBuffer, PERMISSIONERROR);
360
                }//if
361
362
                //compare top level access module
363
                if (processTopLeverAccess && needCheckingAccessModule) {
364
                    compareTextNode(currentUnchangableAccessModuleNodeStack,
365
                            textBuffer, UPDATEACCESSERROR);
366
                }
367
368
                if (needCheckingAccessModule
369
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
370
                    // stored the pull out nodes into storedNode stack
371
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
372
                            null, null, MetaCatUtil.normalize(textBuffer
373
                                    .toString()));
374
                    storedAccessNodeStack.push(nodeElement);
375
376
                }
377
378
                // write the textbuffer into db for parent node.
379
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
380
                        parentNode);
381
                // rest hitTextNode
382
                hitTextNode = false;
383
                // reset textbuffer
384
                textBuffer = null;
385
                textBuffer = new StringBuffer();
386
387
            }
388
389
            // Document representation that points to the root document node
390
            if (atFirstElement) {
391
                atFirstElement = false;
392
                // If no DOCTYPE declaration: docname = root element
393
                // doctype = root element name or name space
394
                if (docname == null) {
395
                    docname = localName;
396
                    // if uri isn't null doctype = uri(namespace)
397
                    // othewise root element
398
                    if (uri != null && !(uri.trim()).equals("")) {
399
                        doctype = uri;
400
                    } else {
401
                        doctype = docname;
402
                    }
403
                    MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
404
                    MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
405
                } else if (doctype == null) {
406
                    // because docname is not null and it is declared in dtd
407
                    // so could not be in schema, no namespace
408
                    doctype = docname;
409
                    MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
410
                }
411
                rootNode.writeNodename(docname);
412
                try {
413
                    // for validated XML Documents store a reference to XML DB
414
                    // Catalog
415
                    // Because this is select statement and it needn't to roll
416
                    // back if
417
                    // insert document action fialed.
418
                    // In order to decrease DBConnection usage count, we get a
419
                    // new
420
                    // dbconnection from pool
421
                    String catalogid = null;
422
                    DBConnection dbConn = null;
423
                    int serialNumber = -1;
424
425
                    try {
426
                        // Get dbconnection
427
                        dbConn = DBConnectionPool
428
                                .getDBConnection("DBSAXHandler.startElement");
429
                        serialNumber = dbConn.getCheckOutSerialNumber();
430
431
                        Statement stmt = dbConn.createStatement();
432
                        ResultSet rs = stmt
433
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
434
                                        + "WHERE entry_type = 'Schema' "
435
                                        + "AND public_id = '" + doctype + "'");
436
                        boolean hasRow = rs.next();
437
                        if (hasRow) {
438
                            catalogid = rs.getString(1);
439
                        }
440
                        stmt.close();
441
                    }//try
442
                    finally {
443
                        // Return dbconnection
444
                        DBConnectionPool.returnDBConnection(dbConn,
445
                                serialNumber);
446
                    }//finally
447
448
                    //create documentImpl object by the constructor which can
449
                    // specify
450
                    //the revision
451
                    currentDocument = new DocumentImpl(connection, rootNode
452
                            .getNodeID(), docname, doctype, docid, revision,
453
                            action, user, this.pub, catalogid, this.serverCode);
454
455
                } catch (Exception ane) {
456
                    throw (new SAXException(
457
                            "Error in EMLSaxHandler.startElement " + action,
458
                            ane));
459
                }
460
            }
461
462
            // Create the current node representation
463
            currentNode = new DBSAXNode(connection, qName, localName,
464
                    parentNode, currentDocument.getRootNodeID(), docid,
465
                    currentDocument.getDoctype());
466
            // Use a local variable to store the element node id
467
            // If this element is a start point of subtree(section), it will be
468
            // stored
469
            // otherwise, it will be discated
470
            long startNodeId = currentNode.getNodeID();
471
            // Add all of the namespaces
472
            String prefix = null;
473
            String nsuri = null;
474
            Enumeration prefixes = namespaces.keys();
475
            while (prefixes.hasMoreElements()) {
476
                prefix = (String) prefixes.nextElement();
477
                nsuri = (String) namespaces.get(prefix);
478
                endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
479
            }
480
481
            // Add all of the attributes
482
            for (int i = 0; i < atts.getLength(); i++) {
483
                String attributeName = atts.getQName(i);
484
                String attributeValue = atts.getValue(i);
485
                endNodeId = currentNode.setAttribute(attributeName,
486
                        attributeValue, docid);
487
488
                // To handle name space and schema location if the attribute
489
                // name is
490
                // xsi:schemaLocation. If the name space is in not in catalog
491
                // table
492
                // it will be regeistered.
493
                if (attributeName != null
494
                        && attributeName
495
                                .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
496
                    SchemaLocationResolver resolver = new SchemaLocationResolver(
497
                            attributeValue);
498
                    resolver.resolveNameSpace();
499
500
                } else if (attributeName != null && attributeName.equals(ID)) {
501
502
                    //check unchangedable subtree hash if contains this
503
                    // subtree id
504
                    if (unChangableSubTreeHash.containsKey(attributeValue)) {
505
                        // this subtree couldn't be changed by the user and
506
                        // move it from hash
507
                        SubTree currentUnChangedableSubtree = (SubTree) unChangableSubTreeHash
508
                                .remove(attributeValue);
509
                        currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree
510
                                .getSubTreeNodeStack();
511
                        startCriticalSubTree = true;
512
                        firstElementForCriticalSubTree = true;
513
                    }
514
515
                    // handle subtree info
516
                    SubTree subTress = new SubTree();
517
                    // set sub tree id
518
                    subTress.setSubTreeId(attributeValue);
519
                    // set sub tree sstart lement name
520
                    subTress.setStartElementName(currentNode.getTagName());
521
                    // set start node number
522
                    subTress.setStartNodeId(startNodeId);
523
                    // add to stack, but it didn't get end node id yet
524
                    subTreeInfoStack.push(subTress);
525
526
                }
527
            }//for
528
529
            // handle access stuff
530
            if (localName.equals(ACCESS)) {
531
                // if it is in addtionalmetacat
532
                if (parentNode.getTagName() == ADDITIONALMETADATA) {
533
                    processAdditionalAccess = true;
534
535
                } else {
536
                    //make sure the access is top level
537
                    // this mean current node's parent's parent should be "eml"
538
                    DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
539
                                                                    // parent
540
                                                                    // node
541
                    //peek out grandParentNode
542
                    DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
543
                    // put parent node back
544
                    nodeStack.push(tmpNode);
545
                    String grandParentTag = grandParentNode.getTagName();
546
                    if (grandParentTag.equals(EML)) {
547
                        processTopLeverAccess = true;
548
                    } else {
549
                        // process other access embedded into resource level
550
                        // module
551
                        processOtherAccess = true;
552
                    }
553
554
                }
555
                // create access object
556
                accessObject = new AccessSection();
557
                // set permission order
558
                String permOrder = currentNode.getAttribute(ORDER);
559
                accessObject.setPermissionOrder(permOrder);
560
                // set access id
561
                String accessId = currentNode.getAttribute(ID);
562
                accessObject.setSubTreeId(accessId);
563
                accessObject.setStartNodeId(startNodeId);
564
                accessObject.setDocId(docid);
565
566
                // load top level node stack to
567
                // currentUnchangableAccessModuleNodeStack
568
                if (processTopLeverAccess && needCheckingAccessModule) {
569
                    // get the node stack for
570
                    currentUnchangableAccessModuleNodeStack = topAccessSection
571
                            .getSubTreeNodeStack();
572
                }
573
574
            }
575
            // Set up a access rule for allow
576
            else if (parentNode.getTagName() != null
577
                    && (parentNode.getTagName()).equals(ACCESS)
578
                    && localName.equals(ALLOW)) {
579
580
                accessRule = new AccessRule();
581
582
                //set permission type "allow"
583
                accessRule.setPermissionType(ALLOW);
584
585
            }
586
            // set up an access rule for den
587
            else if (parentNode.getTagName() != null
588
                    && (parentNode.getTagName()).equals(ACCESS)
589
                    && localName.equals(DENY)) {
590
                accessRule = new AccessRule();
591
                //set permission type "allow"
592
                accessRule.setPermissionType(DENY);
593
            }
594
595
            // Add the node to the stack, so that any text data can be
596
            // added as it is encountered
597
            nodeStack.push(currentNode);
598
            // Add the node to the vector used by thread for writing XML Index
599
            nodeIndex.addElement(currentNode);
600
601
            // handle critical subtree
602
            if (startCriticalSubTree && firstElementForCriticalSubTree) {
603
                //store the element name
604
                firstElementNameForCriticalSubTree = qName;
605
                firstElementForCriticalSubTree = false;
606
            }//for first element
607
608
            // handle critical subtree
609
            if (startCriticalSubTree) {
610
                compareElementNameSpaceAttributes(
611
                        currentUnChangedableSubtreeNodeStack, namespaces, atts,
612
                        localName, PERMISSIONERROR);
613
614
            }
615
            //compare top access level module
616
            if (processTopLeverAccess && needCheckingAccessModule) {
617
                compareElementNameSpaceAttributes(
618
                        currentUnchangableAccessModuleNodeStack, namespaces,
619
                        atts, localName, UPDATEACCESSERROR);
620
621
            }
622
623
            // store access module element and attributes into stored stack
624
            if (needCheckingAccessModule
625
                    && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
626
                // stored the pull out nodes into storedNode stack
627
                NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
628
                        localName, prefix, MetaCatUtil.normalize(null));
629
                storedAccessNodeStack.push(nodeElement);
630
                for (int i = 0; i < atts.getLength(); i++) {
631
                    String attributeName = atts.getQName(i);
632
                    String attributeValue = atts.getValue(i);
633
                    NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2,
634
                            "ATTRIBUTE", attributeName, null, MetaCatUtil
635
                                    .normalize(attributeValue));
636
                    storedAccessNodeStack.push(nodeAttribute);
637
                }
638
639
            }
640
641
            // reset name space
642
            namespaces = null;
643
            namespaces = new Hashtable();
644
        }//not inline data
645
        else {
646
            // we don't buffer the inline data in characters() method
647
            // so start character don't need to hand text node.
648
649
            // inline data may be the xml format.
650
            StringBuffer inlineElements = new StringBuffer();
651
            inlineElements.append("<").append(qName);
652
            // append attributes
653
            for (int i = 0; i < atts.getLength(); i++) {
654
                String attributeName = atts.getQName(i);
655
                String attributeValue = atts.getValue(i);
656
                inlineElements.append(" ");
657
                inlineElements.append(attributeName);
658
                inlineElements.append("=\"");
659
                inlineElements.append(attributeValue);
660
                inlineElements.append("\"");
661
            }
662
            // append namespace
663
            String prefix = null;
664
            String nsuri = null;
665
            Enumeration prefixes = inlineDataNameSpace.keys();
666
            while (prefixes.hasMoreElements()) {
667
                prefix = (String) prefixes.nextElement();
668
                nsuri = (String) namespaces.get(prefix);
669
                inlineElements.append(" ");
670
                inlineElements.append("xmlns:");
671
                inlineElements.append(prefix);
672
                inlineElements.append("=\"");
673
                inlineElements.append(nsuri);
674
                inlineElements.append("\"");
675
            }
676
            inlineElements.append(">");
677
            //reset inline data name space
678
            inlineDataNameSpace = null;
679
            inlineDataNameSpace = new Hashtable();
680
            //write inline data into file
681
            MetaCatUtil.debugMessage("the inline element data is: "
682
                    + inlineElements.toString(), 50);
683
            writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
684
        }//else
685
686
    }
687
688
    private void compareElementNameSpaceAttributes(Stack unchangableNodeStack,
689
            Hashtable nameSpaces, Attributes attributes, String localName,
690
            String error) throws SAXException
691
    {
692
        //Get element subtree node stack (element node)
693
        NodeRecord elementNode = null;
694
        try {
695
            elementNode = (NodeRecord) unchangableNodeStack.pop();
696
        } catch (EmptyStackException ee) {
697
            MetaCatUtil
698
                    .debugMessage("Node stack is empty for element data", 35);
699
            throw new SAXException(error);
700
        }
701
        MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
702
        MetaCatUtil.debugMessage("node type from stack: "
703
                + elementNode.getNodeType(), 40);
704
        MetaCatUtil.debugMessage("node name from xml document: " + localName,
705
                40);
706
        MetaCatUtil.debugMessage("node name from stack: "
707
                + elementNode.getNodeName(), 40);
708
        MetaCatUtil.debugMessage("node data from stack: "
709
                + elementNode.getNodeData(), 40);
710
        MetaCatUtil.debugMessage("node id is: " + elementNode.getNodeId(), 40);
711
        // if this node is not element or local name not equal or name space
712
        // not
713
        // equals, throw an exception
714
        if (!elementNode.getNodeType().equals("ELEMENT")
715
                || !localName.equals(elementNode.getNodeName()))
716
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
717
        {
718
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
719
            MetaCatUtil.debugMessage("current node type from xml is ELEMENT",
720
                    40);
721
            MetaCatUtil.debugMessage("node type from stack: "
722
                    + elementNode.getNodeType(), 40);
723
            MetaCatUtil.debugMessage("node name from xml document: "
724
                    + localName, 40);
725
            MetaCatUtil.debugMessage("node name from stack: "
726
                    + elementNode.getNodeName(), 40);
727
            MetaCatUtil.debugMessage("node data from stack: "
728
                    + elementNode.getNodeData(), 40);
729
            MetaCatUtil.debugMessage("node id is: " + elementNode.getNodeId(),
730
                    40);
731
            throw new SAXException(error);
732
        }
733
734
        //compare namespace
735
        Enumeration nameEn = nameSpaces.keys();
736
        while (nameEn.hasMoreElements()) {
737
            //Get namespacke node stack (element node)
738
            NodeRecord nameNode = null;
739
            try {
740
                nameNode = (NodeRecord) unchangableNodeStack.pop();
741
            } catch (EmptyStackException ee) {
742
                MetaCatUtil.debugMessage(
743
                        "Node stack is empty for namespace data", 35);
744
                throw new SAXException(error);
745
            }
746
747
            String prefixName = (String) nameEn.nextElement();
748
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
749
            if (!nameNode.getNodeType().equals("NAMESPACE")
750
                    || !prefixName.equals(nameNode.getNodeName())
751
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
752
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
753
                MetaCatUtil.debugMessage(
754
                        "current node type from xml is NAMESPACE", 40);
755
                MetaCatUtil.debugMessage("node type from stack: "
756
                        + nameNode.getNodeType(), 40);
757
                MetaCatUtil.debugMessage("current node name from xml is: "
758
                        + prefixName, 40);
759
                MetaCatUtil.debugMessage("node name from stack: "
760
                        + nameNode.getNodeName(), 40);
761
                MetaCatUtil.debugMessage("current node data from xml is: "
762
                        + nameSpaceUri, 40);
763
                MetaCatUtil.debugMessage("node data from stack: "
764
                        + nameNode.getNodeData(), 40);
765
                MetaCatUtil.debugMessage("node id is: " + nameNode.getNodeId(),
766
                        40);
767
                throw new SAXException(error);
768
            }
769
770
        }//while
771
772
        //compare attributes
773
        for (int i = 0; i < attributes.getLength(); i++) {
774
            NodeRecord attriNode = null;
775
            try {
776
                attriNode = (NodeRecord) unchangableNodeStack.pop();
777
778
            } catch (EmptyStackException ee) {
779
                MetaCatUtil.debugMessage(
780
                        "Node stack is empty for attribute data", 35);
781
                throw new SAXException(error);
782
            }
783
            String attributeName = attributes.getQName(i);
784
            String attributeValue = attributes.getValue(i);
785
            MetaCatUtil.debugMessage(
786
                    "current node type from xml is ATTRIBUTE ", 40);
787
            MetaCatUtil.debugMessage("node type from stack: "
788
                    + attriNode.getNodeType(), 40);
789
            MetaCatUtil.debugMessage("current node name from xml is: "
790
                    + attributeName, 40);
791
            MetaCatUtil.debugMessage("node name from stack: "
792
                    + attriNode.getNodeName(), 40);
793
            MetaCatUtil.debugMessage("current node data from xml is: "
794
                    + attributeValue, 40);
795
            MetaCatUtil.debugMessage("node data from stack: "
796
                    + attriNode.getNodeData(), 40);
797
            MetaCatUtil.debugMessage("node id  is: " + attriNode.getNodeId(),
798
                    40);
799
800
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
801
                    || !attributeName.equals(attriNode.getNodeName())
802
                    || !attributeValue.equals(attriNode.getNodeData())) {
803
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
804
                MetaCatUtil.debugMessage(
805
                        "current node type from xml is ATTRIBUTE ", 40);
806
                MetaCatUtil.debugMessage("node type from stack: "
807
                        + attriNode.getNodeType(), 40);
808
                MetaCatUtil.debugMessage("current node name from xml is: "
809
                        + attributeName, 40);
810
                MetaCatUtil.debugMessage("node name from stack: "
811
                        + attriNode.getNodeName(), 40);
812
                MetaCatUtil.debugMessage("current node data from xml is: "
813
                        + attributeValue, 40);
814
                MetaCatUtil.debugMessage("node data from stack: "
815
                        + attriNode.getNodeData(), 40);
816
                MetaCatUtil.debugMessage("node is: " + attriNode.getNodeId(),
817
                        40);
818
                throw new SAXException(error);
819
            }
820
        }//for
821
822
    }
823
824
    /* mehtod to compare current text node and node in db */
825
    private void compareTextNode(Stack nodeStack, StringBuffer text,
826
            String error) throws SAXException
827
    {
828
        NodeRecord node = null;
829
        //get node from current stack
830
        try {
831
            node = (NodeRecord) nodeStack.pop();
832
        } catch (EmptyStackException ee) {
833
            MetaCatUtil.debugMessage(
834
                    "Node stack is empty for text data in startElement", 35);
835
            throw new SAXException(error);
836
        }
837
        MetaCatUtil.debugMessage(
838
                "current node type from xml is TEXT in start element", 40);
839
        MetaCatUtil.debugMessage("node type from stack: " + node.getNodeType(),
840
                40);
841
        MetaCatUtil.debugMessage("current node data from xml is: "
842
                + text.toString(), 40);
843
        MetaCatUtil.debugMessage("node data from stack: " + node.getNodeData(),
844
                40);
845
        MetaCatUtil.debugMessage("node name from stack: " + node.getNodeName(),
846
                40);
847
        MetaCatUtil.debugMessage("node is: " + node.getNodeId(), 40);
848
        if (!node.getNodeType().equals("TEXT")
849
                || !(text.toString()).equals(node.getNodeData())) {
850
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
851
            MetaCatUtil.debugMessage(
852
                    "current node type from xml is TEXT in start element", 40);
853
            MetaCatUtil.debugMessage("node type from stack: "
854
                    + node.getNodeType(), 40);
855
            MetaCatUtil.debugMessage("current node data from xml is: "
856
                    + text.toString(), 40);
857
            MetaCatUtil.debugMessage("node data from stack: "
858
                    + node.getNodeData(), 40);
859
            MetaCatUtil.debugMessage("node name from stack: "
860
                    + node.getNodeName(), 40);
861
            MetaCatUtil.debugMessage("node is: " + node.getNodeId(), 40);
862
            throw new SAXException(error);
863
        }//if
864
    }
865
866
    /** SAX Handler that is called for each XML text node */
867
    public void characters(char[] cbuf, int start, int len) throws SAXException
868
    {
869
        MetaCatUtil.debugMessage("CHARACTERS", 50);
870
        if (!handleInlineData) {
871
            // buffer all text nodes for same element. This is for text was
872
            // splited
873
            // into different nodes
874
            textBuffer.append(new String(cbuf, start, len));
875
            // set hittextnode true
876
            hitTextNode = true;
877
            // if text buffer .size is greater than max, write it to db.
878
            // so we can save memory
879
            if (textBuffer.length() > MAXDATACHARS) {
880
                MetaCatUtil
881
                        .debugMessage(
882
                                "Write text into DB in charaters"
883
                                        + " when text buffer size is greater than maxmum number",
884
                                50);
885
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
886
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
887
                        currentNode);
888
                textBuffer = null;
889
                textBuffer = new StringBuffer();
890
            }
891
        } else {
892
            // this is inline data and write file system directly
893
            // we don't need to buffered it.
894
            StringBuffer inlineText = new StringBuffer();
895
            inlineText.append(new String(cbuf, start, len));
896
            MetaCatUtil.debugMessage(
897
                    "The inline text data write into file system: "
898
                            + inlineText.toString(), 50);
899
            writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
900
        }
901
    }
902
903
    /** SAX Handler that is called at the end of each XML element */
904
    public void endElement(String uri, String localName, String qName)
905
            throws SAXException
906
    {
907
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
908
909
        if (localName.equals(INLINE) && handleInlineData) {
910
            // Get the node from the stack
911
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
912
            String currentTag = currentNode.getTagName();
913
            MetaCatUtil.debugMessage("End of inline data", 35);
914
            // close file writer
915
            try {
916
                inlineDataFileWriter.close();
917
                handleInlineData = false;
918
            } catch (IOException ioe) {
919
                throw new SAXException(ioe.getMessage());
920
            }
921
922
            //check if user changed inine data or not if user doesn't have
923
            // write permission
924
            if (startCriticalSubTree) {
925
                NodeRecord node = null;
926
                String inlineData;
927
                try {
928
                    node = (NodeRecord) currentUnChangedableSubtreeNodeStack
929
                            .pop();
930
                    // get file name from db
931
                    String fileName = node.getNodeData();
932
                    MetaCatUtil.debugMessage("in handle inline data", 35);
933
                    MetaCatUtil.debugMessage(
934
                            "the inline data file name from node is: "
935
                                    + fileName, 40);
936
                    if (!compareInlineDataFiles(fileName, inlineDataFileName)) {
937
                        MetaCatUtil.debugMessage(
938
                                "inline data was changed by a user"
939
                                        + " who doesn't have permission", 30);
940
                        throw new SAXException(PERMISSIONERROR);
941
                    }
942
                } catch (EmptyStackException ee) {
943
                    MetaCatUtil.debugMessage(
944
                            "the stack is empty for text data", 32);
945
                    throw new SAXException(PERMISSIONERROR);
946
                } catch (McdbException eee) {
947
                    throw new SAXException(eee.getMessage());
948
                } finally {
949
                    // delete the inline data file already in file system
950
                    deleteInlineDataFile(inlineDataFileName);
951
                }
952
953
            }//if
954
            // write put inline data file name into text buffer (without path)
955
            textBuffer = new StringBuffer(inlineDataFileName);
956
            // write file name into db
957
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
958
                    currentNode);
959
            // reset textbuff
960
            textBuffer = null;
961
            textBuffer = new StringBuffer();
962
            return;
963
        }
964
965
        if (!handleInlineData) {
966
            // Get the node from the stack
967
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
968
            String currentTag = currentNode.getTagName();
969
970
            // If before the end element, the parser hit text nodes and store
971
            // them
972
            // into the buffer, write the buffer to data base. The reason we
973
            // put
974
            // write database here is for xerces some time split text node
975
            if (hitTextNode) {
976
                // get access value
977
                String data = null;
978
                // add principal
979
                if (currentTag.equals(PRINCIPAL) && accessRule != null) {
980
                    data = (textBuffer.toString()).trim();
981
                    accessRule.addPrincipal(data);
982
983
                } else if (currentTag.equals(PERMISSION) && accessRule != null) {
984
                    data = (textBuffer.toString()).trim();
985
                    // we conbine different a permission into one value
986
                    int permission = accessRule.getPermission();
987
                    // add permision
988
                    if (data.toUpperCase().equals(READSTRING)) {
989
                        permission = permission | READ;
990
                    } else if (data.toUpperCase().equals(WRITESTRING)) {
991
                        permission = permission | WRITE;
992
                    } else if (data.toUpperCase().equals(CHMODSTRING)) {
993
                        permission = permission | CHMOD;
994
                    } else if (data.toUpperCase().equals(ALLSTRING)) {
995
                        permission = permission | ALL;
996
                    }
997
                    accessRule.setPermission(permission);
998
                }
999
                // put additionalmetadata/describes into vector
1000
                else if (currentTag.equals(DESCRIBES)) {
1001
                    data = (textBuffer.toString()).trim();
1002
                    describesId.add(data);
1003
                } else if (currentTag.equals(REFERENCES)
1004
                        && (processTopLeverAccess || processAdditionalAccess || processOtherAccess)) {
1005
                    // get reference
1006
                    data = (textBuffer.toString()).trim();
1007
                    // put reference id into accessSection
1008
                    accessObject.setReferences(data);
1009
1010
                } else if (currentTag.equals(URL)) {
1011
                    //handle online data, make sure its'parent is online
1012
                    DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1013
                    if (parentNode != null && parentNode.getTagName() != null
1014
                            && parentNode.getTagName().equals(ONLINE)) {
1015
                        // if online data is in local metacat, add it to the
1016
                        // vector
1017
                        data = (textBuffer.toString()).trim();
1018
                        handleOnlineUrlDataFile(data);
1019
                        /*if (data != null
1020
                                && (data.indexOf(MetaCatUtil
1021
                                        .getOption("httpserver")) != -1 || data
1022
                                        .indexOf(MetaCatUtil
1023
                                                .getOption("server")) != -1)) {
1024
                            // Get docid from url
1025
                            String dataId = MetaCatUtil
1026
                                    .getDocIdWithRevFromOnlineURL(data);
1027
                            // add to vector
1028
                            onlineDataFileIdVector.add(dataId);
1029
                        }//if*/
1030
                    }//if
1031
                }//else if
1032
                // write text to db if it is not inline data
1033
                //if (!localName.equals(INLINE))
1034
                {
1035
                    MetaCatUtil.debugMessage(
1036
                            "Write text into DB in End Element", 50);
1037
                    //compare text node if need
1038
                    if (startCriticalSubTree) {
1039
                        compareTextNode(currentUnChangedableSubtreeNodeStack,
1040
                                textBuffer, PERMISSIONERROR);
1041
                    }//if
1042
                    //compare top level access module
1043
                    if (processTopLeverAccess && needCheckingAccessModule) {
1044
                        compareTextNode(
1045
                                currentUnchangableAccessModuleNodeStack,
1046
                                textBuffer, UPDATEACCESSERROR);
1047
                    }
1048
                    // write text node into db
1049
                    endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1050
                            currentNode);
1051
                }
1052
                if (needCheckingAccessModule
1053
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1054
                    // stored the pull out nodes into storedNode stack
1055
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1056
                            null, null, MetaCatUtil.normalize(textBuffer
1057
                                    .toString()));
1058
                    storedAccessNodeStack.push(nodeElement);
1059
1060
                }
1061
            }//if
1062
1063
            //end crtical subtree(user doesn't have permission to write)
1064
            //When reach the first element and stack is empty
1065
            if (localName.equals(firstElementNameForCriticalSubTree)
1066
                    && currentUnChangedableSubtreeNodeStack.isEmpty()) {
1067
                startCriticalSubTree = false;
1068
            }
1069
1070
            //set hitText false
1071
            hitTextNode = false;
1072
            // reset textbuff
1073
            textBuffer = null;
1074
            textBuffer = new StringBuffer();
1075
1076
            // hand sub stree stuff
1077
            if (!subTreeInfoStack.empty()) {
1078
                SubTree tree = (SubTree) subTreeInfoStack.peek();// get last
1079
                                                                 // subtree
1080
                if (tree != null && tree.getStartElementName() != null
1081
                        && (tree.getStartElementName()).equals(currentTag)) {
1082
                    // find the end of sub tree and set the end node id
1083
                    tree.setEndNodeId(endNodeId);
1084
                    // add the subtree into the final store palace
1085
                    subTreeList.add(tree);
1086
                    // get rid of it from stack
1087
                    subTreeInfoStack.pop();
1088
                }//if
1089
            }//if
1090
1091
            // access stuff
1092
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
1093
                // finish parser a ccess rule and assign it to new one
1094
                AccessRule newRule = accessRule;
1095
                //add the new rule to access section object
1096
                accessObject.addAccessRule(newRule);
1097
                // reset access rule
1098
                accessRule = null;
1099
            } else if (currentTag.equals(ACCESS)) {
1100
                // finish parse a access setction and assign it to new one
1101
1102
                accessObject.setEndNodeId(endNodeId);
1103
                AccessSection newAccessObject = accessObject;
1104
1105
                if (newAccessObject != null) {
1106
1107
                    // add the accessSection into a vector to store it
1108
                    // if it is not a reference, need to store it
1109
                    if (newAccessObject.getReferences() == null) {
1110
1111
                        newAccessObject
1112
                                .setStoredTmpNodeStack(storedAccessNodeStack);
1113
                        accessObjectList.add(newAccessObject);
1114
                    }
1115
                    if (processTopLeverAccess) {
1116
1117
                        // top level access control will handle whole document
1118
                        // -docid
1119
                        topLevelAccessControlMap.put(docid, newAccessObject);
1120
                        // reset processtopleveraccess tag
1121
1122
                    }//if
1123
                    else if (processAdditionalAccess) {
1124
                        // for additional control
1125
                        // put everything in describes value and access object
1126
                        // into hash
1127
                        for (int i = 0; i < describesId.size(); i++) {
1128
1129
                            String subId = (String) describesId.elementAt(i);
1130
                            if (subId != null) {
1131
                                additionalAccessControlMap.put(subId,
1132
                                        newAccessObject);
1133
                            }//if
1134
                        }//for
1135
                        // add this hashtable in to vector
1136
1137
                        additionalAccessMapList.add(additionalAccessControlMap);
1138
                        // reset this hashtable in order to store another
1139
                        // additional
1140
                        //accesscontrol
1141
                        additionalAccessControlMap = null;
1142
                        additionalAccessControlMap = new Hashtable();
1143
                    }//if
1144
1145
                }//if
1146
                //check if access node stack is empty after parsing top access
1147
                //module
1148
1149
                if (needCheckingAccessModule && processTopLeverAccess
1150
                        && !currentUnchangableAccessModuleNodeStack.isEmpty()) {
1151
1152
                    MetaCatUtil.debugMessage(
1153
                            "Access node stack is not empty after "
1154
                                    + "parsing access subtree", 40);
1155
                    throw new SAXException(UPDATEACCESSERROR);
1156
1157
                }
1158
                //reset access section object
1159
1160
                accessObject = null;
1161
1162
                // reset tmp stored node stack
1163
                storedAccessNodeStack = null;
1164
                storedAccessNodeStack = new Stack();
1165
1166
                // reset flag
1167
                processAdditionalAccess = false;
1168
                processTopLeverAccess = false;
1169
                processOtherAccess = false;
1170
1171
            } else if (currentTag.equals(ADDITIONALMETADATA)) {
1172
                //reset describesId
1173
                describesId = null;
1174
                describesId = new Vector();
1175
            }
1176
        } else {
1177
            // this is in inline part
1178
            StringBuffer endElement = new StringBuffer();
1179
            endElement.append("</");
1180
            endElement.append(qName);
1181
            endElement.append(">");
1182
            MetaCatUtil.debugMessage("inline endElement: "
1183
                    + endElement.toString(), 50);
1184
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1185
        }
1186
    }
1187
1188
    /**
1189
     * SAX Handler that receives notification of comments in the DTD
1190
     */
1191
    public void comment(char[] ch, int start, int length) throws SAXException
1192
    {
1193
        MetaCatUtil.debugMessage("COMMENT", 50);
1194
        if (!handleInlineData) {
1195
            if (!processingDTD) {
1196
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1197
                String str = new String(ch, start, length);
1198
1199
                //compare comment if need
1200
                if (startCriticalSubTree) {
1201
                    compareCommentNode(currentUnChangedableSubtreeNodeStack,
1202
                            str, PERMISSIONERROR);
1203
                }//if
1204
                //compare top level access module
1205
                if (processTopLeverAccess && needCheckingAccessModule) {
1206
                    compareCommentNode(currentUnchangableAccessModuleNodeStack,
1207
                            str, UPDATEACCESSERROR);
1208
                }
1209
                endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
1210
                        str, docid);
1211
                if (needCheckingAccessModule
1212
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1213
                    // stored the pull out nodes into storedNode stack
1214
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2,
1215
                            "COMMENT", null, null, MetaCatUtil.normalize(str));
1216
                    storedAccessNodeStack.push(nodeElement);
1217
1218
                }
1219
            }
1220
        } else {
1221
            // inline data comment
1222
            StringBuffer inlineComment = new StringBuffer();
1223
            inlineComment.append("<!--");
1224
            inlineComment.append(new String(ch, start, length));
1225
            inlineComment.append("-->");
1226
            MetaCatUtil.debugMessage("inline data comment: "
1227
                    + inlineComment.toString(), 50);
1228
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1229
        }
1230
    }
1231
1232
    /* Comparet comment from xml and db */
1233
    private void compareCommentNode(Stack nodeStack, String string, String error)
1234
            throws SAXException
1235
    {
1236
        NodeRecord node = null;
1237
        try {
1238
            node = (NodeRecord) nodeStack.pop();
1239
        } catch (EmptyStackException ee) {
1240
            MetaCatUtil.debugMessage("the stack is empty for comment data", 32);
1241
            throw new SAXException(error);
1242
        }
1243
        MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
1244
        MetaCatUtil.debugMessage("node type from stack: " + node.getNodeType(),
1245
                40);
1246
        MetaCatUtil
1247
                .debugMessage("current node data from xml is: " + string, 40);
1248
        MetaCatUtil.debugMessage("node data from stack: " + node.getNodeData(),
1249
                40);
1250
        MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(), 40);
1251
        // if not consistent terminate program and throw a exception
1252
        if (!node.getNodeType().equals("COMMENT")
1253
                || !string.equals(node.getNodeData())) {
1254
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1255
            MetaCatUtil.debugMessage("current node type from xml is COMMENT",
1256
                    40);
1257
            MetaCatUtil.debugMessage("node type from stack: "
1258
                    + node.getNodeType(), 40);
1259
            MetaCatUtil.debugMessage(
1260
                    "current node data from xml is: " + string, 40);
1261
            MetaCatUtil.debugMessage("node data from stack: "
1262
                    + node.getNodeData(), 40);
1263
            MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(),
1264
                    40);
1265
            throw new SAXException(error);
1266
        }//if
1267
    }
1268
1269
    /**
1270
     * SAX Handler called once for each processing instruction found: node that
1271
     * PI may occur before or after the root element.
1272
     */
1273
    public void processingInstruction(String target, String data)
1274
            throws SAXException
1275
    {
1276
        MetaCatUtil.debugMessage("PI", 50);
1277
        if (!handleInlineData) {
1278
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1279
            endNodeId = currentNode.writeChildNodeToDB("PI", target, data,
1280
                    docid);
1281
        } else {
1282
            StringBuffer inlinePI = new StringBuffer();
1283
            inlinePI.append("<?");
1284
            inlinePI.append(target);
1285
            inlinePI.append(" ");
1286
            inlinePI.append(data);
1287
            inlinePI.append("?>");
1288
            MetaCatUtil.debugMessage("inline data pi is: "
1289
                    + inlinePI.toString(), 50);
1290
            writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1291
        }
1292
    }
1293
1294
    /** SAX Handler that is called at the start of Namespace */
1295
    public void startPrefixMapping(String prefix, String uri)
1296
            throws SAXException
1297
    {
1298
        MetaCatUtil.debugMessage("NAMESPACE", 50);
1299
        if (!handleInlineData) {
1300
            namespaces.put(prefix, uri);
1301
        } else {
1302
            inlineDataNameSpace.put(prefix, uri);
1303
        }
1304
    }
1305
1306
    /**
1307
     * SAX Handler that is called for each XML text node that is Ignorable
1308
     * white space
1309
     */
1310
    public void ignorableWhitespace(char[] cbuf, int start, int len)
1311
            throws SAXException
1312
    {
1313
        // When validation is turned "on", white spaces are reported here
1314
        // When validation is turned "off" white spaces are not reported here,
1315
        // but through characters() callback
1316
        MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
1317
        if (!handleInlineData) {
1318
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1319
            String data = null;
1320
            int leftover = len;
1321
            int offset = start;
1322
            boolean moredata = true;
1323
1324
            // This loop deals with the case where there are more characters
1325
            // than can fit in a single database text field (limit is
1326
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
1327
            // write a series of nodes that are MAXDATACHARS long, and then the
1328
            // final node contains the remainder
1329
            while (moredata) {
1330
                if (leftover > MAXDATACHARS) {
1331
                    data = new String(cbuf, offset, MAXDATACHARS);
1332
                    leftover -= MAXDATACHARS;
1333
                    offset += MAXDATACHARS;
1334
                } else {
1335
                    data = new String(cbuf, offset, leftover);
1336
                    moredata = false;
1337
                }
1338
1339
                //compare whitespace if need
1340
                if (startCriticalSubTree) {
1341
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1342
                            data, PERMISSIONERROR);
1343
                }//if
1344
1345
                //compare whitespace in access top module
1346
                if (processTopLeverAccess && needCheckingAccessModule) {
1347
                    compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1348
                            data, UPDATEACCESSERROR);
1349
                }
1350
                // Write the content of the node to the database
1351
                if (needCheckingAccessModule
1352
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1353
                    // stored the pull out nodes into storedNode stack
1354
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1355
                            null, null, MetaCatUtil.normalize(data));
1356
                    storedAccessNodeStack.push(nodeElement);
1357
1358
                }
1359
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1360
                        docid);
1361
            }
1362
        } else {
1363
            //This is inline data write to file directly
1364
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1365
                    start, len));
1366
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1367
        }
1368
1369
    }
1370
1371
    /* Compare whitespace from xml and db */
1372
    private void compareWhiteSpace(Stack nodeStack, String string, String error)
1373
            throws SAXException
1374
    {
1375
        NodeRecord node = null;
1376
        try {
1377
            node = (NodeRecord) nodeStack.pop();
1378
        } catch (EmptyStackException ee) {
1379
            MetaCatUtil.debugMessage("the stack is empty for whitespace data",
1380
                    32);
1381
            throw new SAXException(error);
1382
        }
1383
        if (!node.getNodeType().equals("TEXT")
1384
                || !string.equals(node.getNodeData())) {
1385
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1386
            MetaCatUtil.debugMessage(
1387
                    "current node type from xml is WHITESPACE TEXT", 40);
1388
            MetaCatUtil.debugMessage("node type from stack: "
1389
                    + node.getNodeType(), 40);
1390
            MetaCatUtil.debugMessage(
1391
                    "current node data from xml is: " + string, 40);
1392
            MetaCatUtil.debugMessage("node data from stack: "
1393
                    + node.getNodeData(), 40);
1394
            MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(),
1395
                    40);
1396
            throw new SAXException(error);
1397
        }//if
1398
    }
1399
1400
    /** SAX Handler that receives notification of end of the document */
1401
    public void endDocument() throws SAXException
1402
    {
1403
        MetaCatUtil.debugMessage("end Document", 50);
1404
        // There are some unchangable subtree didn't be compare
1405
        // This maybe cause user change the subtree id
1406
        if (!unChangableSubTreeHash.isEmpty()) {
1407
            MetaCatUtil.debugMessage("The unChangealbe subtree is not empty",
1408
                    40);
1409
            throw new SAXException(PERMISSIONERROR);
1410
        }
1411
1412
        // write access rule to db
1413
        writeAccessRuleToDB();
1414
1415
        //delete relation table
1416
        deleteRelations();
1417
        //write relations
1418
        for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1419
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1420
            writeOnlineDataFileIdIntoRelationTable(id);
1421
        }
1422
1423
        // Starting new thread for writing XML Index.
1424
        // It calls the run method of the thread.
1425
        boolean useXMLIndex = (new Boolean(MetaCatUtil.getOption("usexmlindex")))
1426
                .booleanValue();
1427
        if (useXMLIndex) {
1428
            try {
1429
                xmlIndex.start();
1430
            } catch (NullPointerException e) {
1431
                xmlIndex = null;
1432
                throw new SAXException(
1433
                        "Problem with starting thread for writing XML Index. "
1434
                                + e.getMessage());
1435
            }
1436
        }
1437
    }
1438
1439
    /* The method to write all access rule into db */
1440
    private void writeAccessRuleToDB() throws SAXException
1441
    {
1442
        //Delete old permssion
1443
        deletePermissionsInAccessTable(docid);
1444
        //write top leve access rule
1445
        writeTopLevelAccessRuleToDB();
1446
        //write additional access rule
1447
        //writeAddtionalAccessRuleToDB();
1448
    }//writeAccessRuleToDB
1449
1450
    /* The method to write top level access rule into db. */
1451
    private void writeTopLevelAccessRuleToDB() throws SAXException
1452
    {
1453
1454
        // for top document level
1455
        Object accessSection = topLevelAccessControlMap.get(docid);
1456
        boolean top = true;
1457
        String subSectionId = null;
1458
        if (accessSection != null) {
1459
            AccessSection accessSectionObj = (AccessSection) accessSection;
1460
1461
            // if accessSection is not null and is not reference
1462
            if (accessSectionObj.getReferences() == null) {
1463
                // write the top level access module into xml_accesssubtree to
1464
                // store info
1465
                // and then when update to check if the user can update it or
1466
                // not
1467
                deleteAccessSubTreeRecord(docid);
1468
                writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1469
1470
                //write access section into xml_access table
1471
                writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1472
                // write online data file into xml_access too.
1473
                for (int i= 0; i <onlineDataFileIdInTopAccessVector.size(); i++)
1474
                {
1475
                  String id = (String)
1476
                               onlineDataFileIdInTopAccessVector.elementAt(i);
1477
                  writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1478
                }
1479
1480
1481
            } else {
1482
1483
                // this is a reference and go trough the vector which contains
1484
                // all
1485
                // access object
1486
                String referenceId = accessSectionObj.getReferences();
1487
                boolean findAccessObject = false;
1488
                MetaCatUtil.debugMessage("referered id for top access: "
1489
                        + referenceId, 35);
1490
                for (int i = 0; i < accessObjectList.size(); i++) {
1491
                    AccessSection accessObj = (AccessSection) accessObjectList
1492
                            .elementAt(i);
1493
                    String accessObjId = accessObj.getSubTreeId();
1494
                    if (referenceId != null && accessObj != null
1495
                            && referenceId.equals(accessObjId)) {
1496
                        // make sure the user didn't change any thing in this
1497
                        // access moduel
1498
                        // too if user doesn't have all permission
1499
                        if (needCheckingAccessModule) {
1500
1501
                            Stack newStack = accessObj.getStoredTmpNodeStack();
1502
                            //revise order
1503
                            newStack = MetaCatUtil.reviseStack(newStack);
1504
                            // go throught the vector of
1505
                            // unChangableAccessSubtreevector
1506
                            // and find the one whose id is as same as
1507
                            // referenceid
1508
                            AccessSection oldAccessObj = getAccessSectionFromUnchangableAccessVector(referenceId);
1509
                            //if oldAccessObj is null something is wrong
1510
                            if (oldAccessObj == null) {
1511
                                throw new SAXException(UPDATEACCESSERROR);
1512
                            }//if
1513
                            else {
1514
                                // Get the node stack from old access obj
1515
                                Stack oldStack = oldAccessObj
1516
                                        .getSubTreeNodeStack();
1517
                                comparingNodeStacks(newStack, oldStack);
1518
                            }//else
1519
                        }//if
1520
                        // write accessobject into db
1521
                        writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1522
                        // write online data file into xml_access too.
1523
                        for (int j= 0; j <onlineDataFileIdInTopAccessVector.size(); j++)
1524
                        {
1525
                          String id = (String)
1526
                              onlineDataFileIdInTopAccessVector.elementAt(j);
1527
                           writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1528
                        }
1529
1530
                        //write the reference access into xml_accesssubtree
1531
                        // too
1532
                        // write the top level access module into
1533
                        // xml_accesssubtree to store info
1534
                        // and then when update to check if the user can update
1535
                        // it or not
1536
                        deleteAccessSubTreeRecord(docid);
1537
                        writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1538
                        writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1539
                        findAccessObject = true;
1540
                        break;
1541
                    }
1542
                }//for
1543
                // if we couldn't find an access subtree id for this reference
1544
                // id
1545
                if (!findAccessObject) { throw new SAXException(
1546
                        "The referenceid: " + referenceId
1547
                                + " is not access subtree"); }//if
1548
            }//else
1549
1550
        }//if
1551
        else {
1552
            // couldn't find a access section object
1553
            MetaCatUtil.debugMessage(
1554
                    "couldn't find access control for document: " + docid, 35);
1555
        }
1556
1557
    }//writeTopLevelAccessRuletoDB
1558
1559
    /* Given a subtree id and find the responding access section */
1560
    private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1561
    {
1562
        AccessSection result = null;
1563
        // Makse sure the id
1564
        if (id == null || id.equals("")) { return result; }
1565
        // go throught vector and find the list
1566
        for (int i = 0; i < unChangableAccessSubTreeVector.size(); i++) {
1567
            AccessSection accessObj = (AccessSection) unChangableAccessSubTreeVector
1568
                    .elementAt(i);
1569
            if (accessObj.getSubTreeId() != null
1570
                    && (accessObj.getSubTreeId()).equals(id)) {
1571
                result = accessObj;
1572
            }//if
1573
        }//for
1574
        return result;
1575
    }//getAccessSectionFromUnchangableAccessVector
1576
1577
    /* Compare two node stacks to see if they are same */
1578
    private void comparingNodeStacks(Stack stack1, Stack stack2)
1579
            throws SAXException
1580
    {
1581
        // make sure stack1 and stack2 are not empty
1582
        if (stack1.isEmpty() || stack2.isEmpty()) {
1583
            MetaCatUtil.debugMessage("Because stack is empty!", 35);
1584
            throw new SAXException(UPDATEACCESSERROR);
1585
        }
1586
        // go throw two stacks and compare every element
1587
        while (!stack1.isEmpty()) {
1588
            // Pop an element from stack1
1589
            NodeRecord record1 = (NodeRecord) stack1.pop();
1590
            // Pop an element from stack2(stack 2 maybe empty)
1591
            NodeRecord record2 = null;
1592
            try {
1593
                record2 = (NodeRecord) stack2.pop();
1594
            } catch (EmptyStackException ee) {
1595
                MetaCatUtil.debugMessage(
1596
                        "Node stack2 is empty but stack1 isn't!", 35);
1597
                throw new SAXException(UPDATEACCESSERROR);
1598
            }
1599
            // if two records are not same throw a exception
1600
            if (!record1.contentEquals(record2)) {
1601
                MetaCatUtil
1602
                        .debugMessage(
1603
                                "Two records from new and old stack are not "
1604
                                        + "same!", 30);
1605
                throw new SAXException(UPDATEACCESSERROR);
1606
            }//if
1607
        }//while
1608
1609
        // now stack1 is empty and we should make sure stack2 is empty too
1610
        if (!stack2.isEmpty()) {
1611
            MetaCatUtil.debugMessage(
1612
                    "stack2 still have some elements while stack "
1613
                            + "is empty! ", 30);
1614
            throw new SAXException(UPDATEACCESSERROR);
1615
        }//if
1616
    }//comparingNodeStacks
1617
1618
    /* The method to write addtional access rule into db. */
1619
    private void writeAddtionalAccessRuleToDB() throws SAXException
1620
    {
1621
1622
        PreparedStatement pstmt = null;
1623
        boolean topLevel = false;
1624
        // go through the vector which contains the additional access control
1625
        //hashtable. Each hashtable has info for one additonalmetadata
1626
        // container
1627
        for (int j = 0; j < additionalAccessMapList.size(); j++) {
1628
1629
            Hashtable accessControlMap = (Hashtable) additionalAccessMapList
1630
                    .elementAt(j);
1631
            // additional access rule
1632
            Enumeration en = accessControlMap.keys();
1633
1634
            while (en.hasMoreElements()) {
1635
                try {
1636
                    // Get subsection id
1637
                    String subSectionId = (String) en.nextElement();
1638
                    MetaCatUtil.debugMessage(
1639
                            "sub section id in additional access mapping"
1640
                                    + "(go through): " + subSectionId, 35);
1641
1642
                    if (subSectionId == null) {
1643
                    // if id is null, terminate the program
1644
                    throw new SAXException("subtree id is null"); }
1645
                    // Get AccessSection Object
1646
                    Object accessSectionObj = accessControlMap
1647
                            .get(subSectionId);
1648
                    if (accessSectionObj == null) {
1649
                        // if accesssection is null, terminate the program
1650
                        throw new SAXException("access subtree is null");
1651
                    } else {
1652
                        AccessSection accessControlObj = (AccessSection) accessSectionObj;
1653
                        // if the access section is not references, write it to
1654
                        // db
1655
                        if (accessControlObj.getReferences() == null) {
1656
                            writeGivenAccessRuleIntoDB(accessControlObj,
1657
                                    topLevel, subSectionId);
1658
                        } else {
1659
                            // this is a reference and go trough the vector
1660
                            // which contains all
1661
                            // access object
1662
                            String referenceId = accessControlObj
1663
                                    .getReferences();
1664
1665
                            boolean findAccessObject = false;
1666
                            MetaCatUtil.debugMessage(
1667
                                    "referered id for additional access "
1668
                                            + "mapping(go through): "
1669
                                            + referenceId, 35);
1670
                            for (int i = 0; i < accessObjectList.size(); i++) {
1671
                                AccessSection accessObj = (AccessSection) accessObjectList
1672
                                        .elementAt(i);
1673
                                String accessObjId = accessObj.getSubTreeId();
1674
                                MetaCatUtil.debugMessage(
1675
                                        "access obj id in the list(go through): "
1676
                                                + accessObjId, 35);
1677
                                if (referenceId != null && accessObj != null
1678
                                        && referenceId.equals(accessObjId)) {
1679
                                    writeGivenAccessRuleIntoDB(accessObj,
1680
                                            topLevel, subSectionId);
1681
                                    findAccessObject = true;
1682
                                }//if
1683
                            }//for
1684
                            // if we couldn't find an access subtree id for
1685
                            // this reference id
1686
                            if (!findAccessObject) { throw new SAXException(
1687
                                    "The referenceid: " + referenceId
1688
                                            + " is not access subtree"); }//if
1689
                        }//else
1690
                    }//else
1691
                }//try
1692
                catch (Exception e) {
1693
1694
                    MetaCatUtil.debugMessage(
1695
                            "error in EmlSAXHandler.writeAddtionalAccess"
1696
                                    + ": " + e.getMessage(), 30);
1697
                    throw new SAXException(e.getMessage());
1698
                }
1699
            }//while
1700
        }//for
1701
    }//writeAccessRuletoDB
1702
1703
    /* Write a gaven access rule into db */
1704
    private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1705
            boolean topLevel, String subSectionId) throws SAXException
1706
    {
1707
        if (accessSection == null) { throw new SAXException(
1708
                "The access object is null"); }
1709
1710
        String permOrder = accessSection.getPermissionOrder();
1711
        String sql = null;
1712
        PreparedStatement pstmt = null;
1713
        if (topLevel) {
1714
            sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1715
                    + "perm_type, perm_order, accessfileid) VALUES "
1716
                    + " (?, ?, ?, ?, ?, ?)";
1717
        } else {
1718
            sql = "INSERT INTO xml_access (docid,principal_name, "
1719
                    + "permission, perm_type, perm_order, accessfileid, subtreeid, "
1720
                    + " startnodeid, endnodeid) VALUES"
1721
                    + " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1722
        }
1723
        try {
1724
1725
            pstmt = connection.prepareStatement(sql);
1726
            // Increase DBConnection usage count
1727
            connection.increaseUsageCount(1);
1728
            // Bind the values to the query
1729
            pstmt.setString(1, docid);
1730
            MetaCatUtil.debugMessage("Docid in accesstable: " + docid, 35);
1731
            pstmt.setString(6, docid);
1732
            MetaCatUtil.debugMessage("Accessfileid in accesstable: " + docid,
1733
                    35);
1734
            pstmt.setString(5, permOrder);
1735
            MetaCatUtil.debugMessage("PermOder in accesstable: " + permOrder,
1736
                    35);
1737
            // if it is not top level, set subsection id
1738
            if (!topLevel) {
1739
                long startNodeId = 0;
1740
                long endNodeId = 0;
1741
                // for subtree should specify the
1742
                if (subSectionId == null) { throw new SAXException(
1743
                        "The subsection is null"); }
1744
                // go through the substree list vector and found the start node
1745
                // id
1746
                // and stop node id for this subtree id
1747
                for (int i = 0; i < subTreeList.size(); i++) {
1748
                    SubTree tree = (SubTree) subTreeList.elementAt(i);
1749
                    String subTreeId = tree.getSubTreeId();
1750
                    if (subSectionId.equals(subTreeId)) {
1751
                        startNodeId = tree.getStartNodeId();
1752
                        endNodeId = tree.getEndNodeId();
1753
                    }//if
1754
                }//for
1755
                if (startNodeId == 0 || endNodeId == 0) { throw new SAXException(
1756
                        "Could find the subtree" + "for this id: "
1757
                                + subSectionId); }
1758
                pstmt.setString(7, subSectionId);
1759
                MetaCatUtil.debugMessage("SubSectionId in accesstable: "
1760
                        + subSectionId, 35);
1761
                pstmt.setLong(8, startNodeId);
1762
                MetaCatUtil
1763
                        .debugMessage("Start node id is: " + startNodeId, 35);
1764
                pstmt.setLong(9, endNodeId);
1765
                MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1766
1767
            }
1768
1769
            Vector accessRules = accessSection.getAccessRules();
1770
            // go through every rule
1771
            for (int i = 0; i < accessRules.size(); i++) {
1772
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1773
                String permType = rule.getPermissionType();
1774
                int permission = rule.getPermission();
1775
                pstmt.setInt(3, permission);
1776
                MetaCatUtil.debugMessage("permission in accesstable: "
1777
                        + permission, 35);
1778
                pstmt.setString(4, permType);
1779
                MetaCatUtil.debugMessage(
1780
                        "Permtype in accesstable: " + permType, 35);
1781
                // go through every principle in rule
1782
                Vector nameVector = rule.getPrincipal();
1783
                for (int j = 0; j < nameVector.size(); j++) {
1784
                    String prName = (String) nameVector.elementAt(j);
1785
                    pstmt.setString(2, prName);
1786
                    MetaCatUtil.debugMessage("Principal in accesstable: "
1787
                            + prName, 35);
1788
                    pstmt.execute();
1789
                }//for
1790
            }//for
1791
            pstmt.close();
1792
        }//try
1793
        catch (SQLException e) {
1794
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1795
                    + e.getMessage());
1796
        }//catch
1797
        finally {
1798
            try {
1799
                pstmt.close();
1800
            } catch (SQLException ee) {
1801
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1802
                        + ee.getMessage());
1803
            }
1804
        }//finally
1805
1806
    }//writeGivenAccessRuleIntoDB
1807
1808
    /* Write a gaven access rule into db */
1809
    private void writeAccessRuleForRalatedDataFileIntoDB(
1810
            AccessSection accessSection, String dataId) throws SAXException
1811
    {
1812
        if (accessSection == null) { throw new SAXException(
1813
                "The access object is null"); }
1814
        // get rid of rev from dataId
1815
        //dataId = MetaCatUtil.getDocIdFromString(dataId);
1816
        String permOrder = accessSection.getPermissionOrder();
1817
        String sql = null;
1818
        PreparedStatement pstmt = null;
1819
        sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1820
                + "perm_type, perm_order, accessfileid) VALUES "
1821
                + " (?, ?, ?, ?, ?, ?)";
1822
1823
        try {
1824
1825
            pstmt = connection.prepareStatement(sql);
1826
            // Increase DBConnection usage count
1827
            connection.increaseUsageCount(1);
1828
            // Bind the values to the query
1829
            pstmt.setString(1, dataId);
1830
            MetaCatUtil.debugMessage("Docid in accesstable: " + docid, 35);
1831
            pstmt.setString(6, docid);
1832
            MetaCatUtil.debugMessage("Accessfileid in accesstable: " + docid,
1833
                    35);
1834
            pstmt.setString(5, permOrder);
1835
            MetaCatUtil.debugMessage("PermOder in accesstable: " + permOrder,
1836
                    35);
1837
            // if it is not top level, set subsection id
1838
1839
            Vector accessRules = accessSection.getAccessRules();
1840
            // go through every rule
1841
            for (int i = 0; i < accessRules.size(); i++) {
1842
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1843
                String permType = rule.getPermissionType();
1844
                int permission = rule.getPermission();
1845
                pstmt.setInt(3, permission);
1846
                MetaCatUtil.debugMessage("permission in accesstable: "
1847
                        + permission, 35);
1848
                pstmt.setString(4, permType);
1849
                MetaCatUtil.debugMessage(
1850
                        "Permtype in accesstable: " + permType, 35);
1851
                // go through every principle in rule
1852
                Vector nameVector = rule.getPrincipal();
1853
                for (int j = 0; j < nameVector.size(); j++) {
1854
                    String prName = (String) nameVector.elementAt(j);
1855
                    pstmt.setString(2, prName);
1856
                    MetaCatUtil.debugMessage("Principal in accesstable: "
1857
                            + prName, 35);
1858
                    pstmt.execute();
1859
                }//for
1860
            }//for
1861
            pstmt.close();
1862
        }//try
1863
        catch (SQLException e) {
1864
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1865
                    + e.getMessage());
1866
        }//catch
1867
        finally {
1868
            try {
1869
                pstmt.close();
1870
            } catch (SQLException ee) {
1871
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1872
                        + ee.getMessage());
1873
            }
1874
        }//finally
1875
1876
    }//writeAccessRuleForRalatedDataFileIntoDB
1877
1878
    /* Delete from db all permission for resources related to @aclid if any. */
1879
    private void deletePermissionsInAccessTable(String aclid)
1880
            throws SAXException
1881
    {
1882
        Statement stmt = null;
1883
        try {
1884
            // delete all acl records for resources related to @aclid if any
1885
            stmt = connection.createStatement();
1886
            // Increase DBConnection usage count
1887
            connection.increaseUsageCount(1);
1888
            stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
1889
                    + aclid + "'");
1890
1891
        } catch (SQLException e) {
1892
            throw new SAXException(e.getMessage());
1893
        } finally {
1894
            try {
1895
                stmt.close();
1896
            } catch (SQLException ee) {
1897
                throw new SAXException(ee.getMessage());
1898
            }
1899
        }
1900
    }//deletePermissionsInAccessTable
1901
1902
    /*
1903
     * In order to make sure only usr has "all" permission can update access
1904
     * subtree in eml document we need to keep access subtree info in
1905
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1906
     */
1907
    private void writeAccessSubTreeIntoDB(AccessSection accessSection,
1908
            String level) throws SAXException
1909
    {
1910
        if (accessSection == null) { throw new SAXException(
1911
                "The access object is null"); }
1912
1913
        String sql = null;
1914
        PreparedStatement pstmt = null;
1915
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1916
                + "subtreeid, startnodeid, endnodeid) VALUES "
1917
                + " (?, ?, ?, ?, ?, ?)";
1918
        try {
1919
1920
            pstmt = connection.prepareStatement(sql);
1921
            // Increase DBConnection usage count
1922
            connection.increaseUsageCount(1);
1923
            long startNodeId = accessSection.getStartNodeId();
1924
            long endNodeId = accessSection.getEndNodeId();
1925
            String sectionId = accessSection.getSubTreeId();
1926
            // Bind the values to the query
1927
            pstmt.setString(1, docid);
1928
            MetaCatUtil.debugMessage("Docid in access-subtreetable: " + docid,
1929
                    35);
1930
            pstmt.setString(2, revision);
1931
            MetaCatUtil.debugMessage("rev in accesssubtreetable: " + revision,
1932
                    35);
1933
            pstmt.setString(3, level);
1934
            MetaCatUtil.debugMessage("contorl level in access-subtree table: "
1935
                    + level, 35);
1936
            pstmt.setString(4, sectionId);
1937
            MetaCatUtil.debugMessage("Subtree id in access-subtree table: "
1938
                    + sectionId, 35);
1939
            pstmt.setLong(5, startNodeId);
1940
            MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
1941
            pstmt.setLong(6, endNodeId);
1942
            MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1943
            pstmt.execute();
1944
            pstmt.close();
1945
        }//try
1946
        catch (SQLException e) {
1947
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1948
                    + e.getMessage());
1949
        }//catch
1950
        finally {
1951
            try {
1952
                pstmt.close();
1953
            } catch (SQLException ee) {
1954
                throw new SAXException(
1955
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1956
                                + ee.getMessage());
1957
            }
1958
        }//finally
1959
1960
    }//writeAccessSubtreeIntoDB
1961
1962
    /* Delete every access subtree record from xml_accesssubtree. */
1963
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
1964
    {
1965
        Statement stmt = null;
1966
        try {
1967
            // delete all acl records for resources related to @aclid if any
1968
            stmt = connection.createStatement();
1969
            // Increase DBConnection usage count
1970
            connection.increaseUsageCount(1);
1971
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
1972
                    + docId + "'");
1973
1974
        } catch (SQLException e) {
1975
            throw new SAXException(e.getMessage());
1976
        } finally {
1977
            try {
1978
                stmt.close();
1979
            } catch (SQLException ee) {
1980
                throw new SAXException(ee.getMessage());
1981
            }
1982
        }
1983
    }//deleteAccessSubTreeRecord
1984
1985
    // open a file writer for writing inline data to file
1986
    private FileWriter createInlineDataFileWriter(String fileName)
1987
            throws SAXException
1988
    {
1989
        FileWriter writer = null;
1990
        String path = MetaCatUtil.getOption("inlinedatafilepath");
1991
        /*
1992
         * File inlineDataDirectory = new File(path);
1993
         */
1994
        String newFile = path + "/" + fileName;
1995
        MetaCatUtil.debugMessage("inline file name: " + newFile, 30);
1996
        try {
1997
            // true means append
1998
            writer = new FileWriter(newFile, true);
1999
        } catch (IOException ioe) {
2000
            throw new SAXException(ioe.getMessage());
2001
        }
2002
        return writer;
2003
    }
2004
2005
    // write inline data into file system and return file name(without path)
2006
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2007
            throws SAXException
2008
    {
2009
        try {
2010
            writer.write(data.toString());
2011
            writer.flush();
2012
        } catch (Exception e) {
2013
            throw new SAXException(e.getMessage());
2014
        }
2015
    }
2016
2017
    /*
2018
     * In eml2, the inline data wouldn't store in db, it store in file system
2019
     * The db stores file name(without path). We got the old file name from db
2020
     * and compare to the new in line data file
2021
     */
2022
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2023
            throws McdbException
2024
    {
2025
        // this method need to be testing
2026
        boolean same = true;
2027
        String data = null;
2028
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2029
        // the new file name will look like path/docid.rev.2
2030
        File inlineDataDirectory = new File(path);
2031
        File oldDataFile = new File(inlineDataDirectory, oldFileName);
2032
        File newDataFile = new File(inlineDataDirectory, newFileName);
2033
        try {
2034
            FileReader oldFileReader = new FileReader(oldDataFile);
2035
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2036
            FileReader newFileReader = new FileReader(newDataFile);
2037
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2038
            // read first line of data
2039
            String oldString = oldStringReader.readLine();
2040
            String newString = newStringReader.readLine();
2041
2042
            // at the end oldstring will be null
2043
            while (oldString != null) {
2044
                oldString = oldStringReader.readLine();
2045
                newString = newStringReader.readLine();
2046
                if (!oldString.equals(newString)) {
2047
                    same = false;
2048
                    break;
2049
                }
2050
            }
2051
2052
            // if oldString is null but newString is not null, they are same
2053
            if (same) {
2054
                if (newString != null) {
2055
                    same = false;
2056
                }
2057
            }
2058
2059
        } catch (Exception e) {
2060
            throw new McdbException(e.getMessage());
2061
        }
2062
        MetaCatUtil.debugMessage("the inline data retrieve from file: " + data,
2063
                50);
2064
        return same;
2065
    }
2066
2067
    // if xml file failed to upload, we need to call this method to delete
2068
    // the inline data already in file system
2069
    public void deleteInlineFiles()
2070
    {
2071
        if (!inlineFileIDList.isEmpty()) {
2072
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2073
                String fileName = (String) inlineFileIDList.elementAt(i);
2074
                deleteInlineDataFile(fileName);
2075
            }
2076
        }
2077
    }
2078
2079
    /* delete the inline data file */
2080
    private void deleteInlineDataFile(String fileName)
2081
    {
2082
2083
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2084
        File inlineDataDirectory = new File(path);
2085
        File newFile = new File(inlineDataDirectory, fileName);
2086
        newFile.delete();
2087
2088
    }
2089
2090
    /*
2091
     * In eml2, the inline data wouldn't store in db, it store in file system
2092
     * The db stores file name(without path).
2093
     */
2094
    public static Reader readInlineDataFromFileSystem(String fileName)
2095
            throws McdbException
2096
    {
2097
        //BufferedReader stringReader = null;
2098
        FileReader fileReader = null;
2099
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2100
        // the new file name will look like path/docid.rev.2
2101
        File inlineDataDirectory = new File(path);
2102
        File dataFile = new File(inlineDataDirectory, fileName);
2103
        try {
2104
            fileReader = new FileReader(dataFile);
2105
            //stringReader = new BufferedReader(fileReader);
2106
        } catch (Exception e) {
2107
            throw new McdbException(e.getMessage());
2108
        }
2109
        // return stringReader;
2110
        return fileReader;
2111
    }
2112
2113
    /* Delete relations */
2114
    private void deleteRelations() throws SAXException
2115
    {
2116
        PreparedStatement pStmt = null;
2117
        String sql = "DELETE FROM xml_relation where docid =?";
2118
        try {
2119
            pStmt = connection.prepareStatement(sql);
2120
            //bind variable
2121
            pStmt.setString(1, docid);
2122
            //execute query
2123
            pStmt.execute();
2124
            pStmt.close();
2125
        }//try
2126
        catch (SQLException e) {
2127
            throw new SAXException("EMLSAXHandler.deleteRelations(): "
2128
                    + e.getMessage());
2129
        }//catch
2130
        finally {
2131
            try {
2132
                pStmt.close();
2133
            }//try
2134
            catch (SQLException ee) {
2135
                throw new SAXException("EMLSAXHandler.deleteRelations: "
2136
                        + ee.getMessage());
2137
            }//catch
2138
        }//finally
2139
    }
2140
2141
    /* Write an online data file id into xml_relation table. The dataId shouldnot
2142
     * have the revision
2143
     */
2144
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2145
            throws SAXException
2146
    {
2147
        PreparedStatement pStmt = null;
2148
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2149
                + "relationship, object) values (?, ?, ?, ?, ?)";
2150
        try {
2151
            pStmt = connection.prepareStatement(sql);
2152
            //bind variable
2153
            pStmt.setString(1, docid);
2154
            pStmt.setString(2, DocumentImpl.EML2_1_0NAMESPACE);
2155
            pStmt.setString(3, docid);
2156
            pStmt.setString(4, RELATION);
2157
            pStmt.setString(5, dataId);
2158
            //execute query
2159
            pStmt.execute();
2160
            pStmt.close();
2161
        }//try
2162
        catch (SQLException e) {
2163
            throw new SAXException(
2164
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2165
                            + e.getMessage());
2166
        }//catch
2167
        finally {
2168
            try {
2169
                pStmt.close();
2170
            }//try
2171
            catch (SQLException ee) {
2172
                throw new SAXException(
2173
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2174
                                + ee.getMessage());
2175
            }//catch
2176
        }//finally
2177
2178
    }//writeOnlineDataFileIdIntoRelationTable
2179
2180
    /*
2181
     * This method will handle data file in online url. If the data file is in
2182
     * ecogrid protocol, then the datafile identifier(without rev)should be put
2183
     * into onlineDataFileRelationVector. The  docid in this vector will be
2184
     * insert into xml_relation table in endDocument().
2185
     * If the data file doesn't exsit in xml_documents or
2186
     * xml_revision table, or the user has all permission to the data file if
2187
     * the docid already existed, the data file id (without rev)will be put into
2188
     * onlineDataFileTopAccessVector. The top access rules specified in this eml
2189
     * document will apply to the data file.
2190
     * NEED to do:
2191
     * We should also need to implement http and ftp. Those
2192
     * external files should be download and assign a data file id to it.
2193
     */
2194
    private void handleOnlineUrlDataFile(String url) throws SAXException
2195
    {
2196
      MetaCatUtil.debugMessage("The url is "+ url, 10);
2197
      // if the url is not a ecogrid protocol, null will be getten
2198
      String accessionNumber =
2199
                 MetaCatUtil.getAccessionNumberFromEcogridIdentifier(url);
2200
      if (accessionNumber != null)
2201
      {
2202
        // handle ecogrid protocol
2203
        // get rid of revision number to get the docid.
2204
        String docid = MetaCatUtil.getDocIdFromAccessionNumber(accessionNumber);
2205
        onlineDataFileIdInRelationVector.add(docid);
2206
        try
2207
        {
2208
2209
          if (!AccessionNumber.accNumberUsed(docid))
2210
          {
2211
            onlineDataFileIdInTopAccessVector.add(docid);
2212
          }
2213
          PermissionController controller = new
2214
              PermissionController(accessionNumber);
2215
          if (controller.hasPermission(
2216
              user, groups, AccessControlInterface.ALLSTRING))
2217
          {
2218
            onlineDataFileIdInTopAccessVector.add(docid);
2219
          }
2220
        }//try
2221
        catch(Exception e)
2222
        {
2223
          MetaCatUtil.debugMessage("Eorr in " +
2224
                                "Eml210SAXHanlder.handleOnlineUrlDataFile is " +
2225
                                 e.getMessage(), 30);
2226
          throw new SAXException(e.getMessage());
2227
        }
2228
      }
2229
    }
2230
2231
}