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