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

    
29
package edu.ucsb.nceas.metacat;
30

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

    
48
import org.xml.sax.Attributes;
49
import org.xml.sax.SAXException;
50

    
51
/**
52
 * A database aware Class implementing callback bethods for the SAX parser to
53
 * call when processing the XML stream and generating events
54
 * Here is the rules for user which has write permission in top level access
55
 * rules(he can update metadata but can't update access module) try to update
56
 * a document:
57
 * 1. Checking access part (both in top level and addtional level, node by node)
58
 *    If something was modified, reject the document. Note: for additional part
59
 *    The access subtree startnode starts at "<describ>" rather than <access>.
60
 *    This is because make sure ids wouldn't be mess up by user.
61
 * 2. Checking ids in additional access part, if they points a distribution
62
 *    module with online or inline. If some ids don't, reject the documents.
63
 * 3. For inline distribution:
64
 *    If user can't read the inline data, the empty string in inline element
65
 *    will be send to user if he read this eml document(user has read access
66
 *    at top level - metadata, but user couldn't read inline data).
67
 *    Here is some intrested senario: If user does have read and write
68
 *    permission in top level access rules(for metadata)
69
 *    but 1) user doesn't have read and write permission in inline data block,
70
 *    so if user update the document with some inline data rather than
71
 *    empty string in same inline data block(same distribution inline id),
72
 *    this means user updated the inline data. So the document should be
73
 *    rejected.
74
 *    2) user doesn't have read permssion, but has write premission in
75
 *    inline data block. If user send back inline data block with empty
76
 *    string, we will think user doesn't update inline data and we will
77
 *    copy old inline data back to the new one. If user send something
78
 *    else, we will overwrite the old inline data by new one.
79
 * 4. For online distribution:
80
 *    It is easy than inline distribution. When the user try to change a external
81
 *    document id, we will checking if the user have "all" permission to it.
82
 *    If don't have, reject the document. If have, delete the old rules and apply
83
 *    The new rules.
84
 *
85
 *
86
 * Here is some info about addtional access rules ( data object rules):
87
 *  The data access rules format looks like:
88
 *  <additionalMetadata>
89
 *    <describes>100</describes>
90
 *    <describes>300</describes>
91
 *    <access>rulesone</access>
92
 *  </additionalMetadata>
93
 *  <additionalMetadata>
94
 *    <describes>200</describes>
95
 *    <access>rulesthree</access>
96
 *  </additionalMetadata>
97
 *  Because eml additionalMetadata is (describes+, any) and any ocurrence is 1.
98
 *  So following xml will be rejected by xerces.
99
 *  <additionalMetadata>
100
 *    <describes>100</describes>
101
 *    <describes>300</describes>
102
 *    <other>....</other>
103
 *    <access>rulesone</access>
104
 *  </additionalMetadata>
105
 */
106
public class Eml200SAXHandler extends DBSAXHandler implements
107
        AccessControlInterface
108
{
109
    private boolean processTopLeverAccess = false;
110

    
111
    // now additionalAccess will be explained as distribution access control
112
    // - data file
113
    private boolean processAdditionalAccess = false;
114

    
115
    private boolean processOtherAccess = false;
116

    
117
    private AccessSection accessObject = null;
118

    
119
    private AccessRule accessRule = null;
120

    
121
    private Vector describesId = new Vector(); // store the ids in
122
                                               //additionalmetadata/describes
123

    
124
    //store all distribution element id for online url. key is the distribution
125
    // id and  data  is url
126
    private Hashtable onlineURLDistributionIdList = new Hashtable();
127
    // distribution/oneline/url will store this vector if distribution doesn't
128
    // have a id.
129
    private Vector onelineURLDistributionListWithoutId = new Vector();
130

    
131
    //store all distribution element id for online other distribution, such as
132
    // connection or connectiondefination. key is the distribution id
133
    // and  data  is distribution id
134
    private Hashtable onlineOtherDistributionIdList = new Hashtable();
135

    
136
    //store all distribution element id for inline data.
137
    // key is the distribution id, data is the internal inline id
138
    private Hashtable inlineDistributionIdList = new Hashtable();
139

    
140
    //store all distribution element id for off line data.
141
    // key is the distribution id, data is the id too.
142
    private Hashtable offlineDistributionIdList = new Hashtable();
143

    
144
    // a hash to stored all distribution id, both key and value are id itself
145
    private Hashtable distributionAllIdList = new Hashtable();
146

    
147
    // temporarily store distribution id
148
    private String distributionId = null;
149

    
150
    // flag to indicate to handle distrubiton
151
    private boolean proccessDistribution = false;
152

    
153
    // a hash table to stored the distribution which is a reference and this
154
    // distribution has a id too. The key is itself id of this distribution,
155
    // the value is the referenced id.
156
    // So, we only stored the format like this:
157
    // <distribution id ="100"><reference>300</reference></distribution>
158
    // the reason is:
159
    // if not id in distribution, then the distribution couldn't be added
160
    // to additional access module. The distribution block which was referenced
161
    // id (300) will be stored in above distribution lists.
162
    private Hashtable distributionReferenceList = new Hashtable();
163

    
164
    private boolean needCheckingAccessModule = false;
165

    
166
    private AccessSection unChangebleTopAccessSubTree = null;
167

    
168
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
169

    
170
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
171

    
172
    private AccessSection topAccessSection;
173

    
174
    private Vector addtionalAccessVector = new Vector();
175

    
176
    // key is subtree id and value is accessSection object
177
    private Hashtable possibleReferencedAccessHash = new Hashtable();
178

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

    
183
    // vector stored the data file id which will be write into relation table
184
    private Vector onlineDataFileIdInRelationVector = new Vector();
185

    
186
    // Indicator of inline data
187
    private boolean handleInlineData = false;
188

    
189
    private Hashtable inlineDataNameSpace = null;
190

    
191
    private FileWriter inlineDataFileWriter = null;
192

    
193
    private String inlineDataFileName = null;
194

    
195
    private int inLineDataIndex = 0;
196

    
197
    private Vector inlineFileIDList = new Vector();
198

    
199
    private boolean inAddtionalMetaData = false;
200

    
201
    //user has unwritable inline data object when it updates a document
202
    private boolean unWritableInlineDataObject = false;
203
    //user has unreadable inline data when it updates a dcoument
204
    private boolean unReadableInlineDataObject = false;
205

    
206
    // the hashtable contains the info from xml_access table which
207
    // inline data the user can't read when user update a document.
208
    // The key in hashtable is subtree id and data is the inline data internal
209
    // file name.
210

    
211
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
212

    
213
    // the hashtable contains the info from xml_access table which
214
    // inline data the user can't write when user update a document.
215
    // The key in hashtable is subtree id and data is the inline data internal
216
    // file name.
217
    private Hashtable previousUnwritableInlineDataObjectHash = new Hashtable();
218

    
219
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
220

    
221
    //This hashtable will stored the id which already has additional access
222
    // control. So the top level access control will ignore them.
223
    private Hashtable onlineURLIdHasAddtionalAccess   = new Hashtable();
224

    
225
    // additional access module will be in additionalMetadata part. Its format
226
    // look like
227
    //<additionalMetadata>
228
    //   <describes>100</describes>
229
    //   <describes>300</describes>
230
    //   <access>rulesone</access>
231
    //</additionalMetadata>
232
    // If user couldn't have all permission to update access rules, he/she could
233
    // not update access module, but also couldn't update "describes".
234
    // So the start node id for additional access section is the first describes
235
    // element
236
    private boolean firstDescribesInAdditionalMetadata = true;
237
    private long    firstDescribesNodeId               = -1;
238

    
239
    private int numberOfHitUnWritableInlineData = 0;
240

    
241
    // Constant
242
    private static final String EML = "eml";
243

    
244
    private static final String DESCRIBES = "describes";
245

    
246
    private static final String ADDITIONALMETADATA = "additionalMetadata";
247

    
248
    private static final String ORDER = "order";
249

    
250
    private static final String ID = "id";
251

    
252
    private static final String REFERENCES = "references";
253

    
254
    public static final String INLINE = "inline";
255

    
256
    private static final String ONLINE = "online";
257

    
258
    private static final String OFFLINE = "offline";
259

    
260
    private static final String CONNECTION = "connection";
261

    
262
    private static final String CONNECTIONDEFINITION = "connectionDefinition";
263

    
264
    private static final String URL = "url";
265

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

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

    
272
    public static final String TOPLEVEL = "top";
273

    
274
    public static final String DATAACCESSLEVEL = "dataAccess";
275

    
276
    // this level is for the access module which is not in top or additional
277
    // place, but it was referenced by top or additional
278
    private static final String REFERENCEDLEVEL = "referenced";
279

    
280
    private static final String RELATION = "Provides info for";
281

    
282
    private static final String DISTRIBUTION = "distribution";
283

    
284
    /**
285
     * Construct an instance of the handler class In this constructor, user can
286
     * specify the version need to upadate
287
     *
288
     * @param conn the JDBC connection to which information is written
289
     * @param action - "INSERT" or "UPDATE"
290
     * @param docid to be inserted or updated into JDBC connection
291
     * @param revision, the user specified the revision need to be update
292
     * @param user the user connected to MetaCat servlet and owns the document
293
     * @param groups the groups to which user belongs
294
     * @param pub flag for public "read" access on document
295
     * @param serverCode the serverid from xml_replication on which this
296
     *            document resides.
297
     *
298
     */
299
    public Eml200SAXHandler(DBConnection conn, String action, String docid,
300
            String revision, String user, String[] groups, String pub,
301
            int serverCode) throws SAXException
302
    {
303
        super(conn, action, docid, revision, user, groups, pub, serverCode);
304
        // Get the unchangable subtrees (user doesn't have write permission)
305
        try
306
        {
307
            PermissionController control = new PermissionController(docid
308
                    + MetaCatUtil.getOption("accNumSeparator") + revision);
309
            //unChangableSubTreeHash = getUnchangableSubTree(control, user,
310
            // groups);
311

    
312
            //If the action is update and user doesn't have "ALL" permission
313
            // we need to check if user update access subtree
314
            if (action != null && action.equals("UPDATE")
315
                    && !control.hasPermission(user, groups,
316
                            AccessControlInterface.ALLSTRING))
317
            {
318
                needCheckingAccessModule = true;
319
                unChangebleTopAccessSubTree = getTopAccessSubTreeFromDB();
320
                unChangebleAdditionalAccessSubTreeVector =
321
                                         getAdditionalAccessSubTreeListFromDB();
322
                unChangebleReferencedAccessSubTreeHash =
323
                                         getReferencedAccessSubTreeListFromDB();
324
            }
325

    
326
            //Here is for  data object checking.
327
            if (action != null && action.equals("UPDATE"))
328
            {
329
              //info about inline data object which user doesn't have read
330
              //permission the info come from xml_access table
331
              previousUnreadableInlineDataObjectHash = PermissionController.
332
                            getUnReadableInlineDataIdList(docid, user,
333
                                                          groups, true);
334

    
335
              //info about data object which user doesn't have write permission
336
              // the info come from xml_accesss table
337
              previousUnwritableInlineDataObjectHash = PermissionController.
338
                            getUnWritableInlineDataIdList(docid, user,
339
                                                          groups, true);
340

    
341
            }
342

    
343

    
344
        }
345
        catch (Exception e)
346
        {
347
            MetaCatUtil.debugMessage("erorr in Eml200SAXHanlder is "
348
                                     +e.getMessage(), 30);
349
            throw new SAXException(e.getMessage());
350
        }
351
    }
352

    
353
    /*
354
     * Get the top level access subtree info from xml_accesssubtree table.
355
     * If no top access subtree found, null will be return.
356
     */
357
     private AccessSection getTopAccessSubTreeFromDB()
358
                                                       throws SAXException
359
     {
360
       AccessSection topAccess = null;
361
       PreparedStatement pstmt = null;
362
       ResultSet rs = null;
363
       String sql = "SELECT subtreeid, startnodeid, endnodeid "
364
                + "FROM xml_accesssubtree WHERE docid like ? "
365
                + "AND controllevel like ?";
366

    
367

    
368
       try
369
       {
370
            pstmt = connection.prepareStatement(sql);
371
            // Increase DBConnection usage count
372
            connection.increaseUsageCount(1);
373
            // Bind the values to the query
374
            pstmt.setString(1, docid);
375
            pstmt.setString(2, TOPLEVEL);
376
            pstmt.execute();
377

    
378
            // Get result set
379
            rs = pstmt.getResultSet();
380
            if (rs.next())
381
            {
382
                String sectionId = rs.getString(1);
383
                long startNodeId = rs.getLong(2);
384
                long endNodeId = rs.getLong(3);
385
                // create a new access section
386
                topAccess = new AccessSection();
387
                topAccess.setControlLevel(TOPLEVEL);
388
                topAccess.setDocId(docid);
389
                topAccess.setSubTreeId(sectionId);
390
                topAccess.setStartNodeId(startNodeId);
391
                topAccess.setEndNodeId(endNodeId);
392
            }
393
            pstmt.close();
394
        }//try
395
        catch (SQLException e)
396
        {
397
            throw new SAXException(
398
                    "EMLSAXHandler.getTopAccessSubTreeFromDB(): "
399
                            + e.getMessage());
400
        }//catch
401
        finally
402
        {
403
            try
404
            {
405
                pstmt.close();
406
            }
407
            catch (SQLException ee)
408
            {
409
                throw new SAXException(
410
                        "EMLSAXHandler.getTopAccessSubTreeFromDB(): "
411
                                + ee.getMessage());
412
            }
413
        }//finally
414
        return topAccess;
415

    
416
     }
417

    
418
    /*
419
     * Get the subtree node info from xml_accesssubtree table
420
     */
421
    private Vector getAdditionalAccessSubTreeListFromDB() throws Exception
422
    {
423
        Vector result = new Vector();
424
        PreparedStatement pstmt = null;
425
        ResultSet rs = null;
426
        String sql = "SELECT subtreeid, startnodeid, endnodeid "
427
                + "FROM xml_accesssubtree WHERE docid like ? "
428
                + "AND controllevel like ? "
429
                + "ORDER BY startnodeid ASC";
430

    
431
        try
432
        {
433

    
434
            pstmt = connection.prepareStatement(sql);
435
            // Increase DBConnection usage count
436
            connection.increaseUsageCount(1);
437
            // Bind the values to the query
438
            pstmt.setString(1, docid);
439
            pstmt.setString(2, DATAACCESSLEVEL);
440
            pstmt.execute();
441

    
442
            // Get result set
443
            rs = pstmt.getResultSet();
444
            while (rs.next())
445
            {
446
                String sectionId = rs.getString(1);
447
                long startNodeId = rs.getLong(2);
448
                long endNodeId = rs.getLong(3);
449
                // create a new access section
450
                AccessSection accessObj = new AccessSection();
451
                accessObj.setControlLevel(DATAACCESSLEVEL);
452
                accessObj.setDocId(docid);
453
                accessObj.setSubTreeId(sectionId);
454
                accessObj.setStartNodeId(startNodeId);
455
                accessObj.setEndNodeId(endNodeId);
456
                // add this access obj into vector
457
                result.add(accessObj);
458

    
459
            }
460
            pstmt.close();
461
        }//try
462
        catch (SQLException e)
463
        {
464
            throw new SAXException(
465
                    "EMLSAXHandler.getAddtionalAccessSubTreeListFromDB(): "
466
                            + e.getMessage());
467
        }//catch
468
        finally
469
        {
470
            try
471
            {
472
                pstmt.close();
473
            }
474
            catch (SQLException ee)
475
            {
476
                throw new SAXException(
477
                        "EMLSAXHandler.getAccessSubTreeListFromDB(): "
478
                                + ee.getMessage());
479
            }
480
        }//finally
481
        return result;
482
    }
483

    
484
   /*
485
    * Get the access subtree for referenced info from xml_accesssubtree table
486
    */
487
   private Hashtable getReferencedAccessSubTreeListFromDB() throws Exception
488
   {
489
       Hashtable result = new Hashtable();
490
       PreparedStatement pstmt = null;
491
       ResultSet rs = null;
492
       String sql = "SELECT subtreeid, startnodeid, endnodeid "
493
               + "FROM xml_accesssubtree WHERE docid like ? "
494
               + "AND controllevel like ? "
495
               + "ORDER BY startnodeid ASC";
496

    
497
       try
498
       {
499

    
500
           pstmt = connection.prepareStatement(sql);
501
           // Increase DBConnection usage count
502
           connection.increaseUsageCount(1);
503
           // Bind the values to the query
504
           pstmt.setString(1, docid);
505
           pstmt.setString(2, REFERENCEDLEVEL);
506
           pstmt.execute();
507

    
508
           // Get result set
509
           rs = pstmt.getResultSet();
510
           while (rs.next())
511
           {
512
               String sectionId = rs.getString(1);
513
               long startNodeId = rs.getLong(2);
514
               long endNodeId = rs.getLong(3);
515
               // create a new access section
516
               AccessSection accessObj = new AccessSection();
517
               accessObj.setControlLevel(DATAACCESSLEVEL);
518
               accessObj.setDocId(docid);
519
               accessObj.setSubTreeId(sectionId);
520
               accessObj.setStartNodeId(startNodeId);
521
               accessObj.setEndNodeId(endNodeId);
522
               // add this access obj into hastable
523
               if ( sectionId != null && !sectionId.trim().equals(""))
524
               {
525
                 result.put(sectionId, accessObj);
526
               }
527

    
528
           }
529
           pstmt.close();
530
       }//try
531
       catch (SQLException e)
532
       {
533
           throw new SAXException(
534
                   "EMLSAXHandler.getReferencedAccessSubTreeListFromDB(): "
535
                           + e.getMessage());
536
       }//catch
537
       finally
538
       {
539
           try
540
           {
541
               pstmt.close();
542
           }
543
           catch (SQLException ee)
544
           {
545
               throw new SAXException(
546
                       "EMLSAXHandler.getReferencedSubTreeListFromDB(): "
547
                               + ee.getMessage());
548
           }
549
       }//finally
550
       return result;
551
   }
552

    
553

    
554

    
555
    /** SAX Handler that is called at the start of each XML element */
556
    public void startElement(String uri, String localName, String qName,
557
            Attributes atts) throws SAXException
558
    {
559
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
560
        // for element <acl....> both qname and local name is "eml"
561
        // uri is namesapce
562
        MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 10);
563
        MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 10);
564
        MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 10);
565

    
566
        DBSAXNode parentNode = null;
567
        DBSAXNode currentNode = null;
568
        // none inline part
569
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
570
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
571
        if (!handleInlineData)
572
        {
573
            // Get a reference to the parent node for the id
574
            try
575
            {
576
                parentNode = (DBSAXNode) nodeStack.peek();
577
            }
578
            catch (EmptyStackException e)
579
            {
580
                parentNode = null;
581
            }
582

    
583
            //start handle inline data
584
            //=====================================================
585
            if (qName.equals(INLINE) && !inAddtionalMetaData)
586
            {
587
                handleInlineData = true;
588
                inLineDataIndex++;
589
                //intitialize namespace hash for in line data
590
                inlineDataNameSpace = new Hashtable();
591
                //initialize file writer
592
                String docidWithoutRev = MetaCatUtil.getDocIdFromString(docid);
593
                String seperator = MetaCatUtil.getOption("accNumSeparator");
594
                // the new file name will look like docid.rev.2
595
                inlineDataFileName = docidWithoutRev + seperator + revision
596
                        + seperator + inLineDataIndex;
597
                inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
598
                // put the inline file id into a vector. If upload failed,
599
                // metacat will
600
                // delete the inline data file
601
                inlineFileIDList.add(inlineDataFileName);
602

    
603
                // put distribution id and inline file id into a  hash
604
                if (distributionId != null)
605
                {
606
                  //check to see if this inline data is readable or writable to
607
                  // this user
608
                  if (!previousUnreadableInlineDataObjectHash.isEmpty() &&
609
                       previousUnreadableInlineDataObjectHash.containsKey(distributionId))
610
                  {
611
                      unReadableInlineDataObject = true;
612
                  }
613
                  if (!previousUnwritableInlineDataObjectHash.isEmpty() &&
614
                       previousUnwritableInlineDataObjectHash.containsKey(distributionId))
615
                  {
616
                     unWritableInlineDataObject = true;
617
                     numberOfHitUnWritableInlineData++;
618
                  }
619

    
620

    
621
                  // store the distributid and inlinedata filename into a hash
622
                  inlineDistributionIdList.put(distributionId, inlineDataFileName);
623
                }
624

    
625
            }
626
            //==============================================================
627

    
628

    
629
            // If hit a text node, we need write this text for current's parent
630
            // node
631
            // This will happend if the element is mixted
632
            //==============================================================
633
            if (hitTextNode && parentNode != null)
634
            {
635

    
636

    
637
                if (needCheckingAccessModule
638
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
639
                    // stored the pull out nodes into storedNode stack
640
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
641
                            null, null, MetaCatUtil.normalize(textBuffer
642
                                    .toString()));
643
                    storedAccessNodeStack.push(nodeElement);
644

    
645
                }
646

    
647
                // write the textbuffer into db for parent node.
648
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
649
                        parentNode);
650
                // rest hitTextNode
651
                hitTextNode = false;
652
                // reset textbuffer
653
                textBuffer = null;
654
                textBuffer = new StringBuffer();
655

    
656
            }
657
            //==================================================================
658

    
659
            // Document representation that points to the root document node
660
            //==================================================================
661
            if (atFirstElement)
662
            {
663
                atFirstElement = false;
664
                // If no DOCTYPE declaration: docname = root element
665
                // doctype = root element name or name space
666
                if (docname == null) {
667
                    docname = localName;
668
                    // if uri isn't null doctype = uri(namespace)
669
                    // othewise root element
670
                    if (uri != null && !(uri.trim()).equals("")) {
671
                        doctype = uri;
672
                    } else {
673
                        doctype = docname;
674
                    }
675
                    MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
676
                    MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
677
                } else if (doctype == null) {
678
                    // because docname is not null and it is declared in dtd
679
                    // so could not be in schema, no namespace
680
                    doctype = docname;
681
                    MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
682
                }
683
                rootNode.writeNodename(docname);
684
                System.out.println("here!!!!!!!!!!!!!!!!!!1");
685
                try {
686
                    // for validated XML Documents store a reference to XML DB
687
                    // Catalog
688
                    // Because this is select statement and it needn't to roll
689
                    // back if
690
                    // insert document action fialed.
691
                    // In order to decrease DBConnection usage count, we get a
692
                    // new
693
                    // dbconnection from pool
694
                    String catalogid = null;
695
                    DBConnection dbConn = null;
696
                    int serialNumber = -1;
697

    
698
                    try {
699
                        // Get dbconnection
700
                        dbConn = DBConnectionPool
701
                                .getDBConnection("DBSAXHandler.startElement");
702
                        serialNumber = dbConn.getCheckOutSerialNumber();
703

    
704
                        Statement stmt = dbConn.createStatement();
705
                        ResultSet rs = stmt
706
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
707
                                        + "WHERE entry_type = 'Schema' "
708
                                        + "AND public_id = '" + doctype + "'");
709
                        boolean hasRow = rs.next();
710
                        if (hasRow) {
711
                            catalogid = rs.getString(1);
712
                        }
713
                        stmt.close();
714
                        System.out.println("here!!!!!!!!!!!!!!!!!!2");
715
                    }//try
716
                    finally {
717
                        // Return dbconnection
718
                        DBConnectionPool.returnDBConnection(dbConn,
719
                                serialNumber);
720
                    }//finally
721

    
722
                    //create documentImpl object by the constructor which can
723
                    // specify
724
                    //the revision
725
                    if (!super.getIsRevisionDoc())
726
                    {
727
                       
728
                       currentDocument = new DocumentImpl(connection, rootNode
729
                            .getNodeID(), docname, doctype, docid, revision,
730
                            action, user, this.pub, catalogid, this.serverCode);
731
                    }
732
                    else
733
                    {
734
                        
735
                        currentDocument = new DeletedDocumentImpl(connection, rootNode
736
                                .getNodeID(), docname, doctype, docid, revision,
737
                                action, user, this.pub, catalogid, this.serverCode);
738
                    }
739

    
740
                } catch (Exception ane) {
741
                    throw (new SAXException(
742
                            "Error in EMLSaxHandler.startElement " + action,
743
                            ane));
744
                }
745
                
746
            }
747
            //==================================================================
748

    
749
            // node
750
            //==================================================================
751
            // Create the current node representation
752
            currentNode = new DBSAXNode(connection, qName, localName,
753
                    parentNode, currentDocument.getRootNodeID(), docid,
754
                    currentDocument.getDoctype());
755
            // Use a local variable to store the element node id
756
            // If this element is a start point of subtree(section), it will be
757
            // stored
758
            // otherwise, it will be discated
759
            long startNodeId = currentNode.getNodeID();
760
            // Add all of the namespaces
761
            String prefix = null;
762
            String nsuri = null;
763
            Enumeration prefixes = namespaces.keys();
764
            while (prefixes.hasMoreElements())
765
            {
766
                prefix = (String) prefixes.nextElement();
767
                nsuri = (String) namespaces.get(prefix);
768
                endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
769
            }
770

    
771
            //=================================================================
772
           // attributes
773
           // Add all of the attributes
774
          for (int i = 0; i < atts.getLength(); i++)
775
          {
776
              String attributeName = atts.getQName(i);
777
              String attributeValue = atts.getValue(i);
778
              endNodeId = currentNode.setAttribute(attributeName,
779
                      attributeValue, docid);
780

    
781
              // To handle name space and schema location if the attribute
782
              // name is
783
              // xsi:schemaLocation. If the name space is in not in catalog
784
              // table
785
              // it will be regeistered.
786
              if (attributeName != null
787
                      && attributeName
788
                              .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
789
                  SchemaLocationResolver resolver = new SchemaLocationResolver(
790
                          attributeValue);
791
                  resolver.resolveNameSpace();
792

    
793
              }
794
              else if (attributeName != null && attributeName.equals(ID) &&
795
                       currentNode.getTagName().equals(DISTRIBUTION) &&
796
                       !inAddtionalMetaData)
797
              {
798
                 // this is a distribution element and the id is distributionID
799
                 distributionId = attributeValue;
800
                 distributionAllIdList.put(distributionId, distributionId);
801

    
802
              }
803

    
804
          }//for
805

    
806

    
807
           //=================================================================
808

    
809
            // handle access stuff
810
            //==================================================================
811
            if (localName.equals(ACCESS))
812
            {
813
                //make sure the access is top level
814
                // this mean current node's parent's parent should be "eml"
815
                DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
816
                                                                    // parent
817
                                                                    // node
818
                //peek out grandParentNode
819
                DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
820
                // put parent node back
821
                nodeStack.push(tmpNode);
822
                String grandParentTag = grandParentNode.getTagName();
823
                if (grandParentTag.equals(EML) && !inAddtionalMetaData)
824
                {
825
                  processTopLeverAccess = true;
826

    
827
                }
828
                else if ( !inAddtionalMetaData )
829
                {
830
                  // process other access embedded into resource level
831
                  // module
832
                  processOtherAccess = true;
833
                }
834
                else
835
                {
836
                  // this for access in additional data which don't have
837
                  // described element. If it has a descirbed element,
838
                  // this code would hurt any thing
839
                  processAdditionalAccess = true;
840
                  System.out.println("assing process addtional access true when meet access");
841
                }
842

    
843

    
844
                // create access object
845
                accessObject = new AccessSection();
846
                // set permission order
847
                String permOrder = currentNode.getAttribute(ORDER);
848
                accessObject.setPermissionOrder(permOrder);
849
                // set access id
850
                String accessId = currentNode.getAttribute(ID);
851
                accessObject.setSubTreeId(accessId);
852
                // for additional access subtree, the  start of node id should
853
                // be describe element. We also stored the start access element
854
                // node id too.
855
                if (processAdditionalAccess)
856
                {
857
                  accessObject.seStartedDescribesNodeId(firstDescribesNodeId);
858
                  accessObject.setControlLevel(DATAACCESSLEVEL);
859
                }
860
                else if (processTopLeverAccess)
861
                {
862
                  accessObject.setControlLevel(TOPLEVEL);
863
                }
864
                else if (processOtherAccess)
865
                {
866
                  accessObject.setControlLevel(REFERENCEDLEVEL);
867
                }
868

    
869
                accessObject.setStartNodeId(startNodeId);
870
                accessObject.setDocId(docid);
871

    
872

    
873

    
874
            }
875
            // Set up a access rule for allow
876
            else if (parentNode.getTagName() != null
877
                    && (parentNode.getTagName()).equals(ACCESS)
878
                    && localName.equals(ALLOW))
879
           {
880

    
881
                accessRule = new AccessRule();
882

    
883
                //set permission type "allow"
884
                accessRule.setPermissionType(ALLOW);
885

    
886
            }
887
            // set up an access rule for den
888
            else if (parentNode.getTagName() != null
889
                    && (parentNode.getTagName()).equals(ACCESS)
890
                    && localName.equals(DENY))
891
           {
892
                accessRule = new AccessRule();
893
                //set permission type "allow"
894
                accessRule.setPermissionType(DENY);
895
            }
896

    
897
            //=================================================================
898
            // some other independ stuff
899

    
900
            // Add the node to the stack, so that any text data can be
901
            // added as it is encountered
902
            nodeStack.push(currentNode);
903
            // Add the node to the vector used by thread for writing XML Index
904
            nodeIndex.addElement(currentNode);
905

    
906
            // store access module element and attributes into stored stack
907
            if (needCheckingAccessModule
908
                    && (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
909
            {
910
                // stored the pull out nodes into storedNode stack
911
                NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
912
                        localName, prefix, MetaCatUtil.normalize(null));
913
                storedAccessNodeStack.push(nodeElement);
914
                for (int i = 0; i < atts.getLength(); i++) {
915
                    String attributeName = atts.getQName(i);
916
                    String attributeValue = atts.getValue(i);
917
                    NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2,
918
                            "ATTRIBUTE", attributeName, null, MetaCatUtil
919
                                    .normalize(attributeValue));
920
                    storedAccessNodeStack.push(nodeAttribute);
921
                }
922

    
923
            }
924

    
925
            if (currentNode.getTagName().equals(ADDITIONALMETADATA))
926
            {
927
              inAddtionalMetaData = true;
928
            }
929
            else if (currentNode.getTagName().equals(DESCRIBES) &&
930
                     parentNode.getTagName().equals(ADDITIONALMETADATA) &&
931
                     firstDescribesInAdditionalMetadata)
932
            {
933
              // this is first decirbes element in additional metadata
934
              firstDescribesNodeId = startNodeId;
935
              // we started process additional access rules here
936
              // because access and describe couldn't be seperated
937
              NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
938
                        localName, prefix, MetaCatUtil.normalize(null));
939
              storedAccessNodeStack.push(nodeElement);
940
              processAdditionalAccess = true;
941
              System.out.println("set processAdditonalAccess ture when meet describe");
942
            }
943
            else if (inAddtionalMetaData && processAdditionalAccess &&
944
                     parentNode.getTagName().equals(ADDITIONALMETADATA) &&
945
                     !currentNode.getTagName().equals(DESCRIBES) &&
946
                     !currentNode.getTagName().equals(ACCESS))
947
            {
948
               // we start processAddtionalAccess  module when first hit describes
949
               // in additionalMetadata. So this is possible, there are
950
               // "describes" but not "access". So here is try to terminate
951
               // processAddionalAccess. In this situation, there another element
952
               // rather than "describes" or "access" as a child of additionalMetadata
953
               // so this is impossible it will have access element now.
954
               // If additionalMetadata has access element, the flag will be
955
               // terminated in endElement
956
               processAdditionalAccess = false;
957
               System.out.println("set processAddtionAccess false if the there is no access in additional");
958
            }
959
            else if (currentNode.getTagName().equals(DISTRIBUTION) &&
960
                     !inAddtionalMetaData)
961
            {
962
              proccessDistribution = true;
963
            }
964

    
965

    
966
             //==================================================================
967
            // reset name space
968
            namespaces = null;
969
            namespaces = new Hashtable();
970

    
971
        }//not inline data
972
        // inline data
973
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
974
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
975
        else
976
        {
977
            // we don't buffer the inline data in characters() method
978
            // so start character don't need to hand text node.
979

    
980
            // inline data may be the xml format.
981
            StringBuffer inlineElements = new StringBuffer();
982
            inlineElements.append("<").append(qName);
983
            // append attributes
984
            for (int i = 0; i < atts.getLength(); i++) {
985
                String attributeName = atts.getQName(i);
986
                String attributeValue = atts.getValue(i);
987
                inlineElements.append(" ");
988
                inlineElements.append(attributeName);
989
                inlineElements.append("=\"");
990
                inlineElements.append(attributeValue);
991
                inlineElements.append("\"");
992
            }
993
            // append namespace
994
            String prefix = null;
995
            String nsuri = null;
996
            Enumeration prefixes = inlineDataNameSpace.keys();
997
            while (prefixes.hasMoreElements()) {
998
                prefix = (String) prefixes.nextElement();
999
                nsuri =  (String)  inlineDataNameSpace.get(prefix);
1000
                inlineElements.append(" ");
1001
                inlineElements.append("xmlns:");
1002
                inlineElements.append(prefix);
1003
                inlineElements.append("=\"");
1004
                inlineElements.append(nsuri);
1005
                inlineElements.append("\"");
1006
            }
1007
            inlineElements.append(">");
1008
            //reset inline data name space
1009
            inlineDataNameSpace = null;
1010
            inlineDataNameSpace = new Hashtable();
1011
            //write inline data into file
1012
            MetaCatUtil.debugMessage("the inline element data is: "
1013
                    + inlineElements.toString(), 50);
1014
            writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
1015
        }//else
1016
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1017
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1018

    
1019
    }
1020

    
1021

    
1022
    /** SAX Handler that is called for each XML text node */
1023
    public void characters(char[] cbuf, int start, int len) throws SAXException
1024
    {
1025
        MetaCatUtil.debugMessage("CHARACTERS", 50);
1026
        if (!handleInlineData) {
1027
            // buffer all text nodes for same element. This is for text was
1028
            // splited
1029
            // into different nodes
1030
            textBuffer.append(new String(cbuf, start, len));
1031
            // set hittextnode true
1032
            hitTextNode = true;
1033
            // if text buffer .size is greater than max, write it to db.
1034
            // so we can save memory
1035
            if (textBuffer.length() >= MAXDATACHARS)
1036
            {
1037
                MetaCatUtil
1038
                        .debugMessage(
1039
                                "Write text into DB in charaters"
1040
                                        + " when text buffer size is greater than maxmum number",
1041
                                50);
1042
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1043
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1044
                        currentNode);
1045
                if (needCheckingAccessModule
1046
                     && (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1047
                {
1048
                     // stored the pull out nodes into storedNode stack
1049
                     NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1050
                       null, null, MetaCatUtil.normalize(textBuffer
1051
                          .toString()));
1052
                     storedAccessNodeStack.push(nodeElement);
1053

    
1054
                }
1055
                textBuffer = null;
1056
                textBuffer = new StringBuffer();
1057
            }
1058
        }
1059
        else
1060
        {
1061
            // this is inline data and write file system directly
1062
            // we don't need to buffered it.
1063
            StringBuffer inlineText = new StringBuffer();
1064
            inlineText.append(new String(cbuf, start, len));
1065
            MetaCatUtil.debugMessage(
1066
                    "The inline text data write into file system: "
1067
                            + inlineText.toString(), 50);
1068
            writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
1069
        }
1070
    }
1071

    
1072
    /** SAX Handler that is called at the end of each XML element */
1073
    public void endElement(String uri, String localName, String qName)
1074
            throws SAXException
1075
    {
1076
        MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
1077

    
1078
        // when close inline element
1079
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1080
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1081
        if (localName.equals(INLINE) && handleInlineData)
1082
        {
1083
            // Get the node from the stack
1084
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1085
            String currentTag = currentNode.getTagName();
1086
            MetaCatUtil.debugMessage("End of inline data", 35);
1087
            // close file writer
1088
            try
1089
            {
1090
                inlineDataFileWriter.close();
1091
                handleInlineData = false;
1092
            }
1093
            catch (IOException ioe)
1094
            {
1095
                throw new SAXException(ioe.getMessage());
1096
            }
1097

    
1098
            //check if user changed inine data or not if user doesn't have
1099
            // write permission for this inline block
1100
            // if some error happends, we would delete the inline data file here,
1101
            // we will call a method named deletedInlineFiles in DocumentImple
1102
            if (unWritableInlineDataObject)
1103
            {
1104
                if (unReadableInlineDataObject)
1105
                {
1106
                  // now user just got a empty string in linline part
1107
                  // so if the user send back a empty string is fine and we will
1108
                  // copy the old file to new file. If he send something else,
1109
                  // the document will be rejected
1110
                  if (inlineDataIsEmpty(inlineDataFileName))
1111
                  {
1112
                    copyInlineFile(distributionId, inlineDataFileName);
1113
                  }
1114
                  else
1115
                  {
1116
                    MetaCatUtil.debugMessage(
1117
                               "inline data was changed by a user"
1118
                                       + " who doesn't have permission", 30);
1119
                    throw new SAXException(PERMISSIONERROR);
1120

    
1121
                  }
1122
                }//if
1123
                else
1124
                {
1125
                  // user get the inline data
1126
                  if (modifiedInlineData(distributionId, inlineDataFileName))
1127
                  {
1128
                    MetaCatUtil.debugMessage(
1129
                                "inline data was changed by a user"
1130
                                        + " who doesn't have permission", 30);
1131
                    throw new SAXException(PERMISSIONERROR);
1132
                  }//if
1133
                }//else
1134
            }//if
1135
            else
1136
            {
1137
               //now user can update file.
1138
               if (unReadableInlineDataObject)
1139
               {
1140
                  // now user just got a empty string in linline part
1141
                  // so if the user send back a empty string is fine and we will
1142
                  // copy the old file to new file. If he send something else,
1143
                  // the new inline data will overwite the old one(here we need
1144
                  // do nothing because the new inline data already existed
1145
                  if (inlineDataIsEmpty(inlineDataFileName))
1146
                  {
1147
                    copyInlineFile(distributionId, inlineDataFileName);
1148
                  }
1149
                }//if
1150

    
1151
            }//else
1152
            // put inline data file name into text buffer (without path)
1153
            textBuffer = new StringBuffer(inlineDataFileName);
1154
            // write file name into db
1155
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1156
                    currentNode);
1157
            // reset textbuff
1158
            textBuffer = null;
1159
            textBuffer = new StringBuffer();
1160
            // resetinlinedata file name
1161
            inlineDataFileName = null;
1162
            unWritableInlineDataObject = false;
1163
            unReadableInlineDataObject = false;
1164
            return;
1165
        }
1166
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1167
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1168

    
1169

    
1170

    
1171
        // close element which is not in inline data
1172
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1173
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1174
        if (!handleInlineData)
1175
        {
1176
            // Get the node from the stack
1177
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1178
            String currentTag = currentNode.getTagName();
1179

    
1180
            // If before the end element, the parser hit text nodes and store
1181
            // them
1182
            // into the buffer, write the buffer to data base. The reason we
1183
            // put
1184
            // write database here is for xerces some time split text node
1185
            if (hitTextNode)
1186
            {
1187
                // get access value
1188
                String data = null;
1189
                // add principal
1190
                if (currentTag.equals(PRINCIPAL) && accessRule != null)
1191
                {
1192
                    data = (textBuffer.toString()).trim();
1193
                    accessRule.addPrincipal(data);
1194

    
1195
                }
1196
                else if (currentTag.equals(PERMISSION) && accessRule != null)
1197
                {
1198
                    data = (textBuffer.toString()).trim();
1199
                    // we conbine different a permission into one value
1200
                    int permission = accessRule.getPermission();
1201
                    // add permision
1202
                    if (data.toUpperCase().equals(READSTRING))
1203
                    {
1204
                        permission = permission | READ;
1205
                    }
1206
                    else if (data.toUpperCase().equals(WRITESTRING))
1207
                    {
1208
                        permission = permission | WRITE;
1209
                    }
1210
                    else if (data.toUpperCase().equals(CHMODSTRING))
1211
                    {
1212
                        permission = permission | CHMOD;
1213
                    }
1214
                    else if (data.toUpperCase().equals(ALLSTRING))
1215
                    {
1216
                        permission = permission | ALL;
1217
                    }
1218
                    accessRule.setPermission(permission);
1219
                }
1220
                // put additionalmetadata/describes into vector
1221
                else if (currentTag.equals(DESCRIBES))
1222
                {
1223
                    data = (textBuffer.toString()).trim();
1224
                    describesId.add(data);
1225
                    //firstDescribesInAdditionalMetadata = false;
1226
                    //firstDescribesNodeId = 0;
1227
                }
1228
                else if (currentTag.equals(REFERENCES)
1229
                        && (processTopLeverAccess || processAdditionalAccess || processOtherAccess))
1230
                {
1231
                    // get reference
1232
                    data = (textBuffer.toString()).trim();
1233
                    // put reference id into accessSection
1234
                    accessObject.setReferences(data);
1235

    
1236
                }
1237
                else if (currentTag.equals(REFERENCES) && proccessDistribution)
1238
                {
1239
                  // get reference for distribution
1240
                  data = (textBuffer.toString()).trim();
1241
                  // we only stored the distribution reference which itself
1242
                  // has a id
1243
                  if (distributionId != null)
1244
                  {
1245
                    distributionReferenceList.put(distributionId, data);
1246
                  }
1247

    
1248
                }
1249
                else if (currentTag.equals(URL) && !inAddtionalMetaData)
1250
                {
1251
                    //handle online data, make sure its'parent is online
1252
                    DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1253
                    if (parentNode != null && parentNode.getTagName() != null
1254
                            && parentNode.getTagName().equals(ONLINE))
1255
                    {
1256
                        data = (textBuffer.toString()).trim();
1257
                        if (distributionId != null)
1258
                        {
1259
                          onlineURLDistributionIdList.put(distributionId, data);
1260
                        }
1261
                        else
1262
                        {
1263
                          onelineURLDistributionListWithoutId.add(data);
1264
                        }
1265
                    }//if
1266
                }//else if
1267
                // write text to db if it is not inline data
1268

    
1269
                MetaCatUtil.debugMessage(
1270
                            "Write text into DB in End Element", 50);
1271

    
1272
                 // write text node into db
1273
                 endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1274
                            currentNode);
1275

    
1276
                if (needCheckingAccessModule
1277
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1278
                    // stored the pull out nodes into storedNode stack
1279
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1280
                            null, null, MetaCatUtil.normalize(textBuffer
1281
                                    .toString()));
1282
                    storedAccessNodeStack.push(nodeElement);
1283

    
1284
                }
1285
            }//if handle text node
1286

    
1287

    
1288

    
1289
            //set hitText false
1290
            hitTextNode = false;
1291
            // reset textbuff
1292
            textBuffer = null;
1293
            textBuffer = new StringBuffer();
1294

    
1295

    
1296
            // access stuff
1297
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY))
1298
            {
1299
                // finish parser a ccess rule and assign it to new one
1300
                AccessRule newRule = accessRule;
1301
                //add the new rule to access section object
1302
                accessObject.addAccessRule(newRule);
1303
                // reset access rule
1304
                accessRule = null;
1305
            }// ALLOW or DENY
1306
            else if (currentTag.equals(ACCESS))
1307
            {
1308
                // finish parse a access setction and stored them into different
1309
                // places
1310

    
1311
                accessObject.setEndNodeId(endNodeId);
1312
                AccessSection newAccessObject = accessObject;
1313
                newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1314
                if (newAccessObject != null)
1315
                {
1316

    
1317
                    if (processTopLeverAccess)
1318
                    {
1319
                       topAccessSection = newAccessObject;
1320

    
1321
                    }//if
1322
                    else if (processAdditionalAccess)
1323
                    {
1324
                        // for additional control
1325
                        // put discribesId into the accessobject and put this
1326
                        // access object into vector
1327
                        newAccessObject.setDescribedIdList(describesId);
1328
                        addtionalAccessVector.add(newAccessObject);
1329

    
1330
                    }//if
1331
                    else if (processOtherAccess)
1332
                    {
1333
                      // we only stored the access object which has a id
1334
                      // because only the access object which has a id can
1335
                      // be reference
1336
                      if (newAccessObject.getSubTreeId() != null &&
1337
                          !newAccessObject.getSubTreeId().trim().equals(""))
1338
                      {
1339
                         possibleReferencedAccessHash.
1340
                           put(newAccessObject.getSubTreeId(), newAccessObject);
1341
                      }
1342
                    }
1343

    
1344
                }//if
1345
                //reset access section object
1346
                accessObject = null;
1347

    
1348
                // reset tmp stored node stack
1349
                storedAccessNodeStack = null;
1350
                storedAccessNodeStack = new Stack();
1351

    
1352
                // reset flag
1353
                processAdditionalAccess = false;
1354
                processTopLeverAccess = false;
1355
                processOtherAccess = false;
1356

    
1357
            }//access element
1358
            else if (currentTag.equals(ADDITIONALMETADATA))
1359
            {
1360
                //reset describesId
1361
                describesId = null;
1362
                describesId = new Vector();
1363
                inAddtionalMetaData = false;
1364
                firstDescribesNodeId = -1;
1365
                // reset tmp stored node stack
1366
                storedAccessNodeStack = null;
1367
                storedAccessNodeStack = new Stack();
1368

    
1369

    
1370
            }
1371
            else if (currentTag.equals(DISTRIBUTION) && !inAddtionalMetaData)
1372
            {
1373
               //reset distribution id
1374
               distributionId = null;
1375
               proccessDistribution = false;
1376
            }
1377
            else if (currentTag.equals(OFFLINE) && !inAddtionalMetaData)
1378
            {
1379
               if (distributionId != null)
1380
               {
1381
                 offlineDistributionIdList.put(distributionId, distributionId);
1382
               }
1383
            }
1384
            else if ((currentTag.equals(CONNECTION) || currentTag.equals(CONNECTIONDEFINITION))
1385
                     && !inAddtionalMetaData)
1386
            {
1387
              //handle online data, make sure its'parent is online
1388
                 DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1389
                 if (parentNode != null && parentNode.getTagName() != null
1390
                         && parentNode.getTagName().equals(ONLINE))
1391
                 {
1392
                     if (distributionId != null)
1393
                     {
1394
                        onlineOtherDistributionIdList.put(distributionId, distributionId);
1395
                     }
1396
                 }//if
1397

    
1398
            }//else if
1399
            else if (currentTag.equals(DESCRIBES))
1400
            {
1401
                firstDescribesInAdditionalMetadata = false;
1402

    
1403
            }
1404

    
1405

    
1406

    
1407
        }
1408
        // close elements which are in inline data (inline data can be xml doc)
1409
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1410
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1411
        else
1412
        {
1413
            // this is in inline part
1414
            StringBuffer endElement = new StringBuffer();
1415
            endElement.append("</");
1416
            endElement.append(qName);
1417
            endElement.append(">");
1418
            MetaCatUtil.debugMessage("inline endElement: "
1419
                    + endElement.toString(), 50);
1420
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1421
        }
1422
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1423
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1424
    }
1425

    
1426

    
1427
    /*
1428
     * Method to check if the new line data is as same as the old one
1429
     */
1430
     private boolean modifiedInlineData(String inlineDistributionId,
1431
                                          String newInlineInternalFileName)
1432
     {
1433
       boolean modified = true;
1434
       if (inlineDistributionId == null || newInlineInternalFileName == null)
1435
       {
1436
         return modified;
1437
       }
1438
       String oldInlineInternalFileName =
1439
            (String)previousUnwritableInlineDataObjectHash.get(inlineDistributionId);
1440
       if (oldInlineInternalFileName == null ||
1441
           oldInlineInternalFileName.trim().equals(""))
1442
       {
1443
         return modified;
1444
       }
1445
       MetaCatUtil.debugMessage("in handle inline data", 35);
1446
       MetaCatUtil.debugMessage("the inline data file name from xml_access is: "
1447
                                    + oldInlineInternalFileName, 40);
1448

    
1449
       try
1450
       {
1451
         if (!compareInlineDataFiles(oldInlineInternalFileName,
1452
                                     newInlineInternalFileName))
1453
         {
1454
           modified = true;
1455

    
1456
         }
1457
         else
1458
         {
1459
           modified = false;
1460
         }
1461
       }
1462
       catch(Exception e)
1463
       {
1464
         modified = true;
1465
       }
1466

    
1467
       // delete the inline data file already in file system
1468
       if (modified)
1469
       {
1470
         deleteInlineDataFile(newInlineInternalFileName);
1471

    
1472
       }
1473
       return modified;
1474
     }
1475

    
1476
     /*
1477
      * A method to check if a line file is empty
1478
      */
1479
     private boolean inlineDataIsEmpty(String fileName) throws SAXException
1480
     {
1481
        boolean isEmpty = true;
1482
        if ( fileName == null)
1483
        {
1484
          throw new SAXException("The inline file name is null");
1485
        }
1486
        String path = MetaCatUtil.getOption("inlinedatafilepath");
1487
        // the new file name will look like path/docid.rev.2
1488
        File inlineDataDirectory = new File(path);
1489
        File inlineDataFile = new File(inlineDataDirectory, fileName);
1490
        try
1491
        {
1492
            FileReader inlineFileReader = new FileReader(inlineDataFile);
1493
            BufferedReader inlineStringReader = new BufferedReader(inlineFileReader);
1494
            String string = inlineStringReader.readLine();
1495
            // at the end oldstring will be null
1496
            while (string != null)
1497
            {
1498
                string = inlineStringReader.readLine();
1499
                if (string != null && !string.trim().equals(""))
1500
                {
1501
                  isEmpty = false;
1502
                  break;
1503
                }
1504
            }
1505

    
1506
        }
1507
        catch (Exception e)
1508
        {
1509
            throw new SAXException(e.getMessage());
1510
        }
1511
        return isEmpty;
1512

    
1513
     }
1514

    
1515

    
1516
    /**
1517
     * SAX Handler that receives notification of comments in the DTD
1518
     */
1519
    public void comment(char[] ch, int start, int length) throws SAXException
1520
    {
1521
        MetaCatUtil.debugMessage("COMMENT", 50);
1522
        if (!handleInlineData) {
1523
            if (!processingDTD) {
1524
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1525
                String str = new String(ch, start, length);
1526

    
1527
                //compare comment if need
1528
                /*if (startCriticalSubTree) {
1529
                    compareCommentNode(currentUnChangedableSubtreeNodeStack,
1530
                            str, PERMISSIONERROR);
1531
                }//if*/
1532
                //compare top level access module
1533
                if (processTopLeverAccess && needCheckingAccessModule) {
1534
                    /*compareCommentNode(currentUnchangableAccessModuleNodeStack,
1535
                            str, UPDATEACCESSERROR);*/
1536
                }
1537
                endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
1538
                        str, docid);
1539
                if (needCheckingAccessModule
1540
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1541
                    // stored the pull out nodes into storedNode stack
1542
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2,
1543
                            "COMMENT", null, null, MetaCatUtil.normalize(str));
1544
                    storedAccessNodeStack.push(nodeElement);
1545

    
1546
                }
1547
            }
1548
        } else {
1549
            // inline data comment
1550
            StringBuffer inlineComment = new StringBuffer();
1551
            inlineComment.append("<!--");
1552
            inlineComment.append(new String(ch, start, length));
1553
            inlineComment.append("-->");
1554
            MetaCatUtil.debugMessage("inline data comment: "
1555
                    + inlineComment.toString(), 50);
1556
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1557
        }
1558
    }
1559

    
1560

    
1561

    
1562
    /**
1563
     * SAX Handler called once for each processing instruction found: node that
1564
     * PI may occur before or after the root element.
1565
     */
1566
    public void processingInstruction(String target, String data)
1567
            throws SAXException
1568
    {
1569
        MetaCatUtil.debugMessage("PI", 50);
1570
        if (!handleInlineData) {
1571
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1572
            endNodeId = currentNode.writeChildNodeToDB("PI", target, data,
1573
                    docid);
1574
        } else {
1575
            StringBuffer inlinePI = new StringBuffer();
1576
            inlinePI.append("<?");
1577
            inlinePI.append(target);
1578
            inlinePI.append(" ");
1579
            inlinePI.append(data);
1580
            inlinePI.append("?>");
1581
            MetaCatUtil.debugMessage("inline data pi is: "
1582
                    + inlinePI.toString(), 50);
1583
            writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1584
        }
1585
    }
1586

    
1587
    /** SAX Handler that is called at the start of Namespace */
1588
    public void startPrefixMapping(String prefix, String uri)
1589
            throws SAXException
1590
    {
1591
        MetaCatUtil.debugMessage("NAMESPACE", 50);
1592
        MetaCatUtil.debugMessage("NAMESPACE prefix "+prefix, 50);
1593
        MetaCatUtil.debugMessage("NAMESPACE uri "+uri, 50);
1594
        if (!handleInlineData) {
1595
            namespaces.put(prefix, uri);
1596
        } else {
1597
            inlineDataNameSpace.put(prefix, uri);
1598
        }
1599
    }
1600

    
1601
    /**
1602
     * SAX Handler that is called for each XML text node that is Ignorable
1603
     * white space
1604
     */
1605
    public void ignorableWhitespace(char[] cbuf, int start, int len)
1606
            throws SAXException
1607
    {
1608
        // When validation is turned "on", white spaces are reported here
1609
        // When validation is turned "off" white spaces are not reported here,
1610
        // but through characters() callback
1611
        MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
1612
        if (!handleInlineData) {
1613
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1614
            String data = null;
1615
            int leftover = len;
1616
            int offset = start;
1617
            boolean moredata = true;
1618

    
1619
            // This loop deals with the case where there are more characters
1620
            // than can fit in a single database text field (limit is
1621
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
1622
            // write a series of nodes that are MAXDATACHARS long, and then the
1623
            // final node contains the remainder
1624
            while (moredata) {
1625
                if (leftover > MAXDATACHARS) {
1626
                    data = new String(cbuf, offset, MAXDATACHARS);
1627
                    leftover -= MAXDATACHARS;
1628
                    offset += MAXDATACHARS;
1629
                } else {
1630
                    data = new String(cbuf, offset, leftover);
1631
                    moredata = false;
1632
                }
1633

    
1634
                //compare whitespace if need
1635
                /*if (startCriticalSubTree) {
1636
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1637
                            data, PERMISSIONERROR);
1638
                }//if*/
1639

    
1640
                //compare whitespace in access top module
1641
                if (processTopLeverAccess && needCheckingAccessModule) {
1642
                    /*compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1643
                            data, UPDATEACCESSERROR);*/
1644
                }
1645
                // Write the content of the node to the database
1646
                if (needCheckingAccessModule
1647
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1648
                    // stored the pull out nodes into storedNode stack
1649
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1650
                            null, null, MetaCatUtil.normalize(data));
1651
                    storedAccessNodeStack.push(nodeElement);
1652

    
1653
                }
1654
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1655
                        docid);
1656
            }
1657
        } else {
1658
            //This is inline data write to file directly
1659
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1660
                    start, len));
1661
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1662
        }
1663

    
1664
    }
1665

    
1666

    
1667
    /** SAX Handler that receives notification of end of the document */
1668
    public void endDocument() throws SAXException
1669
    {
1670
        MetaCatUtil.debugMessage("end Document", 50);
1671
        if (needCheckingAccessModule)
1672
        {
1673
          compareAllAccessModules();
1674
        }
1675

    
1676
        // user deleted some inline block which it counldn't delete
1677
        if (numberOfHitUnWritableInlineData !=
1678
            previousUnwritableInlineDataObjectHash.size())
1679
        {
1680
          throw new SAXException("user deleted some inline block it couldn't");
1681
        }
1682

    
1683
        if (!super.getIsRevisionDoc())
1684
        {
1685
          // write access rule to xml_access table which include both top level
1686
          // and additional level(data access level). It also write access subtree
1687
          // info into xml_accesssubtree about the top access, additional access
1688
          // and some third place access modules which are referenced by top
1689
          // level or additional level
1690
          writeAccessRuleToDB();
1691

    
1692
          //delete relation table
1693
          deleteRelations();
1694
          //write relations
1695
           for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1696
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1697
            writeOnlineDataFileIdIntoRelationTable(id);
1698
           }
1699
        }
1700

    
1701
        // clean the subtree record
1702
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1703
    }
1704

    
1705

    
1706

    
1707
    /* The method will compare all access modules in eml document -
1708
     * topLevel, additionalLevel(data access) and referenced access module*/
1709
    private void compareAllAccessModules() throws SAXException
1710
    {
1711
      //compare top level
1712
      compareAccessSubtree(unChangebleTopAccessSubTree, topAccessSection);
1713

    
1714
      //compare additional level
1715
      int oldSize = unChangebleAdditionalAccessSubTreeVector.size();
1716
      int newSize = addtionalAccessVector.size();
1717
      // if size is different, use deleted or added rules, so throw a exception
1718
      if (oldSize != newSize)
1719
      {
1720
        throw new SAXException(UPDATEACCESSERROR);
1721
      }
1722
      //because access modules are both ordered in ASC in vectors, so we can
1723
      // compare one bye one
1724
      for ( int i = 0; i < newSize; i++)
1725
      {
1726
        AccessSection fromDB = (AccessSection)
1727
                          unChangebleAdditionalAccessSubTreeVector.elementAt(i);
1728
        AccessSection fromParser = (AccessSection)
1729
                                addtionalAccessVector.elementAt(i);
1730
        compareAccessSubtree(fromDB, fromParser);
1731
      }
1732

    
1733
      //compare referenced level
1734
      Enumeration em = unChangebleReferencedAccessSubTreeHash.keys();
1735
      while (em.hasMoreElements())
1736
      {
1737
        String id = (String)em.nextElement();
1738
        AccessSection fromDB = (AccessSection)
1739
                               unChangebleReferencedAccessSubTreeHash.get(id);
1740
        AccessSection fromParser = (AccessSection)
1741
                               possibleReferencedAccessHash.get(id);
1742
        compareAccessSubtree(fromDB, fromParser);
1743
      }
1744
    }
1745

    
1746
    /* The method will compare two access subtree. Currently they compare to
1747
     * nodes one by one. It also can be changed to parse the node first, then
1748
     * compare the parsed result
1749
     */
1750
    private void compareAccessSubtree(AccessSection fromDBTable,
1751
                                       AccessSection fromParser)
1752
                                      throws SAXException
1753
    {
1754
       if (fromDBTable == null || fromParser == null)
1755
       {
1756
         throw new SAXException(UPDATEACCESSERROR);
1757
       }
1758
       Stack nodeStackFromDBTable = fromDBTable.getSubTreeNodeStack();
1759
       Stack nodeStackFromParser  = fromParser.getStoredTmpNodeStack();
1760

    
1761
       Stack tempStack = new Stack();
1762
       while(!nodeStackFromDBTable.isEmpty()){
1763
           tempStack.push(nodeStackFromDBTable.pop());
1764
       }
1765
       comparingNodeStacks(tempStack, nodeStackFromParser);
1766
    }
1767

    
1768
    /* Compare two node stacks to see if they are same */
1769
  private void comparingNodeStacks(Stack stack1, Stack stack2)
1770
          throws SAXException
1771
  {
1772
      // make sure stack1 and stack2 are not empty
1773
      if (stack1.isEmpty() || stack2.isEmpty()) {
1774
          MetaCatUtil.debugMessage("Because stack is empty!", 35);
1775
          throw new SAXException(UPDATEACCESSERROR);
1776
      }
1777
      // go throw two stacks and compare every element
1778
      while (!stack1.isEmpty()) {
1779
          // Pop an element from stack1
1780
          NodeRecord record1 = (NodeRecord) stack1.pop();
1781

    
1782
          // Pop an element from stack2(stack 2 maybe empty)
1783
          NodeRecord record2 = null;
1784
          try {
1785
              record2 = (NodeRecord) stack2.pop();
1786
          } catch (EmptyStackException ee) {
1787

    
1788
              MetaCatUtil.debugMessage(
1789
                      "Node stack2 is empty but stack1 isn't!", 35);
1790
              throw new SAXException(UPDATEACCESSERROR);
1791
          }
1792
          // if two records are not same throw a exception
1793
          if (!record1.contentEquals(record2)) {
1794
              MetaCatUtil
1795
                      .debugMessage(
1796
                              "Two records from new and old stack are not "
1797
                                      + "same!" + record1 + "--" +record2, 30);
1798
              throw new SAXException(UPDATEACCESSERROR);
1799
          }//if
1800
      }//while
1801

    
1802
      // now stack1 is empty and we should make sure stack2 is empty too
1803
      if (!stack2.isEmpty()) {
1804

    
1805
          MetaCatUtil.debugMessage(
1806
                  "stack2 still have some elements while stack1 "
1807
                          + "is empty! ", 30);
1808
          throw new SAXException(UPDATEACCESSERROR);
1809
      }//if
1810
  }//comparingNodeStacks
1811

    
1812

    
1813
    /* The method to write all access rule into db */
1814
    private void writeAccessRuleToDB() throws SAXException
1815
    {
1816
        // delete xml_accesssubtree table record for this docid
1817
        deleteAccessSubTreeRecord(docid);
1818
        //write additional access rule, and old records in xml_access will be
1819
        //deleted too
1820
        System.out.println("before write additional access rules");
1821
        writeAddtionalAccessRuleToDB();
1822
        System.out.println("after write additional access rules");
1823
        //write top leve access rule, and old records in xml_access will be
1824
        //deleted too
1825

    
1826
        if (topAccessSection != null){
1827
          writeTopLevelAccessRuleToDB();
1828
        }
1829
        System.out.println("after write top access rules");
1830
    }//writeAccessRuleToDB
1831

    
1832

    
1833
    /* The method will figure out access reference for given access section -
1834
     * return a new AccessSection which contain access rules that be referenced.
1835
     * And will write the access subtree into xml_access table.
1836
     * this is a recursive method
1837
     */
1838
   private AccessSection resolveAccessRuleReference(AccessSection access)
1839
                                                    throws SAXException
1840
   {
1841
     if (access == null)
1842
     {
1843
       MetaCatUtil.debugMessage("access module is null in " +
1844
                                "resolveAccessRulesReference", 30);
1845
       throw new SAXException("An access modules is null");
1846
     }
1847
     String subTreeId = access.getSubTreeId();
1848
     if (subTreeId == null ||
1849
         (subTreeId != null && !accessSubTreeAlreadyWriteDBList.contains(subTreeId)))
1850
     {
1851
        // we should record this access subtree into accesssubtree table.
1852
        // subtreeId is null means it can't be referenced. So this tree couldn't
1853
        // be stored twise in the table. Subtree is not null, but it is in
1854
        // hash yet, so it is new one.
1855
        writeAccessSubTreeIntoDB(access);
1856
        if (subTreeId != null)
1857
        {
1858
          accessSubTreeAlreadyWriteDBList.put(subTreeId, subTreeId);
1859
        }
1860
     }
1861

    
1862
     String reference = access.getReferences();
1863
     if (reference != null)
1864
     {
1865
       // find the reference in top level
1866
       String topSubtreeId = topAccessSection.getSubTreeId();
1867
       if (topSubtreeId != null && topSubtreeId.equals(reference))
1868
       {
1869
          return resolveAccessRuleReference(topAccessSection);
1870
       }
1871
       else
1872
       {
1873
           // search it the additional access
1874
           for ( int i = 0; i <addtionalAccessVector.size(); i++)
1875
           {
1876
             AccessSection additionalAccess = (AccessSection)
1877
                           addtionalAccessVector.elementAt(i);
1878
             String additionId = additionalAccess.getSubTreeId();
1879
             if (additionId != null && additionId.equals(reference))
1880
             {
1881
               return resolveAccessRuleReference(additionalAccess);
1882
             }// if
1883
           }// for
1884

    
1885
           // search possible referenced access hashtable
1886
           if (possibleReferencedAccessHash.containsKey(reference))
1887
           {
1888
             AccessSection referenceAccess = (AccessSection)
1889
                         possibleReferencedAccessHash.get(reference);
1890
             return resolveAccessRuleReference(referenceAccess);
1891
           }
1892

    
1893
           // if hit here, this means you don't find any id match the reference
1894
           // throw a exception
1895
           throw new SAXException("No access module's id match the reference id");
1896
       }
1897
     }
1898
     else
1899
     {
1900
       // base line reference == null
1901
       AccessSection newAccessSection = new AccessSection();
1902
       access.copyPermOrderAndAccessRules(newAccessSection);
1903
       return newAccessSection;
1904
     }
1905
   }//resolveAccessRuleReference
1906

    
1907
   /* This method will return a id which points a real distribution block if
1908
    *  given a distribution id which is a reference. If the given id is a real
1909
    *  distribution the id itself will be returned.
1910
    *  Here is segment of eml
1911
    *   <distribution id ="100"><online><url>abc</url></online></distribution>
1912
    *   <distribution id ="200"><reference>100</reference></distribution>
1913
    * if the given value is 200, 100 will be returned.
1914
    * if the given value is 100, 100 will be returned.
1915
    */
1916
   private String resolveDistributionReference(String givenId)
1917
   {
1918
      if (givenId == null )
1919
      {
1920
        return null;
1921
      }
1922
      if (!distributionReferenceList.containsKey(givenId))
1923
      {
1924
        //this is not reference distribution block, return given id
1925
        return givenId;
1926
      }
1927
      else
1928
      {
1929
         String referencedId = (String) distributionReferenceList.get(givenId);
1930
         // search util the referenced id is not in dsitribtionReferenceList
1931
         while (distributionReferenceList.containsKey(referencedId))
1932
         {
1933
           referencedId = (String) distributionReferenceList.get(referencedId);
1934
         }
1935
         return referencedId;
1936
      }
1937
   }
1938

    
1939

    
1940
  /* The method to write top level access rule into db. The old rules will be
1941
   * deleted
1942
   * If no describedId in the access object, this access rules will be ingorned
1943
   */
1944
  private void writeAddtionalAccessRuleToDB() throws SAXException
1945
  {
1946
     System.out.println("in write addtional");
1947
     // we should delete all inline access rules in xml_access if
1948
     // user has all permission
1949
     if (!needCheckingAccessModule)
1950
     {
1951
       deleteAllInlineDataAccessRules();
1952
     }
1953
     for (int i=0; i < addtionalAccessVector.size(); i++)
1954
     {
1955
       System.out.println("in for loop of write addtional");
1956
       AccessSection access = (AccessSection)addtionalAccessVector.elementAt(i);
1957
       Vector describeIdList = access.getDescribedIdList();
1958
       // if this access is a reference, a new access object will be created
1959
       // which contains the real access rules referenced. Also, each access tree
1960
       // will be write into xml_accesssubtee table
1961
       AccessSection newAccess = resolveAccessRuleReference(access);
1962
       String permOrder = newAccess.getPermissionOrder();
1963
       Vector accessRule = newAccess.getAccessRules();
1964

    
1965
       if (describeIdList == null || describeIdList.isEmpty())
1966
       {
1967
         continue;
1968
       }
1969

    
1970
       for (int j = 0; j < describeIdList.size(); j++)
1971
       {
1972
         String subreeid = (String)describeIdList.elementAt(j);
1973
         MetaCatUtil.debugMessage("describe id in additional access " +
1974
                                  subreeid, 30);
1975
         // we need to figure out the real id if this subreeid is points to
1976
         // a distribution reference.
1977
         subreeid = resolveDistributionReference(subreeid);
1978
         if (subreeid != null && !subreeid.trim().equals(""))
1979
         {
1980
           MetaCatUtil.debugMessage("subtree id is "+ subreeid +
1981
                                    " after resolve reference id", 30 );
1982
           // if this id is for line data, we need to delete the records first
1983
           // then add new records. The key for deleting is subtee id
1984
           if (inlineDistributionIdList.containsKey(subreeid))
1985
           {
1986
             String inlineFileName = (String)
1987
                                        inlineDistributionIdList.get(subreeid);
1988
             deleteSubtreeAccessRule(subreeid);
1989
             MetaCatUtil.debugMessage("Write inline data access into " +
1990
                                   "xml_access table for"+ inlineFileName, 30);
1991
             writeGivenAccessRuleIntoDB(permOrder, accessRule,
1992
                                        inlineFileName, subreeid);
1993
           }
1994
           else if (onlineURLDistributionIdList.containsKey(subreeid))
1995
           {
1996
             String url = (String)onlineURLDistributionIdList.get(subreeid);
1997
             //this method will extrace data file id from url. It also will
1998
             // check if user can change the access rules for the data file id.
1999
             // if couldn't, it will throw a exception. Morover, the docid will
2000
             // be to relation id vector too.
2001
             // for online data, the subtree id we set is null.
2002
             // So in xml_access, only the inline data subteeid is not null
2003
             String dataFileName = handleOnlineUrlDataFile(url);
2004
             MetaCatUtil.debugMessage("The data fileName in online url " +
2005
                                      dataFileName, 30);
2006
             if (dataFileName != null)
2007
             {
2008
               deletePermissionsInAccessTableForDoc(dataFileName);
2009
               writeGivenAccessRuleIntoDB(permOrder, accessRule,
2010
                                          dataFileName, null);
2011
               MetaCatUtil.debugMessage("Write online data access into " +
2012
                                   "xml_access table for " + dataFileName, 30);
2013
               // put the id into a hashtalbe. So when we run wirtetop level
2014
               // access, those id will be ignored because they already has
2015
               // additional access rules
2016
               onlineURLIdHasAddtionalAccess.put(subreeid, subreeid);
2017
             }
2018
           }//elseif
2019
         }//if
2020
       }//for
2021
     }//for
2022

    
2023
   }//writeAdditonalLevelAccessRuletoDB
2024

    
2025

    
2026
    /* The method to write addtional access rule into db. */
2027
    private void writeTopLevelAccessRuleToDB() throws SAXException
2028
    {
2029
       // if top access is reference, we need figure out the real access rules
2030
       // it points to
2031
       System.out.println("permorder in top level" + topAccessSection.getPermissionOrder());
2032
       AccessSection newAccess = resolveAccessRuleReference(topAccessSection);
2033
       System.out.println("permorder in new level" + newAccess.getPermissionOrder());
2034
       String permOrder = newAccess.getPermissionOrder();
2035
       Vector accessRule = newAccess.getAccessRules();
2036
       String subtree     = null;
2037
       // document itself
2038
       deletePermissionsInAccessTableForDoc(docid);
2039
       writeGivenAccessRuleIntoDB(permOrder, accessRule, docid, subtree);
2040
       // for online data, it includes with id and without id.
2041
       // 1. for the data with subtree id, we should ignore the ones already in
2042
       // the hash - onlineURLIdHasAddionalAccess.
2043
       // 2. for those without subreeid, it couldn't have additional access and we
2044
       // couldn't ignore it.
2045
       // 3. for inline data, we need do nothing because if it doesn't have
2046
       // additional access, it default value is the top one.
2047

    
2048
       // here is the online url with id
2049
       Enumeration em = onlineURLDistributionIdList.keys();
2050
       while (em.hasMoreElements())
2051
       {
2052
         String onlineSubtreeId = (String)em.nextElement();
2053
         if (!onlineURLIdHasAddtionalAccess.containsKey(onlineSubtreeId))
2054
         {
2055
            String url =
2056
                       (String)onlineURLDistributionIdList.get(onlineSubtreeId);
2057
            String onlineDataId = handleOnlineUrlDataFile(url);
2058
            if (onlineDataId != null)
2059
            {
2060
              deletePermissionsInAccessTableForDoc(onlineDataId);
2061
              writeGivenAccessRuleIntoDB(permOrder, accessRule,
2062
                                         onlineDataId, subtree);
2063
            }
2064

    
2065
         }
2066
       }//while
2067

    
2068
       // here is the onlineURL without id
2069
       for (int i= 0; i < onelineURLDistributionListWithoutId.size(); i++)
2070
       {
2071
         String url = (String)onelineURLDistributionListWithoutId.elementAt(i);
2072
         String onlineDataId = handleOnlineUrlDataFile(url);
2073
         if (onlineDataId != null)
2074
         {
2075
           deletePermissionsInAccessTableForDoc(onlineDataId);
2076
           writeGivenAccessRuleIntoDB(permOrder, accessRule,
2077
                                         onlineDataId, subtree);
2078
         }
2079
       }//for
2080
    }//writeTopAccessRuletoDB
2081

    
2082
    /* Write a gaven access rule into db */
2083
    private void writeGivenAccessRuleIntoDB(String permOrder, Vector accessRules,
2084
                     String dataId, String subTreeId) throws SAXException
2085
    {
2086
      if (permOrder == null || permOrder.trim().equals("") || dataId == null ||
2087
          dataId.trim().equals("") || accessRules == null ||
2088
          accessRules.isEmpty())
2089
      {
2090
        MetaCatUtil.debugMessage("The access object is null and tried to " +
2091
                                  " write to xml_access table", 30);
2092
        throw new SAXException("The access object is null");
2093
      }
2094
       // get rid of rev from dataId
2095
       //dataId = MetaCatUtil.getDocIdFromString(dataId);
2096
       //String permOrder = accessSection.getPermissionOrder();
2097
       String sql = null;
2098
       PreparedStatement pstmt = null;
2099
       sql = "INSERT INTO xml_access (docid, principal_name, permission, "
2100
               + "perm_type, perm_order, accessfileid, subtreeid) VALUES "
2101
               + " (?, ?, ?, ?, ?, ?, ?)";
2102

    
2103
       try
2104
       {
2105

    
2106
           pstmt = connection.prepareStatement(sql);
2107
           // Increase DBConnection usage count
2108
           connection.increaseUsageCount(1);
2109
           // Bind the values to the query
2110
           pstmt.setString(1, dataId);
2111
           MetaCatUtil.debugMessage("Docid in accesstable: " + docid, 35);
2112
           pstmt.setString(6, docid);
2113
           MetaCatUtil.debugMessage("Accessfileid in accesstable: " + docid,
2114
                   35);
2115
           pstmt.setString(5, permOrder);
2116
           MetaCatUtil.debugMessage("PermOder in accesstable: " + permOrder,
2117
                   35);
2118
           pstmt.setString(7, subTreeId);
2119
           MetaCatUtil.debugMessage("subtree id in accesstable: " + subTreeId,
2120
                   35);
2121
           // if it is not top level, set s id
2122

    
2123
           //Vector accessRules = accessSection.getAccessRules();
2124
           // go through every rule
2125
           for (int i = 0; i < accessRules.size(); i++)
2126
           {
2127
               AccessRule rule = (AccessRule) accessRules.elementAt(i);
2128
               String permType = rule.getPermissionType();
2129
               int permission = rule.getPermission();
2130
               pstmt.setInt(3, permission);
2131
               MetaCatUtil.debugMessage("permission in accesstable: "
2132
                       + permission, 35);
2133
               pstmt.setString(4, permType);
2134
               MetaCatUtil.debugMessage(
2135
                       "Permtype in accesstable: " + permType, 35);
2136
               // go through every principle in rule
2137
               Vector nameVector = rule.getPrincipal();
2138
               for (int j = 0; j < nameVector.size(); j++)
2139
               {
2140
                   String prName = (String) nameVector.elementAt(j);
2141
                   pstmt.setString(2, prName);
2142
                   MetaCatUtil.debugMessage("Principal in accesstable: "
2143
                           + prName, 35);
2144
                   pstmt.execute();
2145
               }//for
2146
           }//for
2147
           pstmt.close();
2148
       }//try
2149
       catch (SQLException e)
2150
       {
2151
           throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
2152
                   + e.getMessage());
2153
       }//catch
2154
       finally
2155
       {
2156
           try
2157
           {
2158
               pstmt.close();
2159
           }
2160
           catch (SQLException ee)
2161
           {
2162
               throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
2163
                       + ee.getMessage());
2164
           }
2165
       }//finally
2166

    
2167
    }//writeGivenAccessRuleIntoDB
2168

    
2169

    
2170
    /* Delete from db all permission for resources related to @docid if any. */
2171
    private void deletePermissionsInAccessTableForDoc(String docid)
2172
            throws SAXException
2173
    {
2174
        Statement stmt = null;
2175
        try {
2176
            // delete all acl records for resources related to @aclid if any
2177
            stmt = connection.createStatement();
2178
            // Increase DBConnection usage count
2179
            connection.increaseUsageCount(1);
2180
            stmt.execute("DELETE FROM xml_access WHERE docid = '"
2181
                    + docid + "'");
2182

    
2183
        } catch (SQLException e) {
2184
            throw new SAXException(e.getMessage());
2185
        } finally {
2186
            try {
2187
                stmt.close();
2188
            } catch (SQLException ee) {
2189
                throw new SAXException(ee.getMessage());
2190
            }
2191
        }
2192
    }//deletePermissionsInAccessTable
2193

    
2194
    /* Delete access rules from xml_access for a subtee id */
2195
    private void deleteSubtreeAccessRule(String subtreeid) throws SAXException
2196
    {
2197
      Statement stmt = null;
2198
       try
2199
       {
2200
           stmt = connection.createStatement();
2201
           // Increase DBConnection usage count
2202
           connection.increaseUsageCount(1);
2203
           stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
2204
                   + docid + "' AND subtreeid ='" + subtreeid +"'");
2205
       }
2206
       catch (SQLException e)
2207
       {
2208
           throw new SAXException(e.getMessage());
2209
       }
2210
       finally
2211
       {
2212
           try
2213
           {
2214
               stmt.close();
2215
           }
2216
           catch (SQLException ee)
2217
           {
2218
               throw new SAXException(ee.getMessage());
2219
           }
2220
       }
2221

    
2222
    }
2223

    
2224
    private void deleteAllInlineDataAccessRules() throws SAXException
2225
    {
2226
      Statement stmt = null;
2227
       try
2228
       {
2229
           stmt = connection.createStatement();
2230
           // Increase DBConnection usage count
2231
           connection.increaseUsageCount(1);
2232
           stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
2233
                   + docid + "' AND subtreeid IS NOT NULL");
2234
       }
2235
       catch (SQLException e)
2236
       {
2237
           throw new SAXException(e.getMessage());
2238
       }
2239
       finally
2240
       {
2241
           try
2242
           {
2243
               stmt.close();
2244
           }
2245
           catch (SQLException ee)
2246
           {
2247
               throw new SAXException(ee.getMessage());
2248
           }
2249
       }
2250

    
2251
    }
2252

    
2253
    /*
2254
     * In order to make sure only usr has "all" permission can update access
2255
     * subtree in eml document we need to keep access subtree info in
2256
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
2257
     */
2258
    private void writeAccessSubTreeIntoDB(AccessSection accessSection)
2259
                                          throws SAXException
2260
    {
2261
        if (accessSection == null)
2262
        {
2263

    
2264
          MetaCatUtil.debugMessage("Access object is null and tried to write "+
2265
                                   "into access subtree table", 30);
2266
          throw new SAXException("The access object is null to write access " +
2267
                                 "sbutree");
2268
        }
2269

    
2270
        String sql = null;
2271
        PreparedStatement pstmt = null;
2272
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
2273
                + "subtreeid, startnodeid, endnodeid) VALUES "
2274
                + " (?, ?, ?, ?, ?, ?)";
2275
        try
2276
        {
2277

    
2278
            pstmt = connection.prepareStatement(sql);
2279
            // Increase DBConnection usage count
2280
            connection.increaseUsageCount(1);
2281
            String level = accessSection.getControlLevel();
2282
            long startNodeId = -1;
2283
            if (level != null && level.equals(DATAACCESSLEVEL))
2284
            {
2285
              // for addtional access module the start node id should be
2286
              // descirbes element id
2287
              startNodeId = accessSection.getStartedDescribesNodeId();
2288
              // if in additional access, there is not describes element,
2289
              // in this senario, describesNodeId will be -1. Then we should
2290
              // the start access element id
2291
              if (startNodeId == -1)
2292
              {
2293
                startNodeId = accessSection.getStartNodeId();
2294
              }
2295
            }
2296
            else
2297
            {
2298
                startNodeId = accessSection.getStartNodeId();
2299
            }
2300

    
2301
            long endNodeId = accessSection.getEndNodeId();
2302
            String sectionId = accessSection.getSubTreeId();
2303

    
2304
            if (startNodeId ==-1 || endNodeId == -1)
2305
            {
2306
              throw new SAXException("Don't find start node or end node id " +
2307
                                      "for the access subtee");
2308

    
2309
            }
2310

    
2311
            // Bind the values to the query
2312
            pstmt.setString(1, docid);
2313
            MetaCatUtil.debugMessage("Docid in access-subtreetable: " + docid,
2314
                    35);
2315
            pstmt.setInt(2, (new Integer(revision)).intValue());
2316
            MetaCatUtil.debugMessage("rev in accesssubtreetable: " + revision,
2317
                    35);
2318
            pstmt.setString(3, level);
2319
            MetaCatUtil.debugMessage("contorl level in access-subtree table: "
2320
                    + level, 35);
2321
            pstmt.setString(4, sectionId);
2322
            MetaCatUtil.debugMessage("Subtree id in access-subtree table: "
2323
                    + sectionId, 35);
2324
            pstmt.setLong(5, startNodeId);
2325
            MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
2326
            pstmt.setLong(6, endNodeId);
2327
            MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
2328
            pstmt.execute();
2329
            pstmt.close();
2330
        }//try
2331
        catch (SQLException e)
2332
        {
2333
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
2334
                    + e.getMessage());
2335
        }//catch
2336
        finally
2337
        {
2338
            try
2339
            {
2340
                pstmt.close();
2341
            }
2342
            catch (SQLException ee)
2343
            {
2344
                throw new SAXException(
2345
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
2346
                                + ee.getMessage());
2347
            }
2348
        }//finally
2349

    
2350
    }//writeAccessSubtreeIntoDB
2351

    
2352
    /* Delete every access subtree record from xml_accesssubtree. */
2353
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
2354
    {
2355
        Statement stmt = null;
2356
        try {
2357
            // delete all acl records for resources related to @aclid if any
2358
            stmt = connection.createStatement();
2359
            // Increase DBConnection usage count
2360
            connection.increaseUsageCount(1);
2361
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
2362
                    + docId + "'");
2363

    
2364
        } catch (SQLException e) {
2365
            throw new SAXException(e.getMessage());
2366
        } finally {
2367
            try {
2368
                stmt.close();
2369
            } catch (SQLException ee) {
2370
                throw new SAXException(ee.getMessage());
2371
            }
2372
        }
2373
    }//deleteAccessSubTreeRecord
2374

    
2375
    // open a file writer for writing inline data to file
2376
    private FileWriter createInlineDataFileWriter(String fileName)
2377
            throws SAXException
2378
    {
2379
        FileWriter writer = null;
2380
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2381
        /*
2382
         * File inlineDataDirectory = new File(path);
2383
         */
2384
        String newFile = path + "/" + fileName;
2385
        MetaCatUtil.debugMessage("inline file name: " + newFile, 30);
2386
        try {
2387
            // true means append
2388
            writer = new FileWriter(newFile, true);
2389
        } catch (IOException ioe) {
2390
            throw new SAXException(ioe.getMessage());
2391
        }
2392
        return writer;
2393
    }
2394

    
2395
    // write inline data into file system and return file name(without path)
2396
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2397
            throws SAXException
2398
    {
2399
        try {
2400
            writer.write(data.toString());
2401
            writer.flush();
2402
        } catch (Exception e) {
2403
            throw new SAXException(e.getMessage());
2404
        }
2405
    }
2406

    
2407

    
2408

    
2409
    /*
2410
     * In eml2, the inline data wouldn't store in db, it store in file system
2411
     * The db stores file name(without path). We got the old file name from db
2412
     * and compare to the new in line data file
2413
     */
2414
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2415
            throws McdbException
2416
    {
2417
        // this method need to be testing
2418
        boolean same = true;
2419
        String data = null;
2420
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2421
        // the new file name will look like path/docid.rev.2
2422
        File inlineDataDirectory = new File(path);
2423
        File oldDataFile = new File(inlineDataDirectory, oldFileName);
2424
        File newDataFile = new File(inlineDataDirectory, newFileName);
2425
        try {
2426
            FileReader oldFileReader = new FileReader(oldDataFile);
2427
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2428
            FileReader newFileReader = new FileReader(newDataFile);
2429
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2430
            // read first line of data
2431
            String oldString = oldStringReader.readLine();
2432
            String newString = newStringReader.readLine();
2433

    
2434
            // at the end oldstring will be null
2435
            while (oldString != null) {
2436
                oldString = oldStringReader.readLine();
2437
                newString = newStringReader.readLine();
2438
                if (!oldString.equals(newString)) {
2439
                    same = false;
2440
                    break;
2441
                }
2442
            }
2443

    
2444
            // if oldString is null but newString is not null, they are same
2445
            if (same) {
2446
                if (newString != null) {
2447
                    same = false;
2448
                }
2449
            }
2450

    
2451
        } catch (Exception e) {
2452
            throw new McdbException(e.getMessage());
2453
        }
2454
        MetaCatUtil.debugMessage("the inline data retrieve from file: " + data,
2455
                50);
2456
        return same;
2457
    }
2458

    
2459
   /*
2460
    * Copy a old line file to a new inline file
2461
    */
2462
   public void copyInlineFile(String inlineDistributionId, String newFileName)
2463
           throws SAXException
2464
   {
2465
     if (inlineDistributionId == null || newFileName == null)
2466
     {
2467
       throw new SAXException("Could not copy inline file from old one to new "+
2468
                              "one!");
2469
     }
2470
     // get old file id from previousUnreadable data object
2471
    String oldInlineInternalFileName =
2472
         (String)previousUnreadableInlineDataObjectHash.get(inlineDistributionId);
2473

    
2474
    if (oldInlineInternalFileName == null ||
2475
        oldInlineInternalFileName.trim().equals(""))
2476
    {
2477
      throw new SAXException("Could not copy inline file from old one to new "+
2478
                              "one because can't find old file name");
2479
    }
2480
    MetaCatUtil.debugMessage("in handle inline data", 35);
2481
    MetaCatUtil.debugMessage("the inline data file name from xml_access is: "
2482
                                 + oldInlineInternalFileName, 40);
2483

    
2484
    String path = MetaCatUtil.getOption("inlinedatafilepath");
2485
    // the new file name will look like path/docid.rev.2
2486
    File inlineDataDirectory = new File(path);
2487
    File oldDataFile = new File(inlineDataDirectory, oldInlineInternalFileName);
2488
    File newDataFile = new File(inlineDataDirectory, newFileName);
2489
    FileReader oldFileReader = null;
2490
    FileWriter newFileWriter = null;
2491
    try
2492
    {
2493
      oldFileReader = new FileReader(oldDataFile);
2494
      newFileWriter = new FileWriter(newDataFile);
2495
      char[] buf = new char[4 * 1024]; // 4K buffer
2496
      int b = oldFileReader.read(buf);
2497
      while (b != -1)
2498
      {
2499
        newFileWriter.write(buf, 0, b);
2500
        b = oldFileReader.read(buf);
2501

    
2502
      }
2503
    }
2504
    catch (Exception e)
2505
    {
2506
      throw new SAXException(e.getMessage());
2507
    }
2508
    finally
2509
    {
2510
        if (oldFileReader != null)
2511
        {
2512
          try
2513
          {
2514
            oldFileReader.close();
2515
          }
2516
          catch (Exception ee)
2517
          {
2518
            throw new SAXException(ee.getMessage());
2519
          }
2520

    
2521
        }
2522
        if (newFileWriter != null)
2523
        {
2524
          try
2525
          {
2526
            newFileWriter.close();
2527
          }
2528
          catch (Exception ee)
2529
          {
2530
            throw new SAXException(ee.getMessage());
2531
          }
2532

    
2533
        }
2534

    
2535
    }
2536

    
2537
  }
2538

    
2539

    
2540
    // if xml file failed to upload, we need to call this method to delete
2541
    // the inline data already in file system
2542
    public void deleteInlineFiles()
2543
    {
2544
        if (!inlineFileIDList.isEmpty()) {
2545
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2546
                String fileName = (String) inlineFileIDList.elementAt(i);
2547
                deleteInlineDataFile(fileName);
2548
            }
2549
        }
2550
    }
2551

    
2552
    /* delete the inline data file */
2553
    private void deleteInlineDataFile(String fileName)
2554
    {
2555

    
2556
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2557
        File inlineDataDirectory = new File(path);
2558
        File newFile = new File(inlineDataDirectory, fileName);
2559
        newFile.delete();
2560

    
2561
    }
2562

    
2563
    /*
2564
     * In eml2, the inline data wouldn't store in db, it store in file system
2565
     * The db stores file name(without path).
2566
     */
2567
    public static Reader readInlineDataFromFileSystem(String fileName)
2568
            throws McdbException
2569
    {
2570
        //BufferedReader stringReader = null;
2571
        FileReader fileReader = null;
2572
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2573
        // the new file name will look like path/docid.rev.2
2574
        File inlineDataDirectory = new File(path);
2575
        File dataFile = new File(inlineDataDirectory, fileName);
2576
        try {
2577
            fileReader = new FileReader(dataFile);
2578
            //stringReader = new BufferedReader(fileReader);
2579
        } catch (Exception e) {
2580
            throw new McdbException(e.getMessage());
2581
        }
2582
        // return stringReader;
2583
        return fileReader;
2584
    }
2585

    
2586
    /* Delete relations */
2587
    private void deleteRelations() throws SAXException
2588
    {
2589
        PreparedStatement pStmt = null;
2590
        String sql = "DELETE FROM xml_relation where docid =?";
2591
        try {
2592
            pStmt = connection.prepareStatement(sql);
2593
            //bind variable
2594
            pStmt.setString(1, docid);
2595
            //execute query
2596
            pStmt.execute();
2597
            pStmt.close();
2598
        }//try
2599
        catch (SQLException e) {
2600
            throw new SAXException("EMLSAXHandler.deleteRelations(): "
2601
                    + e.getMessage());
2602
        }//catch
2603
        finally {
2604
            try {
2605
                pStmt.close();
2606
            }//try
2607
            catch (SQLException ee) {
2608
                throw new SAXException("EMLSAXHandler.deleteRelations: "
2609
                        + ee.getMessage());
2610
            }//catch
2611
        }//finally
2612
    }
2613

    
2614
    /* Write an online data file id into xml_relation table. The dataId shouldnot
2615
     * have the revision
2616
     */
2617
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2618
            throws SAXException
2619
    {
2620
        PreparedStatement pStmt = null;
2621
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2622
                + "relationship, object) values (?, ?, ?, ?, ?)";
2623
        try {
2624
            pStmt = connection.prepareStatement(sql);
2625
            //bind variable
2626
            pStmt.setString(1, docid);
2627
            pStmt.setString(2, doctype);
2628
            pStmt.setString(3, docid);
2629
            pStmt.setString(4, RELATION);
2630
            pStmt.setString(5, dataId);
2631
            //execute query
2632
            pStmt.execute();
2633
            pStmt.close();
2634
        }//try
2635
        catch (SQLException e) {
2636
            throw new SAXException(
2637
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2638
                            + e.getMessage());
2639
        }//catch
2640
        finally {
2641
            try {
2642
                pStmt.close();
2643
            }//try
2644
            catch (SQLException ee) {
2645
                throw new SAXException(
2646
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2647
                                + ee.getMessage());
2648
            }//catch
2649
        }//finally
2650

    
2651
    }//writeOnlineDataFileIdIntoRelationTable
2652

    
2653
    /*
2654
     * This method will handle data file in online url. If the data file is in
2655
     * ecogrid protocol, then the datafile identifier(without rev) be returned.
2656
     * otherwise, null will be returned.
2657
     * If the data file doesn't exsit in xml_documents or
2658
     * xml_revision table, or the user has all permission to the data file if
2659
     * the docid already existed, the data file id (without rev)will be returned
2660
     * NEED to do:
2661
     * We should also need to implement http and ftp. Those
2662
     * external files should be download and assign a data file id to it.
2663
     */
2664
    private String handleOnlineUrlDataFile(String url) throws SAXException
2665
    {
2666
      MetaCatUtil.debugMessage("The url is "+ url, 10);
2667
      String docid = null;
2668
      // if the url is not a ecogrid protocol, null will be getten
2669
      String accessionNumber =
2670
                 MetaCatUtil.getAccessionNumberFromEcogridIdentifier(url);
2671
      if (accessionNumber != null)
2672
      {
2673
        // handle ecogrid protocol
2674
        // get rid of revision number to get the docid.
2675
        docid = MetaCatUtil.getDocIdFromAccessionNumber(accessionNumber);
2676
        onlineDataFileIdInRelationVector.add(docid);
2677
        try
2678
        {
2679

    
2680
          if (!AccessionNumber.accNumberUsed(docid))
2681
          {
2682
            return docid;
2683
          }
2684
          PermissionController controller = new
2685
              PermissionController(accessionNumber);
2686
          if (controller.hasPermission(
2687
              user, groups, AccessControlInterface.ALLSTRING))
2688
          {
2689
            return docid;
2690
          }
2691
          else
2692
          {
2693
            throw new SAXException("User does not have permission to update " +
2694
                  "of access rules for data file "+ docid);
2695
          }
2696
        }//try
2697
        catch(Exception e)
2698
        {
2699
          MetaCatUtil.debugMessage("Eorr in " +
2700
                                "Eml200SAXHanlder.handleOnlineUrlDataFile is " +
2701
                                 e.getMessage(), 30);
2702
          throw new SAXException(e.getMessage());
2703
        }
2704
      }
2705
      return docid;
2706
    }
2707

    
2708
    private void compareElementNameSpaceAttributes(Stack unchangableNodeStack,
2709
            Hashtable nameSpaces, Attributes attributes, String localName,
2710
            String error) throws SAXException
2711
    {
2712
        //Get element subtree node stack (element node)
2713
        NodeRecord elementNode = null;
2714
        try {
2715
            elementNode = (NodeRecord) unchangableNodeStack.pop();
2716
        } catch (EmptyStackException ee) {
2717
            MetaCatUtil
2718
                    .debugMessage("Node stack is empty for element data", 35);
2719
            throw new SAXException(error);
2720
        }
2721
        MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
2722
        MetaCatUtil.debugMessage("node type from stack: "
2723
                + elementNode.getNodeType(), 40);
2724
        MetaCatUtil.debugMessage("node name from xml document: " + localName,
2725
                40);
2726
        MetaCatUtil.debugMessage("node name from stack: "
2727
                + elementNode.getNodeName(), 40);
2728
        MetaCatUtil.debugMessage("node data from stack: "
2729
                + elementNode.getNodeData(), 40);
2730
        MetaCatUtil.debugMessage("node id is: " + elementNode.getNodeId(), 40);
2731
        // if this node is not element or local name not equal or name space
2732
        // not
2733
        // equals, throw an exception
2734
        if (!elementNode.getNodeType().equals("ELEMENT")
2735
                || !localName.equals(elementNode.getNodeName()))
2736
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
2737
        {
2738
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
2739
            MetaCatUtil.debugMessage("current node type from xml is ELEMENT",
2740
                    40);
2741
            MetaCatUtil.debugMessage("node type from stack: "
2742
                    + elementNode.getNodeType(), 40);
2743
            MetaCatUtil.debugMessage("node name from xml document: "
2744
                    + localName, 40);
2745
            MetaCatUtil.debugMessage("node name from stack: "
2746
                    + elementNode.getNodeName(), 40);
2747
            MetaCatUtil.debugMessage("node data from stack: "
2748
                    + elementNode.getNodeData(), 40);
2749
            MetaCatUtil.debugMessage("node id is: " + elementNode.getNodeId(),
2750
                    40);
2751
            throw new SAXException(error);
2752
        }
2753

    
2754
        //compare namespace
2755
        Enumeration nameEn = nameSpaces.keys();
2756
        while (nameEn.hasMoreElements()) {
2757
            //Get namespacke node stack (element node)
2758
            NodeRecord nameNode = null;
2759
            try {
2760
                nameNode = (NodeRecord) unchangableNodeStack.pop();
2761
            } catch (EmptyStackException ee) {
2762
                MetaCatUtil.debugMessage(
2763
                        "Node stack is empty for namespace data", 35);
2764
                throw new SAXException(error);
2765
            }
2766

    
2767
            String prefixName = (String) nameEn.nextElement();
2768
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
2769
            if (!nameNode.getNodeType().equals("NAMESPACE")
2770
                    || !prefixName.equals(nameNode.getNodeName())
2771
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
2772
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
2773
                MetaCatUtil.debugMessage(
2774
                        "current node type from xml is NAMESPACE", 40);
2775
                MetaCatUtil.debugMessage("node type from stack: "
2776
                        + nameNode.getNodeType(), 40);
2777
                MetaCatUtil.debugMessage("current node name from xml is: "
2778
                        + prefixName, 40);
2779
                MetaCatUtil.debugMessage("node name from stack: "
2780
                        + nameNode.getNodeName(), 40);
2781
                MetaCatUtil.debugMessage("current node data from xml is: "
2782
                        + nameSpaceUri, 40);
2783
                MetaCatUtil.debugMessage("node data from stack: "
2784
                        + nameNode.getNodeData(), 40);
2785
                MetaCatUtil.debugMessage("node id is: " + nameNode.getNodeId(),
2786
                        40);
2787
                throw new SAXException(error);
2788
            }
2789

    
2790
        }//while
2791

    
2792
        //compare attributes
2793
        for (int i = 0; i < attributes.getLength(); i++) {
2794
            NodeRecord attriNode = null;
2795
            try {
2796
                attriNode = (NodeRecord) unchangableNodeStack.pop();
2797

    
2798
            } catch (EmptyStackException ee) {
2799
                MetaCatUtil.debugMessage(
2800
                        "Node stack is empty for attribute data", 35);
2801
                throw new SAXException(error);
2802
            }
2803
            String attributeName = attributes.getQName(i);
2804
            String attributeValue = attributes.getValue(i);
2805
            MetaCatUtil.debugMessage(
2806
                    "current node type from xml is ATTRIBUTE ", 40);
2807
            MetaCatUtil.debugMessage("node type from stack: "
2808
                    + attriNode.getNodeType(), 40);
2809
            MetaCatUtil.debugMessage("current node name from xml is: "
2810
                    + attributeName, 40);
2811
            MetaCatUtil.debugMessage("node name from stack: "
2812
                    + attriNode.getNodeName(), 40);
2813
            MetaCatUtil.debugMessage("current node data from xml is: "
2814
                    + attributeValue, 40);
2815
            MetaCatUtil.debugMessage("node data from stack: "
2816
                    + attriNode.getNodeData(), 40);
2817
            MetaCatUtil.debugMessage("node id  is: " + attriNode.getNodeId(),
2818
                    40);
2819

    
2820
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
2821
                    || !attributeName.equals(attriNode.getNodeName())
2822
                    || !attributeValue.equals(attriNode.getNodeData())) {
2823
                MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
2824
                MetaCatUtil.debugMessage(
2825
                        "current node type from xml is ATTRIBUTE ", 40);
2826
                MetaCatUtil.debugMessage("node type from stack: "
2827
                        + attriNode.getNodeType(), 40);
2828
                MetaCatUtil.debugMessage("current node name from xml is: "
2829
                        + attributeName, 40);
2830
                MetaCatUtil.debugMessage("node name from stack: "
2831
                        + attriNode.getNodeName(), 40);
2832
                MetaCatUtil.debugMessage("current node data from xml is: "
2833
                        + attributeValue, 40);
2834
                MetaCatUtil.debugMessage("node data from stack: "
2835
                        + attriNode.getNodeData(), 40);
2836
                MetaCatUtil.debugMessage("node is: " + attriNode.getNodeId(),
2837
                        40);
2838
                throw new SAXException(error);
2839
            }
2840
        }//for
2841

    
2842
    }
2843

    
2844
    /* mehtod to compare current text node and node in db */
2845
    private void compareTextNode(Stack nodeStack, StringBuffer text,
2846
            String error) throws SAXException
2847
    {
2848
        NodeRecord node = null;
2849
        //get node from current stack
2850
        try {
2851
            node = (NodeRecord) nodeStack.pop();
2852
        } catch (EmptyStackException ee) {
2853
            MetaCatUtil.debugMessage(
2854
                    "Node stack is empty for text data in startElement", 35);
2855
            throw new SAXException(error);
2856
        }
2857
        MetaCatUtil.debugMessage(
2858
                "current node type from xml is TEXT in start element", 40);
2859
        MetaCatUtil.debugMessage("node type from stack: " + node.getNodeType(),
2860
                40);
2861
        MetaCatUtil.debugMessage("current node data from xml is: "
2862
                + text.toString(), 40);
2863
        MetaCatUtil.debugMessage("node data from stack: " + node.getNodeData(),
2864
                40);
2865
        MetaCatUtil.debugMessage("node name from stack: " + node.getNodeName(),
2866
                40);
2867
        MetaCatUtil.debugMessage("node is: " + node.getNodeId(), 40);
2868
        if (!node.getNodeType().equals("TEXT")
2869
                || !(text.toString()).equals(node.getNodeData())) {
2870
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
2871
            MetaCatUtil.debugMessage(
2872
                    "current node type from xml is TEXT in start element", 40);
2873
            MetaCatUtil.debugMessage("node type from stack: "
2874
                    + node.getNodeType(), 40);
2875
            MetaCatUtil.debugMessage("current node data from xml is: "
2876
                    + text.toString(), 40);
2877
            MetaCatUtil.debugMessage("node data from stack: "
2878
                    + node.getNodeData(), 40);
2879
            MetaCatUtil.debugMessage("node name from stack: "
2880
                    + node.getNodeName(), 40);
2881
            MetaCatUtil.debugMessage("node is: " + node.getNodeId(), 40);
2882
            throw new SAXException(error);
2883
        }//if
2884
    }
2885

    
2886
    /* Comparet comment from xml and db */
2887
    private void compareCommentNode(Stack nodeStack, String string, String error)
2888
            throws SAXException
2889
    {
2890
        NodeRecord node = null;
2891
        try {
2892
            node = (NodeRecord) nodeStack.pop();
2893
        } catch (EmptyStackException ee) {
2894
            MetaCatUtil.debugMessage("the stack is empty for comment data", 32);
2895
            throw new SAXException(error);
2896
        }
2897
        MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
2898
        MetaCatUtil.debugMessage("node type from stack: " + node.getNodeType(),
2899
                40);
2900
        MetaCatUtil
2901
                .debugMessage("current node data from xml is: " + string, 40);
2902
        MetaCatUtil.debugMessage("node data from stack: " + node.getNodeData(),
2903
                40);
2904
        MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(), 40);
2905
        // if not consistent terminate program and throw a exception
2906
        if (!node.getNodeType().equals("COMMENT")
2907
                || !string.equals(node.getNodeData())) {
2908
            MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
2909
            MetaCatUtil.debugMessage("current node type from xml is COMMENT",
2910
                    40);
2911
            MetaCatUtil.debugMessage("node type from stack: "
2912
                    + node.getNodeType(), 40);
2913
            MetaCatUtil.debugMessage(
2914
                    "current node data from xml is: " + string, 40);
2915
            MetaCatUtil.debugMessage("node data from stack: "
2916
                    + node.getNodeData(), 40);
2917
            MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(),
2918
                    40);
2919
            throw new SAXException(error);
2920
        }//if
2921
    }
2922

    
2923
    /* Compare whitespace from xml and db */
2924
   private void compareWhiteSpace(Stack nodeStack, String string, String error)
2925
           throws SAXException
2926
   {
2927
       NodeRecord node = null;
2928
       try {
2929
           node = (NodeRecord) nodeStack.pop();
2930
       } catch (EmptyStackException ee) {
2931
           MetaCatUtil.debugMessage("the stack is empty for whitespace data",
2932
                   32);
2933
           throw new SAXException(error);
2934
       }
2935
       if (!node.getNodeType().equals("TEXT")
2936
               || !string.equals(node.getNodeData())) {
2937
           MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
2938
           MetaCatUtil.debugMessage(
2939
                   "current node type from xml is WHITESPACE TEXT", 40);
2940
           MetaCatUtil.debugMessage("node type from stack: "
2941
                   + node.getNodeType(), 40);
2942
           MetaCatUtil.debugMessage(
2943
                   "current node data from xml is: " + string, 40);
2944
           MetaCatUtil.debugMessage("node data from stack: "
2945
                   + node.getNodeData(), 40);
2946
           MetaCatUtil.debugMessage("node is from stack: " + node.getNodeId(),
2947
                   40);
2948
           throw new SAXException(error);
2949
       }//if
2950
   }
2951

    
2952

    
2953

    
2954
}
(35-35/64)