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: sgarg $'
11
 *     '$Date: 2006-06-09 13:09:10 -0700 (Fri, 09 Jun 2006) $'
12
 * '$Revision: 3004 $'
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.apache.log4j.Logger;
49
import org.xml.sax.Attributes;
50
import org.xml.sax.SAXException;
51

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

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

    
116
    private boolean processOtherAccess = false;
117

    
118
    private AccessSection accessObject = null;
119

    
120
    private AccessRule accessRule = null;
121

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

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

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

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

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

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

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

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

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

    
165
    private boolean needCheckingAccessModule = false;
166

    
167
    private AccessSection unChangebleTopAccessSubTree = null;
168

    
169
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
170

    
171
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
172

    
173
    private AccessSection topAccessSection;
174

    
175
    private Vector addtionalAccessVector = new Vector();
176

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

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

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

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

    
190
    private Hashtable inlineDataNameSpace = null;
191

    
192
    private FileWriter inlineDataFileWriter = null;
193

    
194
    private String inlineDataFileName = null;
195

    
196
    private int inLineDataIndex = 0;
197

    
198
    private Vector inlineFileIDList = new Vector();
199

    
200
    private boolean inAddtionalMetaData = false;
201

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

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

    
212
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
213

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

    
220
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
221

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

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

    
240
    private int numberOfHitUnWritableInlineData = 0;
241

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
346
            }
347

    
348

    
349
        }
350
        catch (Exception e)
351
        {
352
            logMetacat.error("erorr in Eml200SAXHanlder is "
353
                                     +e.getMessage());
354
            throw new SAXException(e.getMessage());
355
        }
356
    }
357

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

    
372

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

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

    
421
     }
422

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

    
436
        try
437
        {
438

    
439
            pstmt = connection.prepareStatement(sql);
440
            // Increase DBConnection usage count
441
            connection.increaseUsageCount(1);
442
            // Bind the values to the query
443
            pstmt.setString(1, docid);
444
            pstmt.setString(2, DATAACCESSLEVEL);
445
            pstmt.execute();
446

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

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

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

    
502
       try
503
       {
504

    
505
           pstmt = connection.prepareStatement(sql);
506
           // Increase DBConnection usage count
507
           connection.increaseUsageCount(1);
508
           // Bind the values to the query
509
           pstmt.setString(1, docid);
510
           pstmt.setString(2, REFERENCEDLEVEL);
511
           pstmt.execute();
512

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

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

    
558

    
559

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

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

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

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

    
625

    
626
                  // store the distributid and inlinedata filename into a hash
627
                  inlineDistributionIdList.put(distributionId, inlineDataFileName);
628
                }
629

    
630
            }
631
            //==============================================================
632

    
633

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

    
641

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

    
650
                }
651

    
652
                // write the textbuffer into db for parent node.
653
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
654
                        parentNode);
655
                // rest hitTextNode
656
                hitTextNode = false;
657
                // reset textbuffer
658
                textBuffer = null;
659
                textBuffer = new StringBuffer();
660

    
661
            }
662
            //==================================================================
663

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

    
703
                    try {
704
                        // Get dbconnection
705
                        dbConn = DBConnectionPool
706
                                .getDBConnection("DBSAXHandler.startElement");
707
                        serialNumber = dbConn.getCheckOutSerialNumber();
708

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

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

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

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

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

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

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

    
802
              }
803

    
804
          }//for
805

    
806

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

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

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

    
843

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

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

    
872

    
873

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

    
881
                accessRule = new AccessRule();
882

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

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

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

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

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

    
923
            }
924

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

    
965

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

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

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

    
1019
    }
1020

    
1021

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

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

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

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

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

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

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

    
1166

    
1167

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

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

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

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

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

    
1266
                logMetacat.info(
1267
                            "Write text into DB in End Element");
1268

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

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

    
1281
                }
1282
            }//if handle text node
1283

    
1284

    
1285

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

    
1292

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

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

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

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

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

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

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

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

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

    
1366

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

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

    
1400
            }
1401

    
1402

    
1403

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

    
1423

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

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

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

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

    
1469
       }
1470
       return modified;
1471
     }
1472

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

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

    
1510
     }
1511

    
1512

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

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

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

    
1557

    
1558

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

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

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

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

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

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

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

    
1661
    }
1662

    
1663

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

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

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

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

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

    
1702

    
1703

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

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

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

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

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

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

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

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

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

    
1800
          logMetacat.info(
1801
                  "stack2 still have some elements while stack1 "
1802
                          + "is empty! ");
1803
          throw new SAXException(UPDATEACCESSERROR);
1804
      }//if
1805
  }//comparingNodeStacks
1806

    
1807

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

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

    
1827

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

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

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

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

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

    
1934

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

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

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

    
2018
   }//writeAdditonalLevelAccessRuletoDB
2019

    
2020

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

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

    
2060
         }
2061
       }//while
2062

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

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

    
2098
       try
2099
       {
2100

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

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

    
2159
    }//writeGivenAccessRuleIntoDB
2160

    
2161

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

    
2175
        } catch (SQLException e) {
2176
            throw new SAXException(e.getMessage());
2177
        } finally {
2178
            try {
2179
                stmt.close();
2180
            } catch (SQLException ee) {
2181
                throw new SAXException(ee.getMessage());
2182
            }
2183
        }
2184
    }//deletePermissionsInAccessTable
2185

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

    
2214
    }
2215

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

    
2243
    }
2244

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

    
2256
          logMetacat.info("Access object is null and tried to write "+
2257
                                   "into access subtree table");
2258
          throw new SAXException("The access object is null to write access " +
2259
                                 "sbutree");
2260
        }
2261

    
2262
        String sql = null;
2263
        PreparedStatement pstmt = null;
2264
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
2265
                + "subtreeid, startnodeid, endnodeid) VALUES "
2266
                + " (?, ?, ?, ?, ?, ?)";
2267
        try
2268
        {
2269

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

    
2293
            long endNodeId = accessSection.getEndNodeId();
2294
            String sectionId = accessSection.getSubTreeId();
2295

    
2296
            if (startNodeId ==-1 || endNodeId == -1)
2297
            {
2298
              throw new SAXException("Don't find start node or end node id " +
2299
                                      "for the access subtee");
2300

    
2301
            }
2302

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

    
2340
    }//writeAccessSubtreeIntoDB
2341

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

    
2354
        } catch (SQLException e) {
2355
            throw new SAXException(e.getMessage());
2356
        } finally {
2357
            try {
2358
                stmt.close();
2359
            } catch (SQLException ee) {
2360
                throw new SAXException(ee.getMessage());
2361
            }
2362
        }
2363
    }//deleteAccessSubTreeRecord
2364

    
2365
    // open a file writer for writing inline data to file
2366
    private FileWriter createInlineDataFileWriter(String fileName)
2367
            throws SAXException
2368
    {
2369
        FileWriter writer = null;
2370
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2371
        /*
2372
         * File inlineDataDirectory = new File(path);
2373
         */
2374
        String newFile = path + "/" + fileName;
2375
        logMetacat.info("inline file name: " + newFile);
2376
        try {
2377
            // true means append
2378
            writer = new FileWriter(newFile, true);
2379
        } catch (IOException ioe) {
2380
            throw new SAXException(ioe.getMessage());
2381
        }
2382
        return writer;
2383
    }
2384

    
2385
    // write inline data into file system and return file name(without path)
2386
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2387
            throws SAXException
2388
    {
2389
        try {
2390
            writer.write(data.toString());
2391
            writer.flush();
2392
        } catch (Exception e) {
2393
            throw new SAXException(e.getMessage());
2394
        }
2395
    }
2396

    
2397

    
2398

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

    
2424
            // at the end oldstring will be null
2425
            while (oldString != null) {
2426
                oldString = oldStringReader.readLine();
2427
                newString = newStringReader.readLine();
2428
                if (!oldString.equals(newString)) {
2429
                    same = false;
2430
                    break;
2431
                }
2432
            }
2433

    
2434
            // if oldString is null but newString is not null, they are same
2435
            if (same) {
2436
                if (newString != null) {
2437
                    same = false;
2438
                }
2439
            }
2440

    
2441
        } catch (Exception e) {
2442
            throw new McdbException(e.getMessage());
2443
        }
2444
        logMetacat.info("the inline data retrieve from file: " + data);
2445
        return same;
2446
    }
2447

    
2448
   /*
2449
    * Copy a old line file to a new inline file
2450
    */
2451
   public void copyInlineFile(String inlineDistributionId, String newFileName)
2452
           throws SAXException
2453
   {
2454
     if (inlineDistributionId == null || newFileName == null)
2455
     {
2456
       throw new SAXException("Could not copy inline file from old one to new "+
2457
                              "one!");
2458
     }
2459
     // get old file id from previousUnreadable data object
2460
    String oldInlineInternalFileName =
2461
         (String)previousUnreadableInlineDataObjectHash.get(inlineDistributionId);
2462

    
2463
    if (oldInlineInternalFileName == null ||
2464
        oldInlineInternalFileName.trim().equals(""))
2465
    {
2466
      throw new SAXException("Could not copy inline file from old one to new "+
2467
                              "one because can't find old file name");
2468
    }
2469
    logMetacat.info("in handle inline data");
2470
    logMetacat.info("the inline data file name from xml_access is: "
2471
                                 + oldInlineInternalFileName);
2472

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

    
2491
      }
2492
    }
2493
    catch (Exception e)
2494
    {
2495
      throw new SAXException(e.getMessage());
2496
    }
2497
    finally
2498
    {
2499
        if (oldFileReader != null)
2500
        {
2501
          try
2502
          {
2503
            oldFileReader.close();
2504
          }
2505
          catch (Exception ee)
2506
          {
2507
            throw new SAXException(ee.getMessage());
2508
          }
2509

    
2510
        }
2511
        if (newFileWriter != null)
2512
        {
2513
          try
2514
          {
2515
            newFileWriter.close();
2516
          }
2517
          catch (Exception ee)
2518
          {
2519
            throw new SAXException(ee.getMessage());
2520
          }
2521

    
2522
        }
2523

    
2524
    }
2525

    
2526
  }
2527

    
2528

    
2529
    // if xml file failed to upload, we need to call this method to delete
2530
    // the inline data already in file system
2531
    public void deleteInlineFiles()
2532
    {
2533
        if (!inlineFileIDList.isEmpty()) {
2534
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2535
                String fileName = (String) inlineFileIDList.elementAt(i);
2536
                deleteInlineDataFile(fileName);
2537
            }
2538
        }
2539
    }
2540

    
2541
    /* delete the inline data file */
2542
    private void deleteInlineDataFile(String fileName)
2543
    {
2544

    
2545
        String path = MetaCatUtil.getOption("inlinedatafilepath");
2546
        File inlineDataDirectory = new File(path);
2547
        File newFile = new File(inlineDataDirectory, fileName);
2548
        newFile.delete();
2549

    
2550
    }
2551

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

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

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

    
2640
    }//writeOnlineDataFileIdIntoRelationTable
2641

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

    
2669
          if (!AccessionNumber.accNumberUsed(docid))
2670
          {
2671
            return docid;
2672
          }
2673
          PermissionController controller = new
2674
              PermissionController(accessionNumber);
2675
          if (controller.hasPermission(
2676
              user, groups, AccessControlInterface.ALLSTRING))
2677
          {
2678
            return docid;
2679
          }
2680
          else
2681
          {
2682
            throw new SAXException("User does not have permission to update " +
2683
                  "of access rules for data file "+ docid);
2684
          }
2685
        }//try
2686
        catch(Exception e)
2687
        {
2688
          logMetacat.error("Error in " +
2689
                                "Eml200SAXHanlder.handleOnlineUrlDataFile is " +
2690
                                 e.getMessage());
2691
          throw new SAXException(e.getMessage());
2692
        }
2693
      }
2694
      return docid;
2695
    }
2696

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

    
2739
        //compare namespace
2740
        Enumeration nameEn = nameSpaces.keys();
2741
        while (nameEn.hasMoreElements()) {
2742
            //Get namespacke node stack (element node)
2743
            NodeRecord nameNode = null;
2744
            try {
2745
                nameNode = (NodeRecord) unchangableNodeStack.pop();
2746
            } catch (EmptyStackException ee) {
2747
                logMetacat.error(
2748
                        "Node stack is empty for namespace data");
2749
                throw new SAXException(error);
2750
            }
2751

    
2752
            String prefixName = (String) nameEn.nextElement();
2753
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
2754
            if (!nameNode.getNodeType().equals("NAMESPACE")
2755
                    || !prefixName.equals(nameNode.getNodeName())
2756
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
2757
                logMetacat.info("Inconsistence happend: ");
2758
                logMetacat.info(
2759
                        "current node type from xml is NAMESPACE");
2760
                logMetacat.info("node type from stack: "
2761
                        + nameNode.getNodeType());
2762
                logMetacat.info("current node name from xml is: "
2763
                        + prefixName);
2764
                logMetacat.info("node name from stack: "
2765
                        + nameNode.getNodeName());
2766
                logMetacat.info("current node data from xml is: "
2767
                        + nameSpaceUri);
2768
                logMetacat.info("node data from stack: "
2769
                        + nameNode.getNodeData());
2770
                logMetacat.info("node id is: " + nameNode.getNodeId());
2771
                throw new SAXException(error);
2772
            }
2773

    
2774
        }//while
2775

    
2776
        //compare attributes
2777
        for (int i = 0; i < attributes.getLength(); i++) {
2778
            NodeRecord attriNode = null;
2779
            try {
2780
                attriNode = (NodeRecord) unchangableNodeStack.pop();
2781

    
2782
            } catch (EmptyStackException ee) {
2783
                logMetacat.error(
2784
                        "Node stack is empty for attribute data");
2785
                throw new SAXException(error);
2786
            }
2787
            String attributeName = attributes.getQName(i);
2788
            String attributeValue = attributes.getValue(i);
2789
            logMetacat.info(
2790
                    "current node type from xml is ATTRIBUTE ");
2791
            logMetacat.info("node type from stack: "
2792
                    + attriNode.getNodeType());
2793
            logMetacat.info("current node name from xml is: "
2794
                    + attributeName);
2795
            logMetacat.info("node name from stack: "
2796
                    + attriNode.getNodeName());
2797
            logMetacat.info("current node data from xml is: "
2798
                    + attributeValue);
2799
            logMetacat.info("node data from stack: "
2800
                    + attriNode.getNodeData());
2801
            logMetacat.info("node id  is: " + attriNode.getNodeId());
2802

    
2803
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
2804
                    || !attributeName.equals(attriNode.getNodeName())
2805
                    || !attributeValue.equals(attriNode.getNodeData())) {
2806
                logMetacat.info("Inconsistence happend: ");
2807
                logMetacat.info(
2808
                        "current node type from xml is ATTRIBUTE ");
2809
                logMetacat.info("node type from stack: "
2810
                        + attriNode.getNodeType());
2811
                logMetacat.info("current node name from xml is: "
2812
                        + attributeName);
2813
                logMetacat.info("node name from stack: "
2814
                        + attriNode.getNodeName());
2815
                logMetacat.info("current node data from xml is: "
2816
                        + attributeValue);
2817
                logMetacat.info("node data from stack: "
2818
                        + attriNode.getNodeData());
2819
                logMetacat.info("node is: " + attriNode.getNodeId());
2820
                throw new SAXException(error);
2821
            }
2822
        }//for
2823

    
2824
    }
2825

    
2826
    /* mehtod to compare current text node and node in db */
2827
    private void compareTextNode(Stack nodeStack, StringBuffer text,
2828
            String error) throws SAXException
2829
    {
2830
        NodeRecord node = null;
2831
        //get node from current stack
2832
        try {
2833
            node = (NodeRecord) nodeStack.pop();
2834
        } catch (EmptyStackException ee) {
2835
            logMetacat.error(
2836
                    "Node stack is empty for text data in startElement");
2837
            throw new SAXException(error);
2838
        }
2839
        logMetacat.info(
2840
                "current node type from xml is TEXT in start element");
2841
        logMetacat.info("node type from stack: " + node.getNodeType());
2842
        logMetacat.info("current node data from xml is: "
2843
                + text.toString());
2844
        logMetacat.info("node data from stack: " + node.getNodeData());
2845
        logMetacat.info("node name from stack: " + node.getNodeName());
2846
        logMetacat.info("node is: " + node.getNodeId());
2847
        if (!node.getNodeType().equals("TEXT")
2848
                || !(text.toString()).equals(node.getNodeData())) {
2849
            logMetacat.info("Inconsistence happend: ");
2850
            logMetacat.info(
2851
                    "current node type from xml is TEXT in start element");
2852
            logMetacat.info("node type from stack: "
2853
                    + node.getNodeType());
2854
            logMetacat.info("current node data from xml is: "
2855
                    + text.toString());
2856
            logMetacat.info("node data from stack: "
2857
                    + node.getNodeData());
2858
            logMetacat.info("node name from stack: "
2859
                    + node.getNodeName());
2860
            logMetacat.info("node is: " + node.getNodeId());
2861
            throw new SAXException(error);
2862
        }//if
2863
    }
2864

    
2865
    /* Comparet comment from xml and db */
2866
    private void compareCommentNode(Stack nodeStack, String string, String error)
2867
            throws SAXException
2868
    {
2869
        NodeRecord node = null;
2870
        try {
2871
            node = (NodeRecord) nodeStack.pop();
2872
        } catch (EmptyStackException ee) {
2873
            logMetacat.error("the stack is empty for comment data");
2874
            throw new SAXException(error);
2875
        }
2876
        logMetacat.info("current node type from xml is COMMENT");
2877
        logMetacat.info("node type from stack: " + node.getNodeType());
2878
        logMetacat.info("current node data from xml is: " + string);
2879
        logMetacat.info("node data from stack: " + node.getNodeData());
2880
        logMetacat.info("node is from stack: " + node.getNodeId());
2881
        // if not consistent terminate program and throw a exception
2882
        if (!node.getNodeType().equals("COMMENT")
2883
                || !string.equals(node.getNodeData())) {
2884
            logMetacat.info("Inconsistence happend: ");
2885
            logMetacat.info("current node type from xml is COMMENT");
2886
            logMetacat.info("node type from stack: "
2887
                    + node.getNodeType());
2888
            logMetacat.info(
2889
                    "current node data from xml is: " + string);
2890
            logMetacat.info("node data from stack: "
2891
                    + node.getNodeData());
2892
            logMetacat.info("node is from stack: " + node.getNodeId());
2893
            throw new SAXException(error);
2894
        }//if
2895
    }
2896

    
2897
    /* Compare whitespace from xml and db */
2898
   private void compareWhiteSpace(Stack nodeStack, String string, String error)
2899
           throws SAXException
2900
   {
2901
       NodeRecord node = null;
2902
       try {
2903
           node = (NodeRecord) nodeStack.pop();
2904
       } catch (EmptyStackException ee) {
2905
           logMetacat.error("the stack is empty for whitespace data");
2906
           throw new SAXException(error);
2907
       }
2908
       if (!node.getNodeType().equals("TEXT")
2909
               || !string.equals(node.getNodeData())) {
2910
           logMetacat.info("Inconsistence happend: ");
2911
           logMetacat.info(
2912
                   "current node type from xml is WHITESPACE TEXT");
2913
           logMetacat.info("node type from stack: "
2914
                   + node.getNodeType());
2915
           logMetacat.info(
2916
                   "current node data from xml is: " + string);
2917
           logMetacat.info("node data from stack: "
2918
                   + node.getNodeData());
2919
           logMetacat.info("node is from stack: " + node.getNodeId());
2920
           throw new SAXException(error);
2921
       }//if
2922
   }
2923

    
2924

    
2925

    
2926
}
(34-34/65)