Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author: sgarg $'
11
 *     '$Date: 2005-10-10 11:06:55 -0700 (Mon, 10 Oct 2005) $'
12
 * '$Revision: 2663 $'
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.apache.log4j.Logger;
48
import org.xml.sax.Attributes;
49
import org.xml.sax.SAXException;
50

    
51
/**
52
 * A database aware Class implementing callback bethods for the SAX parser to
53
 * call when processing the XML stream and generating events
54
 */
55
public class Eml210SAXHandler extends DBSAXHandler implements
56
        AccessControlInterface
57
{
58

    
59
    private Vector allowRules = new Vector();
60

    
61
    private Vector denyRules = new Vector();
62

    
63
    private String documentId = null;
64

    
65
    private Vector subDocumentIdList = new Vector();
66

    
67
    private boolean processTopLeverAccess = false;
68

    
69
    private boolean processAdditionalAccess = false;
70

    
71
    private boolean processOtherAccess = false;
72

    
73
    private AccessSection accessObject = null;
74

    
75
    private AccessRule accessRule = null;
76

    
77
    private Vector accessObjectList = new Vector(); // store every access rule
78

    
79
    private Hashtable topLevelAccessControlMap = new Hashtable();
80

    
81
    private Hashtable additionalAccessControlMap = new Hashtable();// store
82

    
83
    //subtree access for single
84
    // additionalmetacat
85
    private Vector additionalAccessMapList = new Vector();// store maps for
86

    
87
    // every addionalmetadata
88
    private Vector describesId = new Vector(); // store the ids in
89

    
90
    //additionalmetadata/describes
91
    private Stack subTreeInfoStack = new Stack();
92

    
93
    private Vector subTreeList = new Vector();// store the final subtree
94

    
95
    private Hashtable unChangableSubTreeHash = new Hashtable();
96

    
97
    private Stack currentUnChangedableSubtreeNodeStack = new Stack();
98

    
99
    private boolean startCriticalSubTree = false;
100

    
101
    private boolean firstElementForCriticalSubTree = false;
102

    
103
    private String firstElementNameForCriticalSubTree;
104

    
105
    private boolean needCheckingAccessModule = false;
106

    
107
    private Vector unChangableAccessSubTreeVector = new Vector();
108

    
109
    private Stack currentUnchangableAccessModuleNodeStack = new Stack();
110

    
111
    private AccessSection topAccessSection;
112

    
113
    // we need an another stack to store the access node which we pull out just
114
    // from xml. If a reference happend, we can use the stack the compare nodes
115
    private Stack storedAccessNodeStack = new Stack();
116

    
117
    // vector stored the data file id which will be write into relation table
118
    private Vector onlineDataFileIdInRelationVector = new Vector();
119

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

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

    
127
    private Stack inlineDataNodeStack = null;
128

    
129
    private Hashtable inlineDataNameSpace = null;
130

    
131
    private FileWriter inlineDataFileWriter = null;
132

    
133
    private String inlineDataFileName = null;
134

    
135
    private int inLineDataIndex = 0;
136

    
137
    private Vector inlineFileIDList = new Vector();
138

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
170
    private Logger logMetacat = Logger.getLogger(Eml210SAXHandler.class);   	   	
171

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

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

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

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

    
245
            }//while
246

    
247
        }//if
248

    
249
        return result;
250
    }
251

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

    
264
        try {
265

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

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

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

    
326
        DBSAXNode parentNode = null;
327
        DBSAXNode currentNode = null;
328

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

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

    
355
            }
356

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

    
367
                //compare top level access module
368
                if (processTopLeverAccess && needCheckingAccessModule) {
369
                    compareTextNode(currentUnchangableAccessModuleNodeStack,
370
                            textBuffer, UPDATEACCESSERROR);
371
                }
372

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

    
381
                }
382

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

    
392
            }
393

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

    
430
                    try {
431
                        // Get dbconnection
432
                        dbConn = DBConnectionPool
433
                                .getDBConnection("DBSAXHandler.startElement");
434
                        serialNumber = dbConn.getCheckOutSerialNumber();
435

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

    
453
                    //create documentImpl object by the constructor which can
454
                    // specify
455
                    //the revision
456
                    if (!super.getIsRevisionDoc())
457
                    {
458
                       currentDocument = new DocumentImpl(connection, rootNode
459
                            .getNodeID(), docname, doctype, docid, revision,
460
                            action, user, this.pub, catalogid, this.serverCode, 
461
                            createDate, updateDate);
462
                    }
463
                   
464
                } catch (Exception ane) {
465
                    throw (new SAXException(
466
                            "Error in EMLSaxHandler.startElement " + action,
467
                            ane));
468
                }
469
            }
470

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

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

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

    
508
                } else if (attributeName != null && attributeName.equals(ID)) {
509

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

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

    
534
                }
535
            }//for
536

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

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

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

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

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

    
588
                accessRule = new AccessRule();
589

    
590
                //set permission type "allow"
591
                accessRule.setPermissionType(ALLOW);
592

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

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

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

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

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

    
629
            }
630

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

    
647
            }
648

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

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

    
694
    }
695

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

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

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

    
773
        }//while
774

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

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

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

    
823
    }
824

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

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

    
898
    /** SAX Handler that is called at the end of each XML element */
899
    public void endElement(String uri, String localName, String qName)
900
            throws SAXException
901
    {
902
        logMetacat.info("End ELEMENT " + qName);
903

    
904
        if (localName.equals(INLINE) && handleInlineData) {
905
            // Get the node from the stack
906
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
907
            String currentTag = currentNode.getTagName();
908
            logMetacat.info("End of inline data");
909
            // close file writer
910
            try {
911
                inlineDataFileWriter.close();
912
                handleInlineData = false;
913
            } catch (IOException ioe) {
914
                throw new SAXException(ioe.getMessage());
915
            }
916

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

    
948
            }//if
949
            // write put inline data file name into text buffer (without path)
950
            textBuffer = new StringBuffer(inlineDataFileName);
951
            // write file name into db
952
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
953
                    currentNode);
954
            // reset textbuff
955
            textBuffer = null;
956
            textBuffer = new StringBuffer();
957
            return;
958
        }
959

    
960
        if (!handleInlineData) {
961
            // Get the node from the stack
962
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
963
            String currentTag = currentNode.getTagName();
964

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

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

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

    
1055
                }
1056
            }//if
1057

    
1058
            //end crtical subtree(user doesn't have permission to write)
1059
            //When reach the first element and stack is empty
1060
            if (localName.equals(firstElementNameForCriticalSubTree)
1061
                    && currentUnChangedableSubtreeNodeStack.isEmpty()) {
1062
                startCriticalSubTree = false;
1063
            }
1064

    
1065
            //set hitText false
1066
            hitTextNode = false;
1067
            // reset textbuff
1068
            textBuffer = null;
1069
            textBuffer = new StringBuffer();
1070

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

    
1086
            // access stuff
1087
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
1088
                // finish parser a ccess rule and assign it to new one
1089
                AccessRule newRule = accessRule;
1090
                //add the new rule to access section object
1091
                accessObject.addAccessRule(newRule);
1092
                // reset access rule
1093
                accessRule = null;
1094
            } else if (currentTag.equals(ACCESS)) {
1095
                // finish parse a access setction and assign it to new one
1096

    
1097
                accessObject.setEndNodeId(endNodeId);
1098
                AccessSection newAccessObject = accessObject;
1099

    
1100
                if (newAccessObject != null) {
1101

    
1102
                    // add the accessSection into a vector to store it
1103
                    // if it is not a reference, need to store it
1104
                    if (newAccessObject.getReferences() == null) {
1105

    
1106
                        newAccessObject
1107
                                .setStoredTmpNodeStack(storedAccessNodeStack);
1108
                        accessObjectList.add(newAccessObject);
1109
                    }
1110
                    if (processTopLeverAccess) {
1111

    
1112
                        // top level access control will handle whole document
1113
                        // -docid
1114
                        topLevelAccessControlMap.put(docid, newAccessObject);
1115
                        // reset processtopleveraccess tag
1116

    
1117
                    }//if
1118
                    else if (processAdditionalAccess) {
1119
                        // for additional control
1120
                        // put everything in describes value and access object
1121
                        // into hash
1122
                        for (int i = 0; i < describesId.size(); i++) {
1123

    
1124
                            String subId = (String) describesId.elementAt(i);
1125
                            if (subId != null) {
1126
                                additionalAccessControlMap.put(subId,
1127
                                        newAccessObject);
1128
                            }//if
1129
                        }//for
1130
                        // add this hashtable in to vector
1131

    
1132
                        additionalAccessMapList.add(additionalAccessControlMap);
1133
                        // reset this hashtable in order to store another
1134
                        // additional
1135
                        //accesscontrol
1136
                        additionalAccessControlMap = null;
1137
                        additionalAccessControlMap = new Hashtable();
1138
                    }//if
1139

    
1140
                }//if
1141
                //check if access node stack is empty after parsing top access
1142
                //module
1143

    
1144
                if (needCheckingAccessModule && processTopLeverAccess
1145
                        && !currentUnchangableAccessModuleNodeStack.isEmpty()) {
1146

    
1147
                    logMetacat.info(
1148
                            "Access node stack is not empty after "
1149
                                    + "parsing access subtree");
1150
                    throw new SAXException(UPDATEACCESSERROR);
1151

    
1152
                }
1153
                //reset access section object
1154

    
1155
                accessObject = null;
1156

    
1157
                // reset tmp stored node stack
1158
                storedAccessNodeStack = null;
1159
                storedAccessNodeStack = new Stack();
1160

    
1161
                // reset flag
1162
                processAdditionalAccess = false;
1163
                processTopLeverAccess = false;
1164
                processOtherAccess = false;
1165

    
1166
            } else if (currentTag.equals(ADDITIONALMETADATA)) {
1167
                //reset describesId
1168
                describesId = null;
1169
                describesId = new Vector();
1170
            }
1171
        } else {
1172
            // this is in inline part
1173
            StringBuffer endElement = new StringBuffer();
1174
            endElement.append("</");
1175
            endElement.append(qName);
1176
            endElement.append(">");
1177
            logMetacat.info("inline endElement: "
1178
                    + endElement.toString());
1179
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1180
        }
1181
    }
1182

    
1183
    /**
1184
     * SAX Handler that receives notification of comments in the DTD
1185
     */
1186
    public void comment(char[] ch, int start, int length) throws SAXException
1187
    {
1188
        logMetacat.info("COMMENT");
1189
        if (!handleInlineData) {
1190
            if (!processingDTD) {
1191
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1192
                String str = new String(ch, start, length);
1193

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

    
1213
                }
1214
            }
1215
        } else {
1216
            // inline data comment
1217
            StringBuffer inlineComment = new StringBuffer();
1218
            inlineComment.append("<!--");
1219
            inlineComment.append(new String(ch, start, length));
1220
            inlineComment.append("-->");
1221
            logMetacat.info("inline data comment: "
1222
                    + inlineComment.toString());
1223
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1224
        }
1225
    }
1226

    
1227
    /* Comparet comment from xml and db */
1228
    private void compareCommentNode(Stack nodeStack, String string, String error)
1229
            throws SAXException
1230
    {
1231
        NodeRecord node = null;
1232
        try {
1233
            node = (NodeRecord) nodeStack.pop();
1234
        } catch (EmptyStackException ee) {
1235
            logMetacat.error("the stack is empty for comment data");
1236
            throw new SAXException(error);
1237
        }
1238
        logMetacat.info("current node type from xml is COMMENT");
1239
        logMetacat.info("node type from stack: " + node.getNodeType());
1240
        logMetacat.info("current node data from xml is: " + string);
1241
        logMetacat.info("node data from stack: " + node.getNodeData());
1242
        logMetacat.info("node is from stack: " + node.getNodeId());
1243
        // if not consistent terminate program and throw a exception
1244
        if (!node.getNodeType().equals("COMMENT")
1245
                || !string.equals(node.getNodeData())) {
1246
            logMetacat.info("Inconsistence happend: ");
1247
            logMetacat.info("current node type from xml is COMMENT");
1248
            logMetacat.info("node type from stack: "
1249
                    + node.getNodeType());
1250
            logMetacat.info(
1251
                    "current node data from xml is: " + string);
1252
            logMetacat.info("node data from stack: "
1253
                    + node.getNodeData());
1254
            logMetacat.info("node is from stack: " + node.getNodeId());
1255
            throw new SAXException(error);
1256
        }//if
1257
    }
1258

    
1259
    /**
1260
     * SAX Handler called once for each processing instruction found: node that
1261
     * PI may occur before or after the root element.
1262
     */
1263
    public void processingInstruction(String target, String data)
1264
            throws SAXException
1265
    {
1266
        logMetacat.info("PI");
1267
        if (!handleInlineData) {
1268
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1269
            endNodeId = currentNode.writeChildNodeToDB("PI", target, data,
1270
                    docid);
1271
        } else {
1272
            StringBuffer inlinePI = new StringBuffer();
1273
            inlinePI.append("<?");
1274
            inlinePI.append(target);
1275
            inlinePI.append(" ");
1276
            inlinePI.append(data);
1277
            inlinePI.append("?>");
1278
            logMetacat.info("inline data pi is: "
1279
                    + inlinePI.toString());
1280
            writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1281
        }
1282
    }
1283

    
1284
    /** SAX Handler that is called at the start of Namespace */
1285
    public void startPrefixMapping(String prefix, String uri)
1286
            throws SAXException
1287
    {
1288
        logMetacat.info("NAMESPACE");
1289
        if (!handleInlineData) {
1290
            namespaces.put(prefix, uri);
1291
        } else {
1292
            inlineDataNameSpace.put(prefix, uri);
1293
        }
1294
    }
1295

    
1296
    /**
1297
     * SAX Handler that is called for each XML text node that is Ignorable
1298
     * white space
1299
     */
1300
    public void ignorableWhitespace(char[] cbuf, int start, int len)
1301
            throws SAXException
1302
    {
1303
        // When validation is turned "on", white spaces are reported here
1304
        // When validation is turned "off" white spaces are not reported here,
1305
        // but through characters() callback
1306
        logMetacat.info("IGNORABLEWHITESPACE");
1307
        if (!handleInlineData) {
1308
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1309
            String data = null;
1310
            int leftover = len;
1311
            int offset = start;
1312
            boolean moredata = true;
1313

    
1314
            // This loop deals with the case where there are more characters
1315
            // than can fit in a single database text field (limit is
1316
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
1317
            // write a series of nodes that are MAXDATACHARS long, and then the
1318
            // final node contains the remainder
1319
            while (moredata) {
1320
                if (leftover > MAXDATACHARS) {
1321
                    data = new String(cbuf, offset, MAXDATACHARS);
1322
                    leftover -= MAXDATACHARS;
1323
                    offset += MAXDATACHARS;
1324
                } else {
1325
                    data = new String(cbuf, offset, leftover);
1326
                    moredata = false;
1327
                }
1328

    
1329
                //compare whitespace if need
1330
                if (startCriticalSubTree) {
1331
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1332
                            data, PERMISSIONERROR);
1333
                }//if
1334

    
1335
                //compare whitespace in access top module
1336
                if (processTopLeverAccess && needCheckingAccessModule) {
1337
                    compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1338
                            data, UPDATEACCESSERROR);
1339
                }
1340
                // Write the content of the node to the database
1341
                if (needCheckingAccessModule
1342
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1343
                    // stored the pull out nodes into storedNode stack
1344
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1345
                            null, null, MetaCatUtil.normalize(data));
1346
                    storedAccessNodeStack.push(nodeElement);
1347

    
1348
                }
1349
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1350
                        docid);
1351
            }
1352
        } else {
1353
            //This is inline data write to file directly
1354
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1355
                    start, len));
1356
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1357
        }
1358

    
1359
    }
1360

    
1361
    /* Compare whitespace from xml and db */
1362
    private void compareWhiteSpace(Stack nodeStack, String string, String error)
1363
            throws SAXException
1364
    {
1365
        NodeRecord node = null;
1366
        try {
1367
            node = (NodeRecord) nodeStack.pop();
1368
        } catch (EmptyStackException ee) {
1369
            logMetacat.error("the stack is empty for whitespace data");
1370
            throw new SAXException(error);
1371
        }
1372
        if (!node.getNodeType().equals("TEXT")
1373
                || !string.equals(node.getNodeData())) {
1374
            logMetacat.info("Inconsistence happend: ");
1375
            logMetacat.info(
1376
                    "current node type from xml is WHITESPACE TEXT");
1377
            logMetacat.info("node type from stack: "
1378
                    + node.getNodeType());
1379
            logMetacat.info(
1380
                    "current node data from xml is: " + string);
1381
            logMetacat.info("node data from stack: "
1382
                    + node.getNodeData());
1383
            logMetacat.info("node is from stack: " + node.getNodeId());
1384
            throw new SAXException(error);
1385
        }//if
1386
    }
1387

    
1388
    /** SAX Handler that receives notification of end of the document */
1389
    public void endDocument() throws SAXException
1390
    {
1391
        logMetacat.info("end Document");
1392
        // There are some unchangable subtree didn't be compare
1393
        // This maybe cause user change the subtree id
1394
        if (!unChangableSubTreeHash.isEmpty()) {
1395
            logMetacat.info("The unChangealbe subtree is not empty");
1396
            throw new SAXException(PERMISSIONERROR);
1397
        }
1398
        if (!super.getIsRevisionDoc())
1399
        {
1400
            // write access rule to db
1401
            writeAccessRuleToDB();
1402
            //delete relation table
1403
            deleteRelations();
1404
            //write relations
1405
            for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1406
                String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1407
                writeOnlineDataFileIdIntoRelationTable(id);
1408
            }
1409
        }
1410
       
1411

    
1412
    }
1413

    
1414
    /* The method to write all access rule into db */
1415
    private void writeAccessRuleToDB() throws SAXException
1416
    {
1417
        //Delete old permssion
1418
        deletePermissionsInAccessTable(docid);
1419
        //write top leve access rule
1420
        writeTopLevelAccessRuleToDB();
1421
        //write additional access rule
1422
        //writeAddtionalAccessRuleToDB();
1423
    }//writeAccessRuleToDB
1424

    
1425
    /* The method to write top level access rule into db. */
1426
    private void writeTopLevelAccessRuleToDB() throws SAXException
1427
    {
1428

    
1429
        // for top document level
1430
        Object accessSection = topLevelAccessControlMap.get(docid);
1431
        boolean top = true;
1432
        String subSectionId = null;
1433
        if (accessSection != null) {
1434
            AccessSection accessSectionObj = (AccessSection) accessSection;
1435

    
1436
            // if accessSection is not null and is not reference
1437
            if (accessSectionObj.getReferences() == null) {
1438
                // write the top level access module into xml_accesssubtree to
1439
                // store info
1440
                // and then when update to check if the user can update it or
1441
                // not
1442
                deleteAccessSubTreeRecord(docid);
1443
                writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1444

    
1445
                //write access section into xml_access table
1446
                writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1447
                // write online data file into xml_access too.
1448
                for (int i= 0; i <onlineDataFileIdInTopAccessVector.size(); i++)
1449
                {
1450
                  String id = (String)
1451
                               onlineDataFileIdInTopAccessVector.elementAt(i);
1452
                  writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1453
                }
1454

    
1455

    
1456
            } else {
1457

    
1458
                // this is a reference and go trough the vector which contains
1459
                // all
1460
                // access object
1461
                String referenceId = accessSectionObj.getReferences();
1462
                boolean findAccessObject = false;
1463
                logMetacat.info("referered id for top access: "
1464
                        + referenceId);
1465
                for (int i = 0; i < accessObjectList.size(); i++) {
1466
                    AccessSection accessObj = (AccessSection) accessObjectList
1467
                            .elementAt(i);
1468
                    String accessObjId = accessObj.getSubTreeId();
1469
                    if (referenceId != null && accessObj != null
1470
                            && referenceId.equals(accessObjId)) {
1471
                        // make sure the user didn't change any thing in this
1472
                        // access moduel
1473
                        // too if user doesn't have all permission
1474
                        if (needCheckingAccessModule) {
1475

    
1476
                            Stack newStack = accessObj.getStoredTmpNodeStack();
1477
                            //revise order
1478
                            newStack = MetaCatUtil.reviseStack(newStack);
1479
                            // go throught the vector of
1480
                            // unChangableAccessSubtreevector
1481
                            // and find the one whose id is as same as
1482
                            // referenceid
1483
                            AccessSection oldAccessObj = getAccessSectionFromUnchangableAccessVector(referenceId);
1484
                            //if oldAccessObj is null something is wrong
1485
                            if (oldAccessObj == null) {
1486
                                throw new SAXException(UPDATEACCESSERROR);
1487
                            }//if
1488
                            else {
1489
                                // Get the node stack from old access obj
1490
                                Stack oldStack = oldAccessObj
1491
                                        .getSubTreeNodeStack();
1492
                                comparingNodeStacks(newStack, oldStack);
1493
                            }//else
1494
                        }//if
1495
                        // write accessobject into db
1496
                        writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1497
                        // write online data file into xml_access too.
1498
                        for (int j= 0; j <onlineDataFileIdInTopAccessVector.size(); j++)
1499
                        {
1500
                          String id = (String)
1501
                              onlineDataFileIdInTopAccessVector.elementAt(j);
1502
                           writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1503
                        }
1504

    
1505
                        //write the reference access into xml_accesssubtree
1506
                        // too
1507
                        // write the top level access module into
1508
                        // xml_accesssubtree to store info
1509
                        // and then when update to check if the user can update
1510
                        // it or not
1511
                        deleteAccessSubTreeRecord(docid);
1512
                        writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1513
                        writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1514
                        findAccessObject = true;
1515
                        break;
1516
                    }
1517
                }//for
1518
                // if we couldn't find an access subtree id for this reference
1519
                // id
1520
                if (!findAccessObject) { throw new SAXException(
1521
                        "The referenceid: " + referenceId
1522
                                + " is not access subtree"); }//if
1523
            }//else
1524

    
1525
        }//if
1526
        else {
1527
            // couldn't find a access section object
1528
            logMetacat.info(
1529
                    "couldn't find access control for document: " + docid);
1530
        }
1531

    
1532
    }//writeTopLevelAccessRuletoDB
1533

    
1534
    /* Given a subtree id and find the responding access section */
1535
    private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1536
    {
1537
        AccessSection result = null;
1538
        // Makse sure the id
1539
        if (id == null || id.equals("")) { return result; }
1540
        // go throught vector and find the list
1541
        for (int i = 0; i < unChangableAccessSubTreeVector.size(); i++) {
1542
            AccessSection accessObj = (AccessSection) unChangableAccessSubTreeVector
1543
                    .elementAt(i);
1544
            if (accessObj.getSubTreeId() != null
1545
                    && (accessObj.getSubTreeId()).equals(id)) {
1546
                result = accessObj;
1547
            }//if
1548
        }//for
1549
        return result;
1550
    }//getAccessSectionFromUnchangableAccessVector
1551

    
1552
    /* Compare two node stacks to see if they are same */
1553
    private void comparingNodeStacks(Stack stack1, Stack stack2)
1554
            throws SAXException
1555
    {
1556
        // make sure stack1 and stack2 are not empty
1557
        if (stack1.isEmpty() || stack2.isEmpty()) {
1558
            logMetacat.info("Because stack is empty!");
1559
            throw new SAXException(UPDATEACCESSERROR);
1560
        }
1561
        // go throw two stacks and compare every element
1562
        while (!stack1.isEmpty()) {
1563
            // Pop an element from stack1
1564
            NodeRecord record1 = (NodeRecord) stack1.pop();
1565
            // Pop an element from stack2(stack 2 maybe empty)
1566
            NodeRecord record2 = null;
1567
            try {
1568
                record2 = (NodeRecord) stack2.pop();
1569
            } catch (EmptyStackException ee) {
1570
                logMetacat.error(
1571
                        "Node stack2 is empty but stack1 isn't!");
1572
                throw new SAXException(UPDATEACCESSERROR);
1573
            }
1574
            // if two records are not same throw a exception
1575
            if (!record1.contentEquals(record2)) {
1576
                logMetacat.info(
1577
                                "Two records from new and old stack are not "
1578
                                        + "same!");
1579
                throw new SAXException(UPDATEACCESSERROR);
1580
            }//if
1581
        }//while
1582

    
1583
        // now stack1 is empty and we should make sure stack2 is empty too
1584
        if (!stack2.isEmpty()) {
1585
            logMetacat.info(
1586
                    "stack2 still have some elements while stack "
1587
                            + "is empty! ");
1588
            throw new SAXException(UPDATEACCESSERROR);
1589
        }//if
1590
    }//comparingNodeStacks
1591

    
1592
    /* The method to write addtional access rule into db. */
1593
    private void writeAddtionalAccessRuleToDB() throws SAXException
1594
    {
1595

    
1596
        PreparedStatement pstmt = null;
1597
        boolean topLevel = false;
1598
        // go through the vector which contains the additional access control
1599
        //hashtable. Each hashtable has info for one additonalmetadata
1600
        // container
1601
        for (int j = 0; j < additionalAccessMapList.size(); j++) {
1602

    
1603
            Hashtable accessControlMap = (Hashtable) additionalAccessMapList
1604
                    .elementAt(j);
1605
            // additional access rule
1606
            Enumeration en = accessControlMap.keys();
1607

    
1608
            while (en.hasMoreElements()) {
1609
                try {
1610
                    // Get subsection id
1611
                    String subSectionId = (String) en.nextElement();
1612
                    logMetacat.info(
1613
                            "sub section id in additional access mapping"
1614
                                    + "(go through): " + subSectionId);
1615

    
1616
                    if (subSectionId == null) {
1617
                    // if id is null, terminate the program
1618
                    throw new SAXException("subtree id is null"); }
1619
                    // Get AccessSection Object
1620
                    Object accessSectionObj = accessControlMap
1621
                            .get(subSectionId);
1622
                    if (accessSectionObj == null) {
1623
                        // if accesssection is null, terminate the program
1624
                        throw new SAXException("access subtree is null");
1625
                    } else {
1626
                        AccessSection accessControlObj = (AccessSection) accessSectionObj;
1627
                        // if the access section is not references, write it to
1628
                        // db
1629
                        if (accessControlObj.getReferences() == null) {
1630
                            writeGivenAccessRuleIntoDB(accessControlObj,
1631
                                    topLevel, subSectionId);
1632
                        } else {
1633
                            // this is a reference and go trough the vector
1634
                            // which contains all
1635
                            // access object
1636
                            String referenceId = accessControlObj
1637
                                    .getReferences();
1638

    
1639
                            boolean findAccessObject = false;
1640
                            logMetacat.info(
1641
                                    "referered id for additional access "
1642
                                            + "mapping(go through): "
1643
                                            + referenceId);
1644
                            for (int i = 0; i < accessObjectList.size(); i++) {
1645
                                AccessSection accessObj = (AccessSection) accessObjectList
1646
                                        .elementAt(i);
1647
                                String accessObjId = accessObj.getSubTreeId();
1648
                                logMetacat.info(
1649
                                        "access obj id in the list(go through): "
1650
                                                + accessObjId);
1651
                                if (referenceId != null && accessObj != null
1652
                                        && referenceId.equals(accessObjId)) {
1653
                                    writeGivenAccessRuleIntoDB(accessObj,
1654
                                            topLevel, subSectionId);
1655
                                    findAccessObject = true;
1656
                                }//if
1657
                            }//for
1658
                            // if we couldn't find an access subtree id for
1659
                            // this reference id
1660
                            if (!findAccessObject) { throw new SAXException(
1661
                                    "The referenceid: " + referenceId
1662
                                            + " is not access subtree"); }//if
1663
                        }//else
1664
                    }//else
1665
                }//try
1666
                catch (Exception e) {
1667

    
1668
                    logMetacat.error(
1669
                            "error in EmlSAXHandler.writeAddtionalAccess"
1670
                                    + ": " + e.getMessage());
1671
                    throw new SAXException(e.getMessage());
1672
                }
1673
            }//while
1674
        }//for
1675
    }//writeAccessRuletoDB
1676

    
1677
    /* Write a gaven access rule into db */
1678
    private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1679
            boolean topLevel, String subSectionId) throws SAXException
1680
    {
1681
        if (accessSection == null) { throw new SAXException(
1682
                "The access object is null"); }
1683

    
1684
        String permOrder = accessSection.getPermissionOrder();
1685
        String sql = null;
1686
        PreparedStatement pstmt = null;
1687
        if (topLevel) {
1688
            sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1689
                    + "perm_type, perm_order, accessfileid) VALUES "
1690
                    + " (?, ?, ?, ?, ?, ?)";
1691
        } else {
1692
            sql = "INSERT INTO xml_access (docid,principal_name, "
1693
                    + "permission, perm_type, perm_order, accessfileid, subtreeid, "
1694
                    + " startnodeid, endnodeid) VALUES"
1695
                    + " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1696
        }
1697
        try {
1698

    
1699
            pstmt = connection.prepareStatement(sql);
1700
            // Increase DBConnection usage count
1701
            connection.increaseUsageCount(1);
1702
            // Bind the values to the query
1703
            pstmt.setString(1, docid);
1704
            logMetacat.info("Docid in accesstable: " + docid);
1705
            pstmt.setString(6, docid);
1706
            logMetacat.info("Accessfileid in accesstable: " + docid);
1707
            pstmt.setString(5, permOrder);
1708
            logMetacat.info("PermOder in accesstable: " + permOrder);
1709
            // if it is not top level, set subsection id
1710
            if (!topLevel) {
1711
                long startNodeId = 0;
1712
                long endNodeId = 0;
1713
                // for subtree should specify the
1714
                if (subSectionId == null) { throw new SAXException(
1715
                        "The subsection is null"); }
1716
                // go through the substree list vector and found the start node
1717
                // id
1718
                // and stop node id for this subtree id
1719
                for (int i = 0; i < subTreeList.size(); i++) {
1720
                    SubTree tree = (SubTree) subTreeList.elementAt(i);
1721
                    String subTreeId = tree.getSubTreeId();
1722
                    if (subSectionId.equals(subTreeId)) {
1723
                        startNodeId = tree.getStartNodeId();
1724
                        endNodeId = tree.getEndNodeId();
1725
                    }//if
1726
                }//for
1727
                if (startNodeId == 0 || endNodeId == 0) { throw new SAXException(
1728
                        "Could find the subtree" + "for this id: "
1729
                                + subSectionId); }
1730
                pstmt.setString(7, subSectionId);
1731
                logMetacat.info("SubSectionId in accesstable: "
1732
                        + subSectionId);
1733
                pstmt.setLong(8, startNodeId);
1734
                logMetacat.info("Start node id is: " + startNodeId);
1735
                pstmt.setLong(9, endNodeId);
1736
                logMetacat.info("End node id is: " + endNodeId);
1737

    
1738
            }
1739

    
1740
            Vector accessRules = accessSection.getAccessRules();
1741
            // go through every rule
1742
            for (int i = 0; i < accessRules.size(); i++) {
1743
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1744
                String permType = rule.getPermissionType();
1745
                int permission = rule.getPermission();
1746
                pstmt.setInt(3, permission);
1747
                logMetacat.info("permission in accesstable: "
1748
                        + permission);
1749
                pstmt.setString(4, permType);
1750
                logMetacat.info(
1751
                        "Permtype in accesstable: " + permType);
1752
                // go through every principle in rule
1753
                Vector nameVector = rule.getPrincipal();
1754
                for (int j = 0; j < nameVector.size(); j++) {
1755
                    String prName = (String) nameVector.elementAt(j);
1756
                    pstmt.setString(2, prName);
1757
                    logMetacat.info("Principal in accesstable: "
1758
                            + prName);
1759
                    pstmt.execute();
1760
                }//for
1761
            }//for
1762
            pstmt.close();
1763
        }//try
1764
        catch (SQLException e) {
1765
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1766
                    + e.getMessage());
1767
        }//catch
1768
        finally {
1769
            try {
1770
                pstmt.close();
1771
            } catch (SQLException ee) {
1772
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1773
                        + ee.getMessage());
1774
            }
1775
        }//finally
1776

    
1777
    }//writeGivenAccessRuleIntoDB
1778

    
1779
    /* Write a gaven access rule into db */
1780
    private void writeAccessRuleForRalatedDataFileIntoDB(
1781
            AccessSection accessSection, String dataId) throws SAXException
1782
    {
1783
        if (accessSection == null) { throw new SAXException(
1784
                "The access object is null"); }
1785
        // get rid of rev from dataId
1786
        //dataId = MetaCatUtil.getDocIdFromString(dataId);
1787
        String permOrder = accessSection.getPermissionOrder();
1788
        String sql = null;
1789
        PreparedStatement pstmt = null;
1790
        sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1791
                + "perm_type, perm_order, accessfileid) VALUES "
1792
                + " (?, ?, ?, ?, ?, ?)";
1793

    
1794
        try {
1795

    
1796
            pstmt = connection.prepareStatement(sql);
1797
            // Increase DBConnection usage count
1798
            connection.increaseUsageCount(1);
1799
            // Bind the values to the query
1800
            pstmt.setString(1, dataId);
1801
            logMetacat.info("Docid in accesstable: " + docid);
1802
            pstmt.setString(6, docid);
1803
            logMetacat.info("Accessfileid in accesstable: " + docid);
1804
            pstmt.setString(5, permOrder);
1805
            logMetacat.info("PermOder in accesstable: " + permOrder);
1806
            // if it is not top level, set subsection id
1807

    
1808
            Vector accessRules = accessSection.getAccessRules();
1809
            // go through every rule
1810
            for (int i = 0; i < accessRules.size(); i++) {
1811
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1812
                String permType = rule.getPermissionType();
1813
                int permission = rule.getPermission();
1814
                pstmt.setInt(3, permission);
1815
                logMetacat.info("permission in accesstable: "
1816
                        + permission);
1817
                pstmt.setString(4, permType);
1818
                logMetacat.info(
1819
                        "Permtype in accesstable: " + permType);
1820
                // go through every principle in rule
1821
                Vector nameVector = rule.getPrincipal();
1822
                for (int j = 0; j < nameVector.size(); j++) {
1823
                    String prName = (String) nameVector.elementAt(j);
1824
                    pstmt.setString(2, prName);
1825
                    logMetacat.info("Principal in accesstable: "
1826
                            + prName);
1827
                    pstmt.execute();
1828
                }//for
1829
            }//for
1830
            pstmt.close();
1831
        }//try
1832
        catch (SQLException e) {
1833
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1834
                    + e.getMessage());
1835
        }//catch
1836
        finally {
1837
            try {
1838
                pstmt.close();
1839
            } catch (SQLException ee) {
1840
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1841
                        + ee.getMessage());
1842
            }
1843
        }//finally
1844

    
1845
    }//writeAccessRuleForRalatedDataFileIntoDB
1846

    
1847
    /* Delete from db all permission for resources related to @aclid if any. */
1848
    private void deletePermissionsInAccessTable(String aclid)
1849
            throws SAXException
1850
    {
1851
        Statement stmt = null;
1852
        try {
1853
            // delete all acl records for resources related to @aclid if any
1854
            stmt = connection.createStatement();
1855
            // Increase DBConnection usage count
1856
            connection.increaseUsageCount(1);
1857
            stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
1858
                    + aclid + "'");
1859

    
1860
        } catch (SQLException e) {
1861
            throw new SAXException(e.getMessage());
1862
        } finally {
1863
            try {
1864
                stmt.close();
1865
            } catch (SQLException ee) {
1866
                throw new SAXException(ee.getMessage());
1867
            }
1868
        }
1869
    }//deletePermissionsInAccessTable
1870

    
1871
    /*
1872
     * In order to make sure only usr has "all" permission can update access
1873
     * subtree in eml document we need to keep access subtree info in
1874
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1875
     */
1876
    private void writeAccessSubTreeIntoDB(AccessSection accessSection,
1877
            String level) throws SAXException
1878
    {
1879
        if (accessSection == null) { throw new SAXException(
1880
                "The access object is null"); }
1881

    
1882
        String sql = null;
1883
        PreparedStatement pstmt = null;
1884
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1885
                + "subtreeid, startnodeid, endnodeid) VALUES "
1886
                + " (?, ?, ?, ?, ?, ?)";
1887
        try {
1888

    
1889
            pstmt = connection.prepareStatement(sql);
1890
            // Increase DBConnection usage count
1891
            connection.increaseUsageCount(1);
1892
            long startNodeId = accessSection.getStartNodeId();
1893
            long endNodeId = accessSection.getEndNodeId();
1894
            String sectionId = accessSection.getSubTreeId();
1895
            // Bind the values to the query
1896
            pstmt.setString(1, docid);
1897
            logMetacat.info("Docid in access-subtreetable: " + docid);
1898
            pstmt.setString(2, revision);
1899
            logMetacat.info("rev in accesssubtreetable: " + revision);
1900
            pstmt.setString(3, level);
1901
            logMetacat.info("contorl level in access-subtree table: "
1902
                    + level);
1903
            pstmt.setString(4, sectionId);
1904
            logMetacat.info("Subtree id in access-subtree table: "
1905
                    + sectionId);
1906
            pstmt.setLong(5, startNodeId);
1907
            logMetacat.info("Start node id is: " + startNodeId);
1908
            pstmt.setLong(6, endNodeId);
1909
            logMetacat.info("End node id is: " + endNodeId);
1910
            pstmt.execute();
1911
            pstmt.close();
1912
        }//try
1913
        catch (SQLException e) {
1914
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1915
                    + e.getMessage());
1916
        }//catch
1917
        finally {
1918
            try {
1919
                pstmt.close();
1920
            } catch (SQLException ee) {
1921
                throw new SAXException(
1922
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1923
                                + ee.getMessage());
1924
            }
1925
        }//finally
1926

    
1927
    }//writeAccessSubtreeIntoDB
1928

    
1929
    /* Delete every access subtree record from xml_accesssubtree. */
1930
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
1931
    {
1932
        Statement stmt = null;
1933
        try {
1934
            // delete all acl records for resources related to @aclid if any
1935
            stmt = connection.createStatement();
1936
            // Increase DBConnection usage count
1937
            connection.increaseUsageCount(1);
1938
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
1939
                    + docId + "'");
1940

    
1941
        } catch (SQLException e) {
1942
            throw new SAXException(e.getMessage());
1943
        } finally {
1944
            try {
1945
                stmt.close();
1946
            } catch (SQLException ee) {
1947
                throw new SAXException(ee.getMessage());
1948
            }
1949
        }
1950
    }//deleteAccessSubTreeRecord
1951

    
1952
    // open a file writer for writing inline data to file
1953
    private FileWriter createInlineDataFileWriter(String fileName)
1954
            throws SAXException
1955
    {
1956
        FileWriter writer = null;
1957
        String path = MetaCatUtil.getOption("inlinedatafilepath");
1958
        /*
1959
         * File inlineDataDirectory = new File(path);
1960
         */
1961
        String newFile = path + "/" + fileName;
1962
        logMetacat.info("inline file name: " + newFile);
1963
        try {
1964
            // true means append
1965
            writer = new FileWriter(newFile, true);
1966
        } catch (IOException ioe) {
1967
            throw new SAXException(ioe.getMessage());
1968
        }
1969
        return writer;
1970
    }
1971

    
1972
    // write inline data into file system and return file name(without path)
1973
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
1974
            throws SAXException
1975
    {
1976
        try {
1977
            writer.write(data.toString());
1978
            writer.flush();
1979
        } catch (Exception e) {
1980
            throw new SAXException(e.getMessage());
1981
        }
1982
    }
1983

    
1984
    /*
1985
     * In eml2, the inline data wouldn't store in db, it store in file system
1986
     * The db stores file name(without path). We got the old file name from db
1987
     * and compare to the new in line data file
1988
     */
1989
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
1990
            throws McdbException
1991
    {
1992
        // this method need to be testing
1993
        boolean same = true;
1994
        String data = null;
1995
        String path = MetaCatUtil.getOption("inlinedatafilepath");
1996
        // the new file name will look like path/docid.rev.2
1997
        File inlineDataDirectory = new File(path);
1998
        File oldDataFile = new File(inlineDataDirectory, oldFileName);
1999
        File newDataFile = new File(inlineDataDirectory, newFileName);
2000
        try {
2001
            FileReader oldFileReader = new FileReader(oldDataFile);
2002
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2003
            FileReader newFileReader = new FileReader(newDataFile);
2004
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2005
            // read first line of data
2006
            String oldString = oldStringReader.readLine();
2007
            String newString = newStringReader.readLine();
2008

    
2009
            // at the end oldstring will be null
2010
            while (oldString != null) {
2011
                oldString = oldStringReader.readLine();
2012
                newString = newStringReader.readLine();
2013
                if (!oldString.equals(newString)) {
2014
                    same = false;
2015
                    break;
2016
                }
2017
            }
2018

    
2019
            // if oldString is null but newString is not null, they are same
2020
            if (same) {
2021
                if (newString != null) {
2022
                    same = false;
2023
                }
2024
            }
2025

    
2026
        } catch (Exception e) {
2027
            throw new McdbException(e.getMessage());
2028
        }
2029
        logMetacat.info("the inline data retrieve from file: " + data);
2030
        return same;
2031
    }
2032

    
2033
    // if xml file failed to upload, we need to call this method to delete
2034
    // the inline data already in file system
2035
    public void deleteInlineFiles()
2036
    {
2037
        if (!inlineFileIDList.isEmpty()) {
2038
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2039
                String fileName = (String) inlineFileIDList.elementAt(i);
2040
                deleteInlineDataFile(fileName);
2041
            }
2042
        }
2043
    }
2044

    
2045
    /* delete the inline data file */
2046
    private void deleteInlineDataFile(String fileName)
2047
    {
2048

    
2049
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2050
        File inlineDataDirectory = new File(path);
2051
        File newFile = new File(inlineDataDirectory, fileName);
2052
        newFile.delete();
2053

    
2054
    }
2055

    
2056
    /*
2057
     * In eml2, the inline data wouldn't store in db, it store in file system
2058
     * The db stores file name(without path).
2059
     */
2060
    public static Reader readInlineDataFromFileSystem(String fileName)
2061
            throws McdbException
2062
    {
2063
        //BufferedReader stringReader = null;
2064
        FileReader fileReader = null;
2065
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2066
        // the new file name will look like path/docid.rev.2
2067
        File inlineDataDirectory = new File(path);
2068
        File dataFile = new File(inlineDataDirectory, fileName);
2069
        try {
2070
            fileReader = new FileReader(dataFile);
2071
            //stringReader = new BufferedReader(fileReader);
2072
        } catch (Exception e) {
2073
            throw new McdbException(e.getMessage());
2074
        }
2075
        // return stringReader;
2076
        return fileReader;
2077
    }
2078

    
2079
    /* Delete relations */
2080
    private void deleteRelations() throws SAXException
2081
    {
2082
        PreparedStatement pStmt = null;
2083
        String sql = "DELETE FROM xml_relation where docid =?";
2084
        try {
2085
            pStmt = connection.prepareStatement(sql);
2086
            //bind variable
2087
            pStmt.setString(1, docid);
2088
            //execute query
2089
            pStmt.execute();
2090
            pStmt.close();
2091
        }//try
2092
        catch (SQLException e) {
2093
            throw new SAXException("EMLSAXHandler.deleteRelations(): "
2094
                    + e.getMessage());
2095
        }//catch
2096
        finally {
2097
            try {
2098
                pStmt.close();
2099
            }//try
2100
            catch (SQLException ee) {
2101
                throw new SAXException("EMLSAXHandler.deleteRelations: "
2102
                        + ee.getMessage());
2103
            }//catch
2104
        }//finally
2105
    }
2106

    
2107
    /* Write an online data file id into xml_relation table. The dataId shouldnot
2108
     * have the revision
2109
     */
2110
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2111
            throws SAXException
2112
    {
2113
        PreparedStatement pStmt = null;
2114
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2115
                + "relationship, object) values (?, ?, ?, ?, ?)";
2116
        try {
2117
            pStmt = connection.prepareStatement(sql);
2118
            //bind variable
2119
            pStmt.setString(1, docid);
2120
            pStmt.setString(2, DocumentImpl.EML2_1_0NAMESPACE);
2121
            pStmt.setString(3, docid);
2122
            pStmt.setString(4, RELATION);
2123
            pStmt.setString(5, dataId);
2124
            //execute query
2125
            pStmt.execute();
2126
            pStmt.close();
2127
        }//try
2128
        catch (SQLException e) {
2129
            throw new SAXException(
2130
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2131
                            + e.getMessage());
2132
        }//catch
2133
        finally {
2134
            try {
2135
                pStmt.close();
2136
            }//try
2137
            catch (SQLException ee) {
2138
                throw new SAXException(
2139
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2140
                                + ee.getMessage());
2141
            }//catch
2142
        }//finally
2143

    
2144
    }//writeOnlineDataFileIdIntoRelationTable
2145

    
2146
    /*
2147
     * This method will handle data file in online url. If the data file is in
2148
     * ecogrid protocol, then the datafile identifier(without rev)should be put
2149
     * into onlineDataFileRelationVector. The  docid in this vector will be
2150
     * insert into xml_relation table in endDocument().
2151
     * If the data file doesn't exsit in xml_documents or
2152
     * xml_revision table, or the user has all permission to the data file if
2153
     * the docid already existed, the data file id (without rev)will be put into
2154
     * onlineDataFileTopAccessVector. The top access rules specified in this eml
2155
     * document will apply to the data file.
2156
     * NEED to do:
2157
     * We should also need to implement http and ftp. Those
2158
     * external files should be download and assign a data file id to it.
2159
     */
2160
    private void handleOnlineUrlDataFile(String url) throws SAXException
2161
    {
2162
      logMetacat.warn("The url is "+ url);
2163
      // if the url is not a ecogrid protocol, null will be getten
2164
      String accessionNumber =
2165
                 MetaCatUtil.getAccessionNumberFromEcogridIdentifier(url);
2166
      if (accessionNumber != null)
2167
      {
2168
        // handle ecogrid protocol
2169
        // get rid of revision number to get the docid.
2170
        String docid = MetaCatUtil.getDocIdFromAccessionNumber(accessionNumber);
2171
        onlineDataFileIdInRelationVector.add(docid);
2172
        try
2173
        {
2174

    
2175
          if (!AccessionNumber.accNumberUsed(docid))
2176
          {
2177
            onlineDataFileIdInTopAccessVector.add(docid);
2178
          }
2179
          PermissionController controller = new
2180
              PermissionController(accessionNumber);
2181
          if (controller.hasPermission(
2182
              user, groups, AccessControlInterface.ALLSTRING))
2183
          {
2184
            onlineDataFileIdInTopAccessVector.add(docid);
2185
          }
2186
        }//try
2187
        catch(Exception e)
2188
        {
2189
          logMetacat.error("Eorr in " +
2190
                                "Eml210SAXHanlder.handleOnlineUrlDataFile is " +
2191
                                 e.getMessage());
2192
          throw new SAXException(e.getMessage());
2193
        }
2194
      }
2195
    }
2196

    
2197
}
(35-35/65)