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-10-01 21:20:35 -0700 (Sat, 01 Oct 2005) $'
12
 * '$Revision: 2623 $'
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, String createDate, String updateDate) throws SAXException
302
    {
303
        super(conn, action, docid, revision, user, groups, pub, 
304
                serverCode, createDate, updateDate);
305
        // Get the unchangable subtrees (user doesn't have write permission)
306
        try
307
        {
308
            PermissionController control = new PermissionController(docid
309
                    + MetaCatUtil.getOption("accNumSeparator") + revision);
310
            //unChangableSubTreeHash = getUnchangableSubTree(control, user,
311
            // groups);
312

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

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

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

    
342
            }
343

    
344

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

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

    
368

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

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

    
417
     }
418

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

    
432
        try
433
        {
434

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

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

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

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

    
498
       try
499
       {
500

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

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

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

    
554

    
555

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

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

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

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

    
621

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

    
626
            }
627
            //==============================================================
628

    
629

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

    
637

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

    
646
                }
647

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

    
657
            }
658
            //==================================================================
659

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

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

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

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

    
736
                } catch (Exception ane) {
737
                    throw (new SAXException(
738
                            "Error in EMLSaxHandler.startElement " + action,
739
                            ane));
740
                }
741
                
742
            }
743
            //==================================================================
744

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

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

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

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

    
798
              }
799

    
800
          }//for
801

    
802

    
803
           //=================================================================
804

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

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

    
839

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

    
865
                accessObject.setStartNodeId(startNodeId);
866
                accessObject.setDocId(docid);
867

    
868

    
869

    
870
            }
871
            // Set up a access rule for allow
872
            else if (parentNode.getTagName() != null
873
                    && (parentNode.getTagName()).equals(ACCESS)
874
                    && localName.equals(ALLOW))
875
           {
876

    
877
                accessRule = new AccessRule();
878

    
879
                //set permission type "allow"
880
                accessRule.setPermissionType(ALLOW);
881

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

    
893
            //=================================================================
894
            // some other independ stuff
895

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

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

    
919
            }
920

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

    
961

    
962
             //==================================================================
963
            // reset name space
964
            namespaces = null;
965
            namespaces = new Hashtable();
966

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

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

    
1015
    }
1016

    
1017

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

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

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

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

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

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

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

    
1165

    
1166

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

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

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

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

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

    
1265
                MetaCatUtil.debugMessage(
1266
                            "Write text into DB in End Element", 50);
1267

    
1268
                 // write text node into db
1269
                 endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1270
                            currentNode);
1271

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

    
1280
                }
1281
            }//if handle text node
1282

    
1283

    
1284

    
1285
            //set hitText false
1286
            hitTextNode = false;
1287
            // reset textbuff
1288
            textBuffer = null;
1289
            textBuffer = new StringBuffer();
1290

    
1291

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

    
1307
                accessObject.setEndNodeId(endNodeId);
1308
                AccessSection newAccessObject = accessObject;
1309
                newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1310
                if (newAccessObject != null)
1311
                {
1312

    
1313
                    if (processTopLeverAccess)
1314
                    {
1315
                       topAccessSection = newAccessObject;
1316

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

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

    
1340
                }//if
1341
                //reset access section object
1342
                accessObject = null;
1343

    
1344
                // reset tmp stored node stack
1345
                storedAccessNodeStack = null;
1346
                storedAccessNodeStack = new Stack();
1347

    
1348
                // reset flag
1349
                processAdditionalAccess = false;
1350
                processTopLeverAccess = false;
1351
                processOtherAccess = false;
1352

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

    
1365

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

    
1394
            }//else if
1395
            else if (currentTag.equals(DESCRIBES))
1396
            {
1397
                firstDescribesInAdditionalMetadata = false;
1398

    
1399
            }
1400

    
1401

    
1402

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

    
1422

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

    
1445
       try
1446
       {
1447
         if (!compareInlineDataFiles(oldInlineInternalFileName,
1448
                                     newInlineInternalFileName))
1449
         {
1450
           modified = true;
1451

    
1452
         }
1453
         else
1454
         {
1455
           modified = false;
1456
         }
1457
       }
1458
       catch(Exception e)
1459
       {
1460
         modified = true;
1461
       }
1462

    
1463
       // delete the inline data file already in file system
1464
       if (modified)
1465
       {
1466
         deleteInlineDataFile(newInlineInternalFileName);
1467

    
1468
       }
1469
       return modified;
1470
     }
1471

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

    
1502
        }
1503
        catch (Exception e)
1504
        {
1505
            throw new SAXException(e.getMessage());
1506
        }
1507
        return isEmpty;
1508

    
1509
     }
1510

    
1511

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

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

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

    
1556

    
1557

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

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

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

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

    
1630
                //compare whitespace if need
1631
                /*if (startCriticalSubTree) {
1632
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1633
                            data, PERMISSIONERROR);
1634
                }//if*/
1635

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

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

    
1660
    }
1661

    
1662

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

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

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

    
1688
          //delete relation table
1689
          deleteRelations();
1690
          //write relations
1691
           for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1692
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1693
            writeOnlineDataFileIdIntoRelationTable(id);
1694
           }
1695
        }
1696

    
1697
        // clean the subtree record
1698
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1699
    }
1700

    
1701

    
1702

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

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

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

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

    
1757
       Stack tempStack = new Stack();
1758
       while(!nodeStackFromDBTable.isEmpty()){
1759
           tempStack.push(nodeStackFromDBTable.pop());
1760
       }
1761
       comparingNodeStacks(tempStack, nodeStackFromParser);
1762
    }
1763

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

    
1778
          // Pop an element from stack2(stack 2 maybe empty)
1779
          NodeRecord record2 = null;
1780
          try {
1781
              record2 = (NodeRecord) stack2.pop();
1782
          } catch (EmptyStackException ee) {
1783

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

    
1798
      // now stack1 is empty and we should make sure stack2 is empty too
1799
      if (!stack2.isEmpty()) {
1800

    
1801
          MetaCatUtil.debugMessage(
1802
                  "stack2 still have some elements while stack1 "
1803
                          + "is empty! ", 30);
1804
          throw new SAXException(UPDATEACCESSERROR);
1805
      }//if
1806
  }//comparingNodeStacks
1807

    
1808

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

    
1822
        if (topAccessSection != null){
1823
          writeTopLevelAccessRuleToDB();
1824
        }
1825
        //System.out.println("after write top access rules");
1826
    }//writeAccessRuleToDB
1827

    
1828

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

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

    
1881
           // search possible referenced access hashtable
1882
           if (possibleReferencedAccessHash.containsKey(reference))
1883
           {
1884
             AccessSection referenceAccess = (AccessSection)
1885
                         possibleReferencedAccessHash.get(reference);
1886
             return resolveAccessRuleReference(referenceAccess);
1887
           }
1888

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

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

    
1935

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

    
1961
       if (describeIdList == null || describeIdList.isEmpty())
1962
       {
1963
         continue;
1964
       }
1965

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

    
2019
   }//writeAdditonalLevelAccessRuletoDB
2020

    
2021

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

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

    
2061
         }
2062
       }//while
2063

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

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

    
2099
       try
2100
       {
2101

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

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

    
2163
    }//writeGivenAccessRuleIntoDB
2164

    
2165

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

    
2179
        } catch (SQLException e) {
2180
            throw new SAXException(e.getMessage());
2181
        } finally {
2182
            try {
2183
                stmt.close();
2184
            } catch (SQLException ee) {
2185
                throw new SAXException(ee.getMessage());
2186
            }
2187
        }
2188
    }//deletePermissionsInAccessTable
2189

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

    
2218
    }
2219

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

    
2247
    }
2248

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

    
2260
          MetaCatUtil.debugMessage("Access object is null and tried to write "+
2261
                                   "into access subtree table", 30);
2262
          throw new SAXException("The access object is null to write access " +
2263
                                 "sbutree");
2264
        }
2265

    
2266
        String sql = null;
2267
        PreparedStatement pstmt = null;
2268
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
2269
                + "subtreeid, startnodeid, endnodeid) VALUES "
2270
                + " (?, ?, ?, ?, ?, ?)";
2271
        try
2272
        {
2273

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

    
2297
            long endNodeId = accessSection.getEndNodeId();
2298
            String sectionId = accessSection.getSubTreeId();
2299

    
2300
            if (startNodeId ==-1 || endNodeId == -1)
2301
            {
2302
              throw new SAXException("Don't find start node or end node id " +
2303
                                      "for the access subtee");
2304

    
2305
            }
2306

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

    
2346
    }//writeAccessSubtreeIntoDB
2347

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

    
2360
        } catch (SQLException e) {
2361
            throw new SAXException(e.getMessage());
2362
        } finally {
2363
            try {
2364
                stmt.close();
2365
            } catch (SQLException ee) {
2366
                throw new SAXException(ee.getMessage());
2367
            }
2368
        }
2369
    }//deleteAccessSubTreeRecord
2370

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

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

    
2403

    
2404

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

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

    
2440
            // if oldString is null but newString is not null, they are same
2441
            if (same) {
2442
                if (newString != null) {
2443
                    same = false;
2444
                }
2445
            }
2446

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

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

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

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

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

    
2517
        }
2518
        if (newFileWriter != null)
2519
        {
2520
          try
2521
          {
2522
            newFileWriter.close();
2523
          }
2524
          catch (Exception ee)
2525
          {
2526
            throw new SAXException(ee.getMessage());
2527
          }
2528

    
2529
        }
2530

    
2531
    }
2532

    
2533
  }
2534

    
2535

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

    
2548
    /* delete the inline data file */
2549
    private void deleteInlineDataFile(String fileName)
2550
    {
2551

    
2552
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2553
        File inlineDataDirectory = new File(path);
2554
        File newFile = new File(inlineDataDirectory, fileName);
2555
        newFile.delete();
2556

    
2557
    }
2558

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

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

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

    
2647
    }//writeOnlineDataFileIdIntoRelationTable
2648

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

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

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

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

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

    
2786
        }//while
2787

    
2788
        //compare attributes
2789
        for (int i = 0; i < attributes.getLength(); i++) {
2790
            NodeRecord attriNode = null;
2791
            try {
2792
                attriNode = (NodeRecord) unchangableNodeStack.pop();
2793

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

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

    
2838
    }
2839

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

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

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

    
2948

    
2949

    
2950
}
(35-35/64)