Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author: tao $'
11
 *     '$Date: 2005-09-30 12:48:59 -0700 (Fri, 30 Sep 2005) $'
12
 * '$Revision: 2608 $'
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
        list = null;
217
        // changed after old code removal
218
        //controller.hasUnaccessableSubTree(user, groups,
219
        //        AccessControlInterface.WRITESTRING);
220
        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
                Stack nodeStack = accessObj.getSubTreeNodeStack();
284
                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
                    if (!super.getIsRevisionDoc())
453
                    {
454
                       currentDocument = new DocumentImpl(connection, rootNode
455
                            .getNodeID(), docname, doctype, docid, revision,
456
                            action, user, this.pub, catalogid, this.serverCode);
457
                    }
458
                    else
459
                    {
460
                        currentDocument = new DeletedDocumentImpl(connection, rootNode
461
                                .getNodeID(), docname, doctype, docid, revision,
462
                                action, user, this.pub, catalogid, this.serverCode);
463
                    }
464

    
465
                } catch (Exception ane) {
466
                    throw (new SAXException(
467
                            "Error in EMLSaxHandler.startElement " + action,
468
                            ane));
469
                }
470
            }
471

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

    
491
            // Add all of the attributes
492
            for (int i = 0; i < atts.getLength(); i++) {
493
                String attributeName = atts.getQName(i);
494
                String attributeValue = atts.getValue(i);
495
                endNodeId = currentNode.setAttribute(attributeName,
496
                        attributeValue, docid);
497

    
498
                // To handle name space and schema location if the attribute
499
                // name is
500
                // xsi:schemaLocation. If the name space is in not in catalog
501
                // table
502
                // it will be regeistered.
503
                if (attributeName != null
504
                        && attributeName
505
                                .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
506
                    SchemaLocationResolver resolver = new SchemaLocationResolver(
507
                            attributeValue);
508
                    resolver.resolveNameSpace();
509

    
510
                } else if (attributeName != null && attributeName.equals(ID)) {
511

    
512
                    //check unchangedable subtree hash if contains this
513
                    // subtree id
514
                    if (unChangableSubTreeHash.containsKey(attributeValue)) {
515
                        // this subtree couldn't be changed by the user and
516
                        // move it from hash
517
                        SubTree currentUnChangedableSubtree = (SubTree) unChangableSubTreeHash
518
                                .remove(attributeValue);
519
                        currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree
520
                                .getSubTreeNodeStack();
521
                        startCriticalSubTree = true;
522
                        firstElementForCriticalSubTree = true;
523
                    }
524

    
525
                    // handle subtree info
526
                    SubTree subTress = new SubTree();
527
                    // set sub tree id
528
                    subTress.setSubTreeId(attributeValue);
529
                    // set sub tree sstart lement name
530
                    subTress.setStartElementName(currentNode.getTagName());
531
                    // set start node number
532
                    subTress.setStartNodeId(startNodeId);
533
                    // add to stack, but it didn't get end node id yet
534
                    subTreeInfoStack.push(subTress);
535

    
536
                }
537
            }//for
538

    
539
            // handle access stuff
540
            if (localName.equals(ACCESS)) {
541
                // if it is in addtionalmetacat
542
                if (parentNode.getTagName() == ADDITIONALMETADATA) {
543
                    processAdditionalAccess = true;
544

    
545
                } else {
546
                    //make sure the access is top level
547
                    // this mean current node's parent's parent should be "eml"
548
                    DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
549
                                                                    // parent
550
                                                                    // node
551
                    //peek out grandParentNode
552
                    DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
553
                    // put parent node back
554
                    nodeStack.push(tmpNode);
555
                    String grandParentTag = grandParentNode.getTagName();
556
                    if (grandParentTag.equals(EML)) {
557
                        processTopLeverAccess = true;
558
                    } else {
559
                        // process other access embedded into resource level
560
                        // module
561
                        processOtherAccess = true;
562
                    }
563

    
564
                }
565
                // create access object
566
                accessObject = new AccessSection();
567
                // set permission order
568
                String permOrder = currentNode.getAttribute(ORDER);
569
                accessObject.setPermissionOrder(permOrder);
570
                // set access id
571
                String accessId = currentNode.getAttribute(ID);
572
                accessObject.setSubTreeId(accessId);
573
                accessObject.setStartNodeId(startNodeId);
574
                accessObject.setDocId(docid);
575

    
576
                // load top level node stack to
577
                // currentUnchangableAccessModuleNodeStack
578
                if (processTopLeverAccess && needCheckingAccessModule) {
579
                    // get the node stack for
580
                    currentUnchangableAccessModuleNodeStack = topAccessSection
581
                            .getSubTreeNodeStack();
582
                }
583

    
584
            }
585
            // Set up a access rule for allow
586
            else if (parentNode.getTagName() != null
587
                    && (parentNode.getTagName()).equals(ACCESS)
588
                    && localName.equals(ALLOW)) {
589

    
590
                accessRule = new AccessRule();
591

    
592
                //set permission type "allow"
593
                accessRule.setPermissionType(ALLOW);
594

    
595
            }
596
            // set up an access rule for den
597
            else if (parentNode.getTagName() != null
598
                    && (parentNode.getTagName()).equals(ACCESS)
599
                    && localName.equals(DENY)) {
600
                accessRule = new AccessRule();
601
                //set permission type "allow"
602
                accessRule.setPermissionType(DENY);
603
            }
604

    
605
            // Add the node to the stack, so that any text data can be
606
            // added as it is encountered
607
            nodeStack.push(currentNode);
608
            // Add the node to the vector used by thread for writing XML Index
609
            nodeIndex.addElement(currentNode);
610

    
611
            // handle critical subtree
612
            if (startCriticalSubTree && firstElementForCriticalSubTree) {
613
                //store the element name
614
                firstElementNameForCriticalSubTree = qName;
615
                firstElementForCriticalSubTree = false;
616
            }//for first element
617

    
618
            // handle critical subtree
619
            if (startCriticalSubTree) {
620
                compareElementNameSpaceAttributes(
621
                        currentUnChangedableSubtreeNodeStack, namespaces, atts,
622
                        localName, PERMISSIONERROR);
623

    
624
            }
625
            //compare top access level module
626
            if (processTopLeverAccess && needCheckingAccessModule) {
627
                compareElementNameSpaceAttributes(
628
                        currentUnchangableAccessModuleNodeStack, namespaces,
629
                        atts, localName, UPDATEACCESSERROR);
630

    
631
            }
632

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

    
649
            }
650

    
651
            // reset name space
652
            namespaces = null;
653
            namespaces = new Hashtable();
654
        }//not inline data
655
        else {
656
            // we don't buffer the inline data in characters() method
657
            // so start character don't need to hand text node.
658

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

    
696
    }
697

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

    
744
        //compare namespace
745
        Enumeration nameEn = nameSpaces.keys();
746
        while (nameEn.hasMoreElements()) {
747
            //Get namespacke node stack (element node)
748
            NodeRecord nameNode = null;
749
            try {
750
                nameNode = (NodeRecord) unchangableNodeStack.pop();
751
            } catch (EmptyStackException ee) {
752
                MetaCatUtil.debugMessage(
753
                        "Node stack is empty for namespace data", 35);
754
                throw new SAXException(error);
755
            }
756

    
757
            String prefixName = (String) nameEn.nextElement();
758
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
759
            if (!nameNode.getNodeType().equals("NAMESPACE")
760
                    || !prefixName.equals(nameNode.getNodeName())
761
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
762
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
763
                MetaCatUtil.debugMessage(
764
                        "current node type from xml is NAMESPACE", 40);
765
                MetaCatUtil.debugMessage("node type from stack: "
766
                        + nameNode.getNodeType(), 40);
767
                MetaCatUtil.debugMessage("current node name from xml is: "
768
                        + prefixName, 40);
769
                MetaCatUtil.debugMessage("node name from stack: "
770
                        + nameNode.getNodeName(), 40);
771
                MetaCatUtil.debugMessage("current node data from xml is: "
772
                        + nameSpaceUri, 40);
773
                MetaCatUtil.debugMessage("node data from stack: "
774
                        + nameNode.getNodeData(), 40);
775
                MetaCatUtil.debugMessage("node id is: " + nameNode.getNodeId(),
776
                        40);
777
                throw new SAXException(error);
778
            }
779

    
780
        }//while
781

    
782
        //compare attributes
783
        for (int i = 0; i < attributes.getLength(); i++) {
784
            NodeRecord attriNode = null;
785
            try {
786
                attriNode = (NodeRecord) unchangableNodeStack.pop();
787

    
788
            } catch (EmptyStackException ee) {
789
                MetaCatUtil.debugMessage(
790
                        "Node stack is empty for attribute data", 35);
791
                throw new SAXException(error);
792
            }
793
            String attributeName = attributes.getQName(i);
794
            String attributeValue = attributes.getValue(i);
795
            MetaCatUtil.debugMessage(
796
                    "current node type from xml is ATTRIBUTE ", 40);
797
            MetaCatUtil.debugMessage("node type from stack: "
798
                    + attriNode.getNodeType(), 40);
799
            MetaCatUtil.debugMessage("current node name from xml is: "
800
                    + attributeName, 40);
801
            MetaCatUtil.debugMessage("node name from stack: "
802
                    + attriNode.getNodeName(), 40);
803
            MetaCatUtil.debugMessage("current node data from xml is: "
804
                    + attributeValue, 40);
805
            MetaCatUtil.debugMessage("node data from stack: "
806
                    + attriNode.getNodeData(), 40);
807
            MetaCatUtil.debugMessage("node id  is: " + attriNode.getNodeId(),
808
                    40);
809

    
810
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
811
                    || !attributeName.equals(attriNode.getNodeName())
812
                    || !attributeValue.equals(attriNode.getNodeData())) {
813
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
814
                MetaCatUtil.debugMessage(
815
                        "current node type from xml is ATTRIBUTE ", 40);
816
                MetaCatUtil.debugMessage("node type from stack: "
817
                        + attriNode.getNodeType(), 40);
818
                MetaCatUtil.debugMessage("current node name from xml is: "
819
                        + attributeName, 40);
820
                MetaCatUtil.debugMessage("node name from stack: "
821
                        + attriNode.getNodeName(), 40);
822
                MetaCatUtil.debugMessage("current node data from xml is: "
823
                        + attributeValue, 40);
824
                MetaCatUtil.debugMessage("node data from stack: "
825
                        + attriNode.getNodeData(), 40);
826
                MetaCatUtil.debugMessage("node is: " + attriNode.getNodeId(),
827
                        40);
828
                throw new SAXException(error);
829
            }
830
        }//for
831

    
832
    }
833

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

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

    
913
    /** SAX Handler that is called at the end of each XML element */
914
    public void endElement(String uri, String localName, String qName)
915
            throws SAXException
916
    {
917
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
918

    
919
        if (localName.equals(INLINE) && handleInlineData) {
920
            // Get the node from the stack
921
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
922
            String currentTag = currentNode.getTagName();
923
            MetaCatUtil.debugMessage("End of inline data", 35);
924
            // close file writer
925
            try {
926
                inlineDataFileWriter.close();
927
                handleInlineData = false;
928
            } catch (IOException ioe) {
929
                throw new SAXException(ioe.getMessage());
930
            }
931

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

    
963
            }//if
964
            // write put inline data file name into text buffer (without path)
965
            textBuffer = new StringBuffer(inlineDataFileName);
966
            // write file name into db
967
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
968
                    currentNode);
969
            // reset textbuff
970
            textBuffer = null;
971
            textBuffer = new StringBuffer();
972
            return;
973
        }
974

    
975
        if (!handleInlineData) {
976
            // Get the node from the stack
977
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
978
            String currentTag = currentNode.getTagName();
979

    
980
            // If before the end element, the parser hit text nodes and store
981
            // them
982
            // into the buffer, write the buffer to data base. The reason we
983
            // put
984
            // write database here is for xerces some time split text node
985
            if (hitTextNode) {
986
                // get access value
987
                String data = null;
988
                // add principal
989
                if (currentTag.equals(PRINCIPAL) && accessRule != null) {
990
                    data = (textBuffer.toString()).trim();
991
                    accessRule.addPrincipal(data);
992

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

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

    
1070
                }
1071
            }//if
1072

    
1073
            //end crtical subtree(user doesn't have permission to write)
1074
            //When reach the first element and stack is empty
1075
            if (localName.equals(firstElementNameForCriticalSubTree)
1076
                    && currentUnChangedableSubtreeNodeStack.isEmpty()) {
1077
                startCriticalSubTree = false;
1078
            }
1079

    
1080
            //set hitText false
1081
            hitTextNode = false;
1082
            // reset textbuff
1083
            textBuffer = null;
1084
            textBuffer = new StringBuffer();
1085

    
1086
            // hand sub stree stuff
1087
            if (!subTreeInfoStack.empty()) {
1088
                SubTree tree = (SubTree) subTreeInfoStack.peek();// get last
1089
                                                                 // subtree
1090
                if (tree != null && tree.getStartElementName() != null
1091
                        && (tree.getStartElementName()).equals(currentTag)) {
1092
                    // find the end of sub tree and set the end node id
1093
                    tree.setEndNodeId(endNodeId);
1094
                    // add the subtree into the final store palace
1095
                    subTreeList.add(tree);
1096
                    // get rid of it from stack
1097
                    subTreeInfoStack.pop();
1098
                }//if
1099
            }//if
1100

    
1101
            // access stuff
1102
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
1103
                // finish parser a ccess rule and assign it to new one
1104
                AccessRule newRule = accessRule;
1105
                //add the new rule to access section object
1106
                accessObject.addAccessRule(newRule);
1107
                // reset access rule
1108
                accessRule = null;
1109
            } else if (currentTag.equals(ACCESS)) {
1110
                // finish parse a access setction and assign it to new one
1111

    
1112
                accessObject.setEndNodeId(endNodeId);
1113
                AccessSection newAccessObject = accessObject;
1114

    
1115
                if (newAccessObject != null) {
1116

    
1117
                    // add the accessSection into a vector to store it
1118
                    // if it is not a reference, need to store it
1119
                    if (newAccessObject.getReferences() == null) {
1120

    
1121
                        newAccessObject
1122
                                .setStoredTmpNodeStack(storedAccessNodeStack);
1123
                        accessObjectList.add(newAccessObject);
1124
                    }
1125
                    if (processTopLeverAccess) {
1126

    
1127
                        // top level access control will handle whole document
1128
                        // -docid
1129
                        topLevelAccessControlMap.put(docid, newAccessObject);
1130
                        // reset processtopleveraccess tag
1131

    
1132
                    }//if
1133
                    else if (processAdditionalAccess) {
1134
                        // for additional control
1135
                        // put everything in describes value and access object
1136
                        // into hash
1137
                        for (int i = 0; i < describesId.size(); i++) {
1138

    
1139
                            String subId = (String) describesId.elementAt(i);
1140
                            if (subId != null) {
1141
                                additionalAccessControlMap.put(subId,
1142
                                        newAccessObject);
1143
                            }//if
1144
                        }//for
1145
                        // add this hashtable in to vector
1146

    
1147
                        additionalAccessMapList.add(additionalAccessControlMap);
1148
                        // reset this hashtable in order to store another
1149
                        // additional
1150
                        //accesscontrol
1151
                        additionalAccessControlMap = null;
1152
                        additionalAccessControlMap = new Hashtable();
1153
                    }//if
1154

    
1155
                }//if
1156
                //check if access node stack is empty after parsing top access
1157
                //module
1158

    
1159
                if (needCheckingAccessModule && processTopLeverAccess
1160
                        && !currentUnchangableAccessModuleNodeStack.isEmpty()) {
1161

    
1162
                    MetaCatUtil.debugMessage(
1163
                            "Access node stack is not empty after "
1164
                                    + "parsing access subtree", 40);
1165
                    throw new SAXException(UPDATEACCESSERROR);
1166

    
1167
                }
1168
                //reset access section object
1169

    
1170
                accessObject = null;
1171

    
1172
                // reset tmp stored node stack
1173
                storedAccessNodeStack = null;
1174
                storedAccessNodeStack = new Stack();
1175

    
1176
                // reset flag
1177
                processAdditionalAccess = false;
1178
                processTopLeverAccess = false;
1179
                processOtherAccess = false;
1180

    
1181
            } else if (currentTag.equals(ADDITIONALMETADATA)) {
1182
                //reset describesId
1183
                describesId = null;
1184
                describesId = new Vector();
1185
            }
1186
        } else {
1187
            // this is in inline part
1188
            StringBuffer endElement = new StringBuffer();
1189
            endElement.append("</");
1190
            endElement.append(qName);
1191
            endElement.append(">");
1192
            MetaCatUtil.debugMessage("inline endElement: "
1193
                    + endElement.toString(), 50);
1194
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1195
        }
1196
    }
1197

    
1198
    /**
1199
     * SAX Handler that receives notification of comments in the DTD
1200
     */
1201
    public void comment(char[] ch, int start, int length) throws SAXException
1202
    {
1203
        MetaCatUtil.debugMessage("COMMENT", 50);
1204
        if (!handleInlineData) {
1205
            if (!processingDTD) {
1206
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1207
                String str = new String(ch, start, length);
1208

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

    
1228
                }
1229
            }
1230
        } else {
1231
            // inline data comment
1232
            StringBuffer inlineComment = new StringBuffer();
1233
            inlineComment.append("<!--");
1234
            inlineComment.append(new String(ch, start, length));
1235
            inlineComment.append("-->");
1236
            MetaCatUtil.debugMessage("inline data comment: "
1237
                    + inlineComment.toString(), 50);
1238
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1239
        }
1240
    }
1241

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

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

    
1304
    /** SAX Handler that is called at the start of Namespace */
1305
    public void startPrefixMapping(String prefix, String uri)
1306
            throws SAXException
1307
    {
1308
        MetaCatUtil.debugMessage("NAMESPACE", 50);
1309
        if (!handleInlineData) {
1310
            namespaces.put(prefix, uri);
1311
        } else {
1312
            inlineDataNameSpace.put(prefix, uri);
1313
        }
1314
    }
1315

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

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

    
1349
                //compare whitespace if need
1350
                if (startCriticalSubTree) {
1351
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1352
                            data, PERMISSIONERROR);
1353
                }//if
1354

    
1355
                //compare whitespace in access top module
1356
                if (processTopLeverAccess && needCheckingAccessModule) {
1357
                    compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1358
                            data, UPDATEACCESSERROR);
1359
                }
1360
                // Write the content of the node to the database
1361
                if (needCheckingAccessModule
1362
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1363
                    // stored the pull out nodes into storedNode stack
1364
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1365
                            null, null, MetaCatUtil.normalize(data));
1366
                    storedAccessNodeStack.push(nodeElement);
1367

    
1368
                }
1369
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1370
                        docid);
1371
            }
1372
        } else {
1373
            //This is inline data write to file directly
1374
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1375
                    start, len));
1376
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1377
        }
1378

    
1379
    }
1380

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

    
1410
    /** SAX Handler that receives notification of end of the document */
1411
    public void endDocument() throws SAXException
1412
    {
1413
        MetaCatUtil.debugMessage("end Document", 50);
1414
        // There are some unchangable subtree didn't be compare
1415
        // This maybe cause user change the subtree id
1416
        if (!unChangableSubTreeHash.isEmpty()) {
1417
            MetaCatUtil.debugMessage("The unChangealbe subtree is not empty",
1418
                    40);
1419
            throw new SAXException(PERMISSIONERROR);
1420
        }
1421
        if (!super.getIsRevisionDoc())
1422
        {
1423
            // write access rule to db
1424
            writeAccessRuleToDB();
1425
            //delete relation table
1426
            deleteRelations();
1427
            //write relations
1428
            for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1429
                String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1430
                writeOnlineDataFileIdIntoRelationTable(id);
1431
            }
1432
        }
1433
       
1434

    
1435
    }
1436

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

    
1448
    /* The method to write top level access rule into db. */
1449
    private void writeTopLevelAccessRuleToDB() throws SAXException
1450
    {
1451

    
1452
        // for top document level
1453
        Object accessSection = topLevelAccessControlMap.get(docid);
1454
        boolean top = true;
1455
        String subSectionId = null;
1456
        if (accessSection != null) {
1457
            AccessSection accessSectionObj = (AccessSection) accessSection;
1458

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

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

    
1478

    
1479
            } else {
1480

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

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

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

    
1548
        }//if
1549
        else {
1550
            // couldn't find a access section object
1551
            MetaCatUtil.debugMessage(
1552
                    "couldn't find access control for document: " + docid, 35);
1553
        }
1554

    
1555
    }//writeTopLevelAccessRuletoDB
1556

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

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

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

    
1616
    /* The method to write addtional access rule into db. */
1617
    private void writeAddtionalAccessRuleToDB() throws SAXException
1618
    {
1619

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

    
1627
            Hashtable accessControlMap = (Hashtable) additionalAccessMapList
1628
                    .elementAt(j);
1629
            // additional access rule
1630
            Enumeration en = accessControlMap.keys();
1631

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

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

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

    
1692
                    MetaCatUtil.debugMessage(
1693
                            "error in EmlSAXHandler.writeAddtionalAccess"
1694
                                    + ": " + e.getMessage(), 30);
1695
                    throw new SAXException(e.getMessage());
1696
                }
1697
            }//while
1698
        }//for
1699
    }//writeAccessRuletoDB
1700

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

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

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

    
1765
            }
1766

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

    
1804
    }//writeGivenAccessRuleIntoDB
1805

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

    
1821
        try {
1822

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

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

    
1874
    }//writeAccessRuleForRalatedDataFileIntoDB
1875

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

    
1889
        } catch (SQLException e) {
1890
            throw new SAXException(e.getMessage());
1891
        } finally {
1892
            try {
1893
                stmt.close();
1894
            } catch (SQLException ee) {
1895
                throw new SAXException(ee.getMessage());
1896
            }
1897
        }
1898
    }//deletePermissionsInAccessTable
1899

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

    
1911
        String sql = null;
1912
        PreparedStatement pstmt = null;
1913
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1914
                + "subtreeid, startnodeid, endnodeid) VALUES "
1915
                + " (?, ?, ?, ?, ?, ?)";
1916
        try {
1917

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

    
1958
    }//writeAccessSubtreeIntoDB
1959

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

    
1972
        } catch (SQLException e) {
1973
            throw new SAXException(e.getMessage());
1974
        } finally {
1975
            try {
1976
                stmt.close();
1977
            } catch (SQLException ee) {
1978
                throw new SAXException(ee.getMessage());
1979
            }
1980
        }
1981
    }//deleteAccessSubTreeRecord
1982

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

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

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

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

    
2050
            // if oldString is null but newString is not null, they are same
2051
            if (same) {
2052
                if (newString != null) {
2053
                    same = false;
2054
                }
2055
            }
2056

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

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

    
2077
    /* delete the inline data file */
2078
    private void deleteInlineDataFile(String fileName)
2079
    {
2080

    
2081
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2082
        File inlineDataDirectory = new File(path);
2083
        File newFile = new File(inlineDataDirectory, fileName);
2084
        newFile.delete();
2085

    
2086
    }
2087

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

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

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

    
2176
    }//writeOnlineDataFileIdIntoRelationTable
2177

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

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

    
2229
}
(36-36/64)