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: daigle $'
10
 *     '$Date: 2008-08-05 17:33:45 -0700 (Tue, 05 Aug 2008) $'
11
 * '$Revision: 4212 $'
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
import edu.ucsb.nceas.metacat.service.PropertyService;
51
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
52
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
53

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

    
62
    private Vector allowRules = new Vector();
63

    
64
    private Vector denyRules = new Vector();
65

    
66
    private String documentId = null;
67

    
68
    private Vector subDocumentIdList = new Vector();
69

    
70
    private boolean processTopLeverAccess = false;
71

    
72
    private boolean processAdditionalAccess = false;
73

    
74
    private boolean processOtherAccess = false;
75

    
76
    private AccessSection accessObject = null;
77

    
78
    private AccessRule accessRule = null;
79

    
80
    private Vector accessObjectList = new Vector(); // store every access rule
81

    
82
    private Hashtable topLevelAccessControlMap = new Hashtable();
83

    
84
    private Hashtable additionalAccessControlMap = new Hashtable();// store
85

    
86
    //subtree access for single
87
    // additionalmetacat
88
    private Vector additionalAccessMapList = new Vector();// store maps for
89

    
90
    // every addionalmetadata
91
    private Vector describesId = new Vector(); // store the ids in
92

    
93
    //additionalmetadata/describes
94
    private Stack subTreeInfoStack = new Stack();
95

    
96
    private Vector subTreeList = new Vector();// store the final subtree
97

    
98
    private Hashtable unChangableSubTreeHash = new Hashtable();
99

    
100
    private Stack currentUnChangedableSubtreeNodeStack = new Stack();
101

    
102
    private boolean startCriticalSubTree = false;
103

    
104
    private boolean firstElementForCriticalSubTree = false;
105

    
106
    private String firstElementNameForCriticalSubTree;
107

    
108
    private boolean needCheckingAccessModule = false;
109

    
110
    private Vector unChangableAccessSubTreeVector = new Vector();
111

    
112
    private Stack currentUnchangableAccessModuleNodeStack = new Stack();
113

    
114
    private AccessSection topAccessSection;
115

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

    
120
    // vector stored the data file id which will be write into relation table
121
    private Vector onlineDataFileIdInRelationVector = new Vector();
122

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

    
127
    // Indicator of inline data
128
    private boolean handleInlineData = false;
129

    
130
    private Stack inlineDataNodeStack = null;
131

    
132
    private Hashtable inlineDataNameSpace = null;
133

    
134
    private FileWriter inlineDataFileWriter = null;
135

    
136
    private String inlineDataFileName = null;
137

    
138
    private int inLineDataIndex = 0;
139

    
140
    private Vector inlineFileIDList = new Vector();
141

    
142
    // Constant
143
    private static final String EML = "eml";
144

    
145
    private static final String DESCRIBES = "describes";
146

    
147
    private static final String ADDITIONALMETADATA = "additionalMetadata";
148

    
149
    private static final String ORDER = "order";
150

    
151
    private static final String ID = "id";
152

    
153
    private static final String REFERENCES = "references";
154

    
155
    public static final String INLINE = "inline";
156

    
157
    private static final String ONLINE = "online";
158

    
159
    private static final String URL = "url";
160

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

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

    
167
    private static final String TOPLEVEL = "top";
168

    
169
    private static final String SUBTREELEVEL = "subtree";
170

    
171
    private static final String RELATION = "Provides info for";
172

    
173
    private Logger logMetacat = Logger.getLogger(Eml210SAXHandler.class);   	   	
174

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

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

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

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

    
248
            }//while
249

    
250
        }//if
251

    
252
        return result;
253
    }
254

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

    
267
        try {
268

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

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

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

    
329
        DBSAXNode parentNode = null;
330
        DBSAXNode currentNode = null;
331

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

    
340
            //start handle inline data
341
            if (localName.equals(INLINE)) {
342
                handleInlineData = true;
343
                inLineDataIndex++;
344
                //intitialize namespace hash for in line data
345
                inlineDataNameSpace = new Hashtable();
346
                //initialize file writer
347
                String docidWithoutRev = MetaCatUtil.getDocIdFromString(docid);
348
                String seperator = ".";
349
                try {
350
                seperator = PropertyService.getProperty("document.accNumSeparator");
351
                } catch (PropertyNotFoundException pnfe) {
352
                	logMetacat.error("Could not fing property 'accNumSeparator'. " 
353
                			+ "Setting separator to '.': " + pnfe.getMessage());
354
                }
355
                // the new file name will look like docid.rev.2
356
                inlineDataFileName = docidWithoutRev + seperator + revision
357
                        + seperator + inLineDataIndex;
358
                inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
359
                // put the inline file id into a vector. If upload failed,
360
                // metacat will
361
                // delete the inline data file
362
                inlineFileIDList.add(inlineDataFileName);
363

    
364
            }
365

    
366
            // If hit a text node, we need write this text for current's parent
367
            // node
368
            // This will happend if the element is mixted
369
            if (hitTextNode && parentNode != null) {
370
                //compare text node data for unchangesubtree
371
                if (startCriticalSubTree) {
372
                    compareTextNode(currentUnChangedableSubtreeNodeStack,
373
                            textBuffer, PERMISSIONERROR);
374
                }//if
375

    
376
                //compare top level access module
377
                if (processTopLeverAccess && needCheckingAccessModule) {
378
                    compareTextNode(currentUnchangableAccessModuleNodeStack,
379
                            textBuffer, UPDATEACCESSERROR);
380
                }
381

    
382
                if (needCheckingAccessModule
383
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
384
                    // stored the pull out nodes into storedNode stack
385
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
386
                            null, null, MetaCatUtil.normalize(textBuffer
387
                                    .toString()));
388
                    storedAccessNodeStack.push(nodeElement);
389

    
390
                }
391

    
392
                // write the textbuffer into db for parent node.
393
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
394
                        parentNode);
395
                // rest hitTextNode
396
                hitTextNode = false;
397
                // reset textbuffer
398
                textBuffer = null;
399
                textBuffer = new StringBuffer();
400

    
401
            }
402

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

    
439
                    try {
440
                        // Get dbconnection
441
                        dbConn = DBConnectionPool
442
                                .getDBConnection("DBSAXHandler.startElement");
443
                        serialNumber = dbConn.getCheckOutSerialNumber();
444

    
445
                        Statement stmt = dbConn.createStatement();
446
                        ResultSet rs = stmt
447
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
448
                                        + "WHERE entry_type = 'Schema' "
449
                                        + "AND public_id = '" + doctype + "'");
450
                        boolean hasRow = rs.next();
451
                        if (hasRow) {
452
                            catalogid = rs.getString(1);
453
                        }
454
                        stmt.close();
455
                    }//try
456
                    finally {
457
                        // Return dbconnection
458
                        DBConnectionPool.returnDBConnection(dbConn,
459
                                serialNumber);
460
                    }//finally
461

    
462
                    //create documentImpl object by the constructor which can
463
                    // specify
464
                    //the revision
465
                    if (!super.getIsRevisionDoc())
466
                    {
467
                       currentDocument = new DocumentImpl(connection, rootNode
468
                            .getNodeID(), docname, doctype, docid, revision,
469
                            action, user, this.pub, catalogid, this.serverCode, 
470
                            createDate, updateDate);
471
                    }
472
                   
473
                } catch (Exception ane) {
474
                    throw (new SAXException(
475
                            "Error in EMLSaxHandler.startElement " + action,
476
                            ane));
477
                }
478
            }
479

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

    
498
            // Add all of the attributes
499
            for (int i = 0; i < atts.getLength(); i++) {
500
                String attributeName = atts.getQName(i);
501
                String attributeValue = atts.getValue(i);
502
                endNodeId = currentNode.setAttribute(attributeName,
503
                        attributeValue, docid);
504

    
505
                // To handle name space and schema location if the attribute
506
                // name is
507
                // xsi:schemaLocation. If the name space is in not in catalog
508
                // table
509
                // it will be regeistered.
510
                if (attributeName != null
511
                        && attributeName
512
                                .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
513
                    SchemaLocationResolver resolver = new SchemaLocationResolver(
514
                            attributeValue);
515
                    resolver.resolveNameSpace();
516

    
517
                } else if (attributeName != null && attributeName.equals(ID)) {
518

    
519
                    //check unchangedable subtree hash if contains this
520
                    // subtree id
521
                    if (unChangableSubTreeHash.containsKey(attributeValue)) {
522
                        // this subtree couldn't be changed by the user and
523
                        // move it from hash
524
                        SubTree currentUnChangedableSubtree = (SubTree) unChangableSubTreeHash
525
                                .remove(attributeValue);
526
                        currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree
527
                                .getSubTreeNodeStack();
528
                        startCriticalSubTree = true;
529
                        firstElementForCriticalSubTree = true;
530
                    }
531

    
532
                    // handle subtree info
533
                    SubTree subTress = new SubTree();
534
                    // set sub tree id
535
                    subTress.setSubTreeId(attributeValue);
536
                    // set sub tree sstart lement name
537
                    subTress.setStartElementName(currentNode.getTagName());
538
                    // set start node number
539
                    subTress.setStartNodeId(startNodeId);
540
                    // add to stack, but it didn't get end node id yet
541
                    subTreeInfoStack.push(subTress);
542

    
543
                }
544
            }//for
545

    
546
            // handle access stuff
547
            if (localName.equals(ACCESS)) {
548
                // if it is in addtionalmetacat
549
                if (parentNode.getTagName() == ADDITIONALMETADATA) {
550
                    processAdditionalAccess = true;
551

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

    
571
                }
572
                // create access object
573
                accessObject = new AccessSection();
574
                // set permission order
575
                String permOrder = currentNode.getAttribute(ORDER);
576
                accessObject.setPermissionOrder(permOrder);
577
                // set access id
578
                String accessId = currentNode.getAttribute(ID);
579
                accessObject.setSubTreeId(accessId);
580
                accessObject.setStartNodeId(startNodeId);
581
                accessObject.setDocId(docid);
582

    
583
                // load top level node stack to
584
                // currentUnchangableAccessModuleNodeStack
585
                if (processTopLeverAccess && needCheckingAccessModule) {
586
                    // get the node stack for
587
                    currentUnchangableAccessModuleNodeStack = topAccessSection
588
                            .getSubTreeNodeStack();
589
                }
590

    
591
            }
592
            // Set up a access rule for allow
593
            else if (parentNode.getTagName() != null
594
                    && (parentNode.getTagName()).equals(ACCESS)
595
                    && localName.equals(ALLOW)) {
596

    
597
                accessRule = new AccessRule();
598

    
599
                //set permission type "allow"
600
                accessRule.setPermissionType(ALLOW);
601

    
602
            }
603
            // set up an access rule for den
604
            else if (parentNode.getTagName() != null
605
                    && (parentNode.getTagName()).equals(ACCESS)
606
                    && localName.equals(DENY)) {
607
                accessRule = new AccessRule();
608
                //set permission type "allow"
609
                accessRule.setPermissionType(DENY);
610
            }
611

    
612
            // Add the node to the stack, so that any text data can be
613
            // added as it is encountered
614
            nodeStack.push(currentNode);
615
            // Add the node to the vector used by thread for writing XML Index
616
            nodeIndex.addElement(currentNode);
617

    
618
            // handle critical subtree
619
            if (startCriticalSubTree && firstElementForCriticalSubTree) {
620
                //store the element name
621
                firstElementNameForCriticalSubTree = qName;
622
                firstElementForCriticalSubTree = false;
623
            }//for first element
624

    
625
            // handle critical subtree
626
            if (startCriticalSubTree) {
627
                compareElementNameSpaceAttributes(
628
                        currentUnChangedableSubtreeNodeStack, namespaces, atts,
629
                        localName, PERMISSIONERROR);
630

    
631
            }
632
            //compare top access level module
633
            if (processTopLeverAccess && needCheckingAccessModule) {
634
                compareElementNameSpaceAttributes(
635
                        currentUnchangableAccessModuleNodeStack, namespaces,
636
                        atts, localName, UPDATEACCESSERROR);
637

    
638
            }
639

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

    
656
            }
657

    
658
            // reset name space
659
            namespaces = null;
660
            namespaces = new Hashtable();
661
        }//not inline data
662
        else {
663
            // we don't buffer the inline data in characters() method
664
            // so start character don't need to hand text node.
665

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

    
703
    }
704

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

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

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

    
782
        }//while
783

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

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

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

    
832
    }
833

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

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

    
907
    /** SAX Handler that is called at the end of each XML element */
908
    public void endElement(String uri, String localName, String qName)
909
            throws SAXException
910
    {
911
        logMetacat.info("End ELEMENT " + qName);
912

    
913
        if (localName.equals(INLINE) && handleInlineData) {
914
            // Get the node from the stack
915
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
916
            String currentTag = currentNode.getTagName();
917
            logMetacat.info("End of inline data");
918
            // close file writer
919
            try {
920
                inlineDataFileWriter.close();
921
                handleInlineData = false;
922
            } catch (IOException ioe) {
923
                throw new SAXException(ioe.getMessage());
924
            }
925

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

    
957
            }//if
958
            // write put inline data file name into text buffer (without path)
959
            textBuffer = new StringBuffer(inlineDataFileName);
960
            // write file name into db
961
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
962
                    currentNode);
963
            // reset textbuff
964
            textBuffer = null;
965
            textBuffer = new StringBuffer();
966
            return;
967
        }
968

    
969
        if (!handleInlineData) {
970
            // Get the node from the stack
971
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
972
            String currentTag = currentNode.getTagName();
973

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

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

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

    
1064
                }
1065
            }//if
1066

    
1067
            //end crtical subtree(user doesn't have permission to write)
1068
            //When reach the first element and stack is empty
1069
            if (localName.equals(firstElementNameForCriticalSubTree)
1070
                    && currentUnChangedableSubtreeNodeStack.isEmpty()) {
1071
                startCriticalSubTree = false;
1072
            }
1073

    
1074
            //set hitText false
1075
            hitTextNode = false;
1076
            // reset textbuff
1077
            textBuffer = null;
1078
            textBuffer = new StringBuffer();
1079

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

    
1095
            // access stuff
1096
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
1097
                // finish parser a ccess rule and assign it to new one
1098
                AccessRule newRule = accessRule;
1099
                //add the new rule to access section object
1100
                accessObject.addAccessRule(newRule);
1101
                // reset access rule
1102
                accessRule = null;
1103
            } else if (currentTag.equals(ACCESS)) {
1104
                // finish parse a access setction and assign it to new one
1105

    
1106
                accessObject.setEndNodeId(endNodeId);
1107
                AccessSection newAccessObject = accessObject;
1108

    
1109
                if (newAccessObject != null) {
1110

    
1111
                    // add the accessSection into a vector to store it
1112
                    // if it is not a reference, need to store it
1113
                    if (newAccessObject.getReferences() == null) {
1114

    
1115
                        newAccessObject
1116
                                .setStoredTmpNodeStack(storedAccessNodeStack);
1117
                        accessObjectList.add(newAccessObject);
1118
                    }
1119
                    if (processTopLeverAccess) {
1120

    
1121
                        // top level access control will handle whole document
1122
                        // -docid
1123
                        topLevelAccessControlMap.put(docid, newAccessObject);
1124
                        // reset processtopleveraccess tag
1125

    
1126
                    }//if
1127
                    else if (processAdditionalAccess) {
1128
                        // for additional control
1129
                        // put everything in describes value and access object
1130
                        // into hash
1131
                        for (int i = 0; i < describesId.size(); i++) {
1132

    
1133
                            String subId = (String) describesId.elementAt(i);
1134
                            if (subId != null) {
1135
                                additionalAccessControlMap.put(subId,
1136
                                        newAccessObject);
1137
                            }//if
1138
                        }//for
1139
                        // add this hashtable in to vector
1140

    
1141
                        additionalAccessMapList.add(additionalAccessControlMap);
1142
                        // reset this hashtable in order to store another
1143
                        // additional
1144
                        //accesscontrol
1145
                        additionalAccessControlMap = null;
1146
                        additionalAccessControlMap = new Hashtable();
1147
                    }//if
1148

    
1149
                }//if
1150
                //check if access node stack is empty after parsing top access
1151
                //module
1152

    
1153
                if (needCheckingAccessModule && processTopLeverAccess
1154
                        && !currentUnchangableAccessModuleNodeStack.isEmpty()) {
1155

    
1156
                    logMetacat.info(
1157
                            "Access node stack is not empty after "
1158
                                    + "parsing access subtree");
1159
                    throw new SAXException(UPDATEACCESSERROR);
1160

    
1161
                }
1162
                //reset access section object
1163

    
1164
                accessObject = null;
1165

    
1166
                // reset tmp stored node stack
1167
                storedAccessNodeStack = null;
1168
                storedAccessNodeStack = new Stack();
1169

    
1170
                // reset flag
1171
                processAdditionalAccess = false;
1172
                processTopLeverAccess = false;
1173
                processOtherAccess = false;
1174

    
1175
            } else if (currentTag.equals(ADDITIONALMETADATA)) {
1176
                //reset describesId
1177
                describesId = null;
1178
                describesId = new Vector();
1179
            }
1180
        } else {
1181
            // this is in inline part
1182
            StringBuffer endElement = new StringBuffer();
1183
            endElement.append("</");
1184
            endElement.append(qName);
1185
            endElement.append(">");
1186
            logMetacat.info("inline endElement: "
1187
                    + endElement.toString());
1188
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1189
        }
1190
    }
1191

    
1192
    /**
1193
     * SAX Handler that receives notification of comments in the DTD
1194
     */
1195
    public void comment(char[] ch, int start, int length) throws SAXException
1196
    {
1197
        logMetacat.info("COMMENT");
1198
        if (!handleInlineData) {
1199
            if (!processingDTD) {
1200
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1201
                String str = new String(ch, start, length);
1202

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

    
1222
                }
1223
            }
1224
        } else {
1225
            // inline data comment
1226
            StringBuffer inlineComment = new StringBuffer();
1227
            inlineComment.append("<!--");
1228
            inlineComment.append(new String(ch, start, length));
1229
            inlineComment.append("-->");
1230
            logMetacat.info("inline data comment: "
1231
                    + inlineComment.toString());
1232
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1233
        }
1234
    }
1235

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

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

    
1293
    /** SAX Handler that is called at the start of Namespace */
1294
    public void startPrefixMapping(String prefix, String uri)
1295
            throws SAXException
1296
    {
1297
        logMetacat.info("NAMESPACE");
1298
        if (!handleInlineData) {
1299
            namespaces.put(prefix, uri);
1300
        } else {
1301
            inlineDataNameSpace.put(prefix, uri);
1302
        }
1303
    }
1304

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

    
1323
            // This loop deals with the case where there are more characters
1324
            // than can fit in a single database text field (limit is
1325
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
1326
            // write a series of nodes that are MAXDATACHARS long, and then the
1327
            // final node contains the remainder
1328
            while (moredata) {
1329
                if (leftover > MAXDATACHARS) {
1330
                    data = new String(cbuf, offset, MAXDATACHARS);
1331
                    leftover -= MAXDATACHARS;
1332
                    offset += MAXDATACHARS;
1333
                } else {
1334
                    data = new String(cbuf, offset, leftover);
1335
                    moredata = false;
1336
                }
1337

    
1338
                //compare whitespace if need
1339
                if (startCriticalSubTree) {
1340
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1341
                            data, PERMISSIONERROR);
1342
                }//if
1343

    
1344
                //compare whitespace in access top module
1345
                if (processTopLeverAccess && needCheckingAccessModule) {
1346
                    compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1347
                            data, UPDATEACCESSERROR);
1348
                }
1349
                // Write the content of the node to the database
1350
                if (needCheckingAccessModule
1351
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1352
                    // stored the pull out nodes into storedNode stack
1353
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1354
                            null, null, MetaCatUtil.normalize(data));
1355
                    storedAccessNodeStack.push(nodeElement);
1356

    
1357
                }
1358
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1359
                        docid);
1360
            }
1361
        } else {
1362
            //This is inline data write to file directly
1363
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1364
                    start, len));
1365
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1366
        }
1367

    
1368
    }
1369

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

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

    
1421
    }
1422

    
1423
    /* The method to write all access rule into db */
1424
    private void writeAccessRuleToDB() throws SAXException
1425
    {
1426
        //Delete old permssion
1427
        deletePermissionsInAccessTable(docid);
1428
        //write top leve access rule
1429
        writeTopLevelAccessRuleToDB();
1430
        //write additional access rule
1431
        //writeAddtionalAccessRuleToDB();
1432
    }//writeAccessRuleToDB
1433

    
1434
    /* The method to write top level access rule into db. */
1435
    private void writeTopLevelAccessRuleToDB() throws SAXException
1436
    {
1437

    
1438
        // for top document level
1439
        Object accessSection = topLevelAccessControlMap.get(docid);
1440
        boolean top = true;
1441
        String subSectionId = null;
1442
        if (accessSection != null) {
1443
            AccessSection accessSectionObj = (AccessSection) accessSection;
1444

    
1445
            // if accessSection is not null and is not reference
1446
            if (accessSectionObj.getReferences() == null) {
1447
                // write the top level access module into xml_accesssubtree to
1448
                // store info
1449
                // and then when update to check if the user can update it or
1450
                // not
1451
                deleteAccessSubTreeRecord(docid);
1452
                writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1453

    
1454
                //write access section into xml_access table
1455
                writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1456
                // write online data file into xml_access too.
1457
                for (int i= 0; i <onlineDataFileIdInTopAccessVector.size(); i++)
1458
                {
1459
                  String id = (String)
1460
                               onlineDataFileIdInTopAccessVector.elementAt(i);
1461
                  writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1462
                }
1463

    
1464

    
1465
            } else {
1466

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

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

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

    
1534
        }//if
1535
        else {
1536
            // couldn't find a access section object
1537
            logMetacat.info(
1538
                    "couldn't find access control for document: " + docid);
1539
        }
1540

    
1541
    }//writeTopLevelAccessRuletoDB
1542

    
1543
    /* Given a subtree id and find the responding access section */
1544
    private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1545
    {
1546
        AccessSection result = null;
1547
        // Makse sure the id
1548
        if (id == null || id.equals("")) { return result; }
1549
        // go throught vector and find the list
1550
        for (int i = 0; i < unChangableAccessSubTreeVector.size(); i++) {
1551
            AccessSection accessObj = (AccessSection) unChangableAccessSubTreeVector
1552
                    .elementAt(i);
1553
            if (accessObj.getSubTreeId() != null
1554
                    && (accessObj.getSubTreeId()).equals(id)) {
1555
                result = accessObj;
1556
            }//if
1557
        }//for
1558
        return result;
1559
    }//getAccessSectionFromUnchangableAccessVector
1560

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

    
1592
        // now stack1 is empty and we should make sure stack2 is empty too
1593
        if (!stack2.isEmpty()) {
1594
            logMetacat.info(
1595
                    "stack2 still have some elements while stack "
1596
                            + "is empty! ");
1597
            throw new SAXException(UPDATEACCESSERROR);
1598
        }//if
1599
    }//comparingNodeStacks
1600

    
1601
    /* The method to write addtional access rule into db. */
1602
    private void writeAddtionalAccessRuleToDB() throws SAXException
1603
    {
1604

    
1605
        PreparedStatement pstmt = null;
1606
        boolean topLevel = false;
1607
        // go through the vector which contains the additional access control
1608
        //hashtable. Each hashtable has info for one additonalmetadata
1609
        // container
1610
        for (int j = 0; j < additionalAccessMapList.size(); j++) {
1611

    
1612
            Hashtable accessControlMap = (Hashtable) additionalAccessMapList
1613
                    .elementAt(j);
1614
            // additional access rule
1615
            Enumeration en = accessControlMap.keys();
1616

    
1617
            while (en.hasMoreElements()) {
1618
                try {
1619
                    // Get subsection id
1620
                    String subSectionId = (String) en.nextElement();
1621
                    logMetacat.info(
1622
                            "sub section id in additional access mapping"
1623
                                    + "(go through): " + subSectionId);
1624

    
1625
                    if (subSectionId == null) {
1626
                    // if id is null, terminate the program
1627
                    throw new SAXException("subtree id is null"); }
1628
                    // Get AccessSection Object
1629
                    Object accessSectionObj = accessControlMap
1630
                            .get(subSectionId);
1631
                    if (accessSectionObj == null) {
1632
                        // if accesssection is null, terminate the program
1633
                        throw new SAXException("access subtree is null");
1634
                    } else {
1635
                        AccessSection accessControlObj = (AccessSection) accessSectionObj;
1636
                        // if the access section is not references, write it to
1637
                        // db
1638
                        if (accessControlObj.getReferences() == null) {
1639
                            writeGivenAccessRuleIntoDB(accessControlObj,
1640
                                    topLevel, subSectionId);
1641
                        } else {
1642
                            // this is a reference and go trough the vector
1643
                            // which contains all
1644
                            // access object
1645
                            String referenceId = accessControlObj
1646
                                    .getReferences();
1647

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

    
1677
                    logMetacat.error(
1678
                            "error in EmlSAXHandler.writeAddtionalAccess"
1679
                                    + ": " + e.getMessage());
1680
                    throw new SAXException(e.getMessage());
1681
                }
1682
            }//while
1683
        }//for
1684
    }//writeAccessRuletoDB
1685

    
1686
    /* Write a gaven access rule into db */
1687
    private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1688
            boolean topLevel, String subSectionId) throws SAXException
1689
    {
1690
        if (accessSection == null) { throw new SAXException(
1691
                "The access object is null"); }
1692

    
1693
        String permOrder = accessSection.getPermissionOrder();
1694
        String sql = null;
1695
        PreparedStatement pstmt = null;
1696
        if (topLevel) {
1697
            sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1698
                    + "perm_type, perm_order, accessfileid) VALUES "
1699
                    + " (?, ?, ?, ?, ?, ?)";
1700
        } else {
1701
            sql = "INSERT INTO xml_access (docid,principal_name, "
1702
                    + "permission, perm_type, perm_order, accessfileid, subtreeid, "
1703
                    + " startnodeid, endnodeid) VALUES"
1704
                    + " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1705
        }
1706
        try {
1707

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

    
1747
            }
1748

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

    
1787
    }//writeGivenAccessRuleIntoDB
1788

    
1789
    /* Write a gaven access rule into db */
1790
    private void writeAccessRuleForRalatedDataFileIntoDB(
1791
            AccessSection accessSection, String dataId) throws SAXException
1792
    {
1793
        if (accessSection == null) { throw new SAXException(
1794
                "The access object is null"); }
1795
        // get rid of rev from dataId
1796
        //dataId = MetaCatUtil.getDocIdFromString(dataId);
1797
        String permOrder = accessSection.getPermissionOrder();
1798
        String sql = null;
1799
        PreparedStatement pstmt = null;
1800
        sql = "INSERT INTO xml_access (docid, principal_name, permission, "
1801
                + "perm_type, perm_order, accessfileid) VALUES "
1802
                + " (?, ?, ?, ?, ?, ?)";
1803

    
1804
        try {
1805

    
1806
            pstmt = connection.prepareStatement(sql);
1807
            // Increase DBConnection usage count
1808
            connection.increaseUsageCount(1);
1809
            // Bind the values to the query
1810
            pstmt.setString(1, dataId);
1811
            logMetacat.info("Docid in accesstable: " + docid);
1812
            pstmt.setString(6, docid);
1813
            logMetacat.info("Accessfileid in accesstable: " + docid);
1814
            pstmt.setString(5, permOrder);
1815
            logMetacat.info("PermOder in accesstable: " + permOrder);
1816
            // if it is not top level, set subsection id
1817

    
1818
            Vector accessRules = accessSection.getAccessRules();
1819
            // go through every rule
1820
            for (int i = 0; i < accessRules.size(); i++) {
1821
                AccessRule rule = (AccessRule) accessRules.elementAt(i);
1822
                String permType = rule.getPermissionType();
1823
                int permission = rule.getPermission();
1824
                pstmt.setInt(3, permission);
1825
                logMetacat.info("permission in accesstable: "
1826
                        + permission);
1827
                pstmt.setString(4, permType);
1828
                logMetacat.info(
1829
                        "Permtype in accesstable: " + permType);
1830
                // go through every principle in rule
1831
                Vector nameVector = rule.getPrincipal();
1832
                for (int j = 0; j < nameVector.size(); j++) {
1833
                    String prName = (String) nameVector.elementAt(j);
1834
                    pstmt.setString(2, prName);
1835
                    logMetacat.info("Principal in accesstable: "
1836
                            + prName);
1837
                    logMetacat.debug("running sql: " + pstmt.toString());
1838
                    pstmt.execute();
1839
                }//for
1840
            }//for
1841
            pstmt.close();
1842
        }//try
1843
        catch (SQLException e) {
1844
            throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1845
                    + e.getMessage());
1846
        }//catch
1847
        finally {
1848
            try {
1849
                pstmt.close();
1850
            } catch (SQLException ee) {
1851
                throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1852
                        + ee.getMessage());
1853
            }
1854
        }//finally
1855

    
1856
    }//writeAccessRuleForRalatedDataFileIntoDB
1857

    
1858
    /* Delete from db all permission for resources related to @aclid if any. */
1859
    private void deletePermissionsInAccessTable(String aclid)
1860
            throws SAXException
1861
    {
1862
        Statement stmt = null;
1863
        try {
1864
            // delete all acl records for resources related to @aclid if any
1865
            stmt = connection.createStatement();
1866
            // Increase DBConnection usage count
1867
            connection.increaseUsageCount(1);
1868
            logMetacat.debug("running sql: DELETE FROM xml_access WHERE accessfileid = '"
1869
                    + aclid + "'");
1870
            stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
1871
                    + aclid + "'");
1872

    
1873
        } catch (SQLException e) {
1874
            throw new SAXException(e.getMessage());
1875
        } finally {
1876
            try {
1877
                stmt.close();
1878
            } catch (SQLException ee) {
1879
                throw new SAXException(ee.getMessage());
1880
            }
1881
        }
1882
    }//deletePermissionsInAccessTable
1883

    
1884
    /*
1885
     * In order to make sure only usr has "all" permission can update access
1886
     * subtree in eml document we need to keep access subtree info in
1887
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1888
     */
1889
    private void writeAccessSubTreeIntoDB(AccessSection accessSection,
1890
            String level) throws SAXException
1891
    {
1892
        if (accessSection == null) { throw new SAXException(
1893
                "The access object is null"); }
1894

    
1895
        String sql = null;
1896
        PreparedStatement pstmt = null;
1897
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1898
                + "subtreeid, startnodeid, endnodeid) VALUES "
1899
                + " (?, ?, ?, ?, ?, ?)";
1900
        try {
1901

    
1902
            pstmt = connection.prepareStatement(sql);
1903
            // Increase DBConnection usage count
1904
            connection.increaseUsageCount(1);
1905
            long startNodeId = accessSection.getStartNodeId();
1906
            long endNodeId = accessSection.getEndNodeId();
1907
            String sectionId = accessSection.getSubTreeId();
1908
            // Bind the values to the query
1909
            pstmt.setString(1, docid);
1910
            logMetacat.info("Docid in access-subtreetable: " + docid);
1911
            pstmt.setString(2, revision);
1912
            logMetacat.info("rev in accesssubtreetable: " + revision);
1913
            pstmt.setString(3, level);
1914
            logMetacat.info("contorl level in access-subtree table: "
1915
                    + level);
1916
            pstmt.setString(4, sectionId);
1917
            logMetacat.info("Subtree id in access-subtree table: "
1918
                    + sectionId);
1919
            pstmt.setLong(5, startNodeId);
1920
            logMetacat.info("Start node id is: " + startNodeId);
1921
            pstmt.setLong(6, endNodeId);
1922
            logMetacat.info("End node id is: " + endNodeId);
1923
            logMetacat.debug("running sql: " + pstmt.toString());
1924
            pstmt.execute();
1925
            pstmt.close();
1926
        }//try
1927
        catch (SQLException e) {
1928
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1929
                    + e.getMessage());
1930
        }//catch
1931
        finally {
1932
            try {
1933
                pstmt.close();
1934
            } catch (SQLException ee) {
1935
                throw new SAXException(
1936
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1937
                                + ee.getMessage());
1938
            }
1939
        }//finally
1940

    
1941
    }//writeAccessSubtreeIntoDB
1942

    
1943
    /* Delete every access subtree record from xml_accesssubtree. */
1944
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
1945
    {
1946
        Statement stmt = null;
1947
        try {
1948
            // delete all acl records for resources related to @aclid if any
1949
            stmt = connection.createStatement();
1950
            // Increase DBConnection usage count
1951
            connection.increaseUsageCount(1);
1952
            logMetacat.debug("running sql: DELETE FROM xml_accesssubtree WHERE docid = '"
1953
                    + docId + "'");
1954
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
1955
                    + docId + "'");
1956

    
1957
        } catch (SQLException e) {
1958
            throw new SAXException(e.getMessage());
1959
        } finally {
1960
            try {
1961
                stmt.close();
1962
            } catch (SQLException ee) {
1963
                throw new SAXException(ee.getMessage());
1964
            }
1965
        }
1966
    }//deleteAccessSubTreeRecord
1967

    
1968
    // open a file writer for writing inline data to file
1969
    private FileWriter createInlineDataFileWriter(String fileName)
1970
            throws SAXException
1971
    {
1972
        FileWriter writer = null;
1973
        String path;
1974
        try {
1975
        	path = PropertyService.getProperty("application.inlinedatafilepath");
1976
        } catch (PropertyNotFoundException pnfe) {
1977
        	throw new SAXException(pnfe.getMessage());
1978
        }
1979
        /*
1980
         * File inlineDataDirectory = new File(path);
1981
         */
1982
        String newFile = path + "/" + fileName;
1983
        logMetacat.info("inline file name: " + newFile);
1984
        try {
1985
            // true means append
1986
            writer = new FileWriter(newFile, true);
1987
        } catch (IOException ioe) {
1988
            throw new SAXException(ioe.getMessage());
1989
        }
1990
        return writer;
1991
    }
1992

    
1993
    // write inline data into file system and return file name(without path)
1994
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
1995
            throws SAXException
1996
    {
1997
        try {
1998
            writer.write(data.toString());
1999
            writer.flush();
2000
        } catch (Exception e) {
2001
            throw new SAXException(e.getMessage());
2002
        }
2003
    }
2004

    
2005
    /*
2006
     * In eml2, the inline data wouldn't store in db, it store in file system
2007
     * The db stores file name(without path). We got the old file name from db
2008
     * and compare to the new in line data file
2009
     */
2010
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2011
            throws McdbException
2012
    {
2013
        // this method need to be testing
2014
        boolean same = true;
2015
        String data = null;
2016
        try {
2017
        	String path = PropertyService.getProperty("application.inlinedatafilepath");
2018
			// the new file name will look like path/docid.rev.2
2019
			File inlineDataDirectory = new File(path);
2020
			File oldDataFile = new File(inlineDataDirectory, oldFileName);
2021
			File newDataFile = new File(inlineDataDirectory, newFileName);
2022

    
2023
            FileReader oldFileReader = new FileReader(oldDataFile);
2024
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2025
            FileReader newFileReader = new FileReader(newDataFile);
2026
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2027
            // read first line of data
2028
            String oldString = oldStringReader.readLine();
2029
            String newString = newStringReader.readLine();
2030

    
2031
            // at the end oldstring will be null
2032
            while (oldString != null) {
2033
                oldString = oldStringReader.readLine();
2034
                newString = newStringReader.readLine();
2035
                if (!oldString.equals(newString)) {
2036
                    same = false;
2037
                    break;
2038
                }
2039
            }
2040

    
2041
            // if oldString is null but newString is not null, they are same
2042
            if (same) {
2043
                if (newString != null) {
2044
                    same = false;
2045
                }
2046
            }
2047

    
2048
        } catch (Exception e) {
2049
            throw new McdbException(e.getMessage());
2050
        }
2051
        logMetacat.info("the inline data retrieve from file: " + data);
2052
        return same;
2053
    }
2054

    
2055
    // if xml file failed to upload, we need to call this method to delete
2056
    // the inline data already in file system
2057
    public void deleteInlineFiles() throws SAXException
2058
    {
2059
        if (!inlineFileIDList.isEmpty()) {
2060
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2061
                String fileName = (String) inlineFileIDList.elementAt(i);
2062
                deleteInlineDataFile(fileName);
2063
            }
2064
        }
2065
    }
2066

    
2067
    /* delete the inline data file */
2068
    private void deleteInlineDataFile(String fileName) throws SAXException
2069
    {
2070
    	String path;
2071
    	try {
2072
        	path = PropertyService.getProperty("application.inlinedatafilepath");
2073
    	} catch (PropertyNotFoundException pnfe) {
2074
    		throw new SAXException ("Could not find inline data file path: " 
2075
    				+ pnfe.getMessage());
2076
    	}
2077
        File inlineDataDirectory = new File(path);
2078
        File newFile = new File(inlineDataDirectory, fileName);
2079
        newFile.delete();
2080

    
2081
    }
2082

    
2083
    /*
2084
	 * In eml2, the inline data wouldn't store in db, it store in file system
2085
	 * The db stores file name(without path).
2086
	 */
2087
	public static Reader readInlineDataFromFileSystem(String fileName)
2088
			throws McdbException {
2089
		// BufferedReader stringReader = null;
2090
		FileReader fileReader = null;
2091
		try {
2092
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2093
			// the new file name will look like path/docid.rev.2
2094
			File inlineDataDirectory = new File(path);
2095
			File dataFile = new File(inlineDataDirectory, fileName);
2096

    
2097
			fileReader = new FileReader(dataFile);
2098
			// stringReader = new BufferedReader(fileReader);
2099
		} catch (Exception e) {
2100
			throw new McdbException(e.getMessage());
2101
		}
2102
		// return stringReader;
2103
		return fileReader;
2104
	}
2105

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

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

    
2171
    }//writeOnlineDataFileIdIntoRelationTable
2172

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

    
2202
          if (!AccessionNumber.accNumberUsed(docid))
2203
          {
2204
            onlineDataFileIdInTopAccessVector.add(docid);
2205
          }
2206
          PermissionController controller = new
2207
              PermissionController(accessionNumber);
2208
          if (controller.hasPermission(
2209
              user, groups, AccessControlInterface.ALLSTRING))
2210
          {
2211
            onlineDataFileIdInTopAccessVector.add(docid);
2212
          }
2213
        }//try
2214
        catch(Exception e)
2215
        {
2216
          logMetacat.error("Eorr in " +
2217
                                "Eml210SAXHanlder.handleOnlineUrlDataFile is " +
2218
                                 e.getMessage());
2219
          throw new SAXException(e.getMessage());
2220
        }
2221
      }
2222
    }
2223

    
2224
}
(36-36/67)