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
 *
9
 *   '$Author: jones $'
10
 *     '$Date: 2006-11-10 10:25:38 -0800 (Fri, 10 Nov 2006) $'
11
 * '$Revision: 3077 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.io.BufferedReader;
31
import java.io.File;
32
import java.io.FileReader;
33
import java.io.FileWriter;
34
import java.io.IOException;
35
import java.io.Reader;
36
import java.sql.PreparedStatement;
37
import java.sql.ResultSet;
38
import java.sql.SQLException;
39
import java.sql.Statement;
40
import java.util.EmptyStackException;
41
import java.util.Enumeration;
42
import java.util.Hashtable;
43
import java.util.Stack;
44
import java.util.Vector;
45

    
46
import org.apache.log4j.Logger;
47
import org.xml.sax.Attributes;
48
import org.xml.sax.SAXException;
49

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

    
58
    private Vector allowRules = new Vector();
59

    
60
    private Vector denyRules = new Vector();
61

    
62
    private String documentId = null;
63

    
64
    private Vector subDocumentIdList = new Vector();
65

    
66
    private boolean processTopLeverAccess = false;
67

    
68
    private boolean processAdditionalAccess = false;
69

    
70
    private boolean processOtherAccess = false;
71

    
72
    private AccessSection accessObject = null;
73

    
74
    private AccessRule accessRule = null;
75

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

    
78
    private Hashtable topLevelAccessControlMap = new Hashtable();
79

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

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

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

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

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

    
94
    private Hashtable unChangableSubTreeHash = new Hashtable();
95

    
96
    private Stack currentUnChangedableSubtreeNodeStack = new Stack();
97

    
98
    private boolean startCriticalSubTree = false;
99

    
100
    private boolean firstElementForCriticalSubTree = false;
101

    
102
    private String firstElementNameForCriticalSubTree;
103

    
104
    private boolean needCheckingAccessModule = false;
105

    
106
    private Vector unChangableAccessSubTreeVector = new Vector();
107

    
108
    private Stack currentUnchangableAccessModuleNodeStack = new Stack();
109

    
110
    private AccessSection topAccessSection;
111

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

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

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

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

    
126
    private Stack inlineDataNodeStack = null;
127

    
128
    private Hashtable inlineDataNameSpace = null;
129

    
130
    private FileWriter inlineDataFileWriter = null;
131

    
132
    private String inlineDataFileName = null;
133

    
134
    private int inLineDataIndex = 0;
135

    
136
    private Vector inlineFileIDList = new Vector();
137

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
244
            }//while
245

    
246
        }//if
247

    
248
        return result;
249
    }
250

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

    
263
        try {
264

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

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

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

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

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

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

    
354
            }
355

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

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

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

    
380
                }
381

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

    
391
            }
392

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

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

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

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

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

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

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

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

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

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

    
533
                }
534
            }//for
535

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

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

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

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

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

    
587
                accessRule = new AccessRule();
588

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

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

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

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

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

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

    
628
            }
629

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

    
646
            }
647

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

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

    
693
    }
694

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

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

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

    
772
        }//while
773

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

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

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

    
822
    }
823

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

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

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

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

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

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

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

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

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

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

    
1054
                }
1055
            }//if
1056

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

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

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

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

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

    
1099
                if (newAccessObject != null) {
1100

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

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

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

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

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

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

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

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

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

    
1151
                }
1152
                //reset access section object
1153

    
1154
                accessObject = null;
1155

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1358
    }
1359

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

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

    
1411
    }
1412

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

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

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

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

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

    
1454

    
1455
            } else {
1456

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

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

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

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

    
1531
    }//writeTopLevelAccessRuletoDB
1532

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1737
            }
1738

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

    
1776
    }//writeGivenAccessRuleIntoDB
1777

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

    
1793
        try {
1794

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

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

    
1844
    }//writeAccessRuleForRalatedDataFileIntoDB
1845

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

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

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

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

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

    
1926
    }//writeAccessSubtreeIntoDB
1927

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

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

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

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

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

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

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

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

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

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

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

    
2053
    }
2054

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

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

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

    
2143
    }//writeOnlineDataFileIdIntoRelationTable
2144

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

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

    
2196
}
(35-35/66)