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

    
28
package edu.ucsb.nceas.metacat;
29

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

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

    
51
import edu.ucsb.nceas.metacat.database.DBConnection;
52
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
53
import edu.ucsb.nceas.metacat.properties.PropertyService;
54
import edu.ucsb.nceas.metacat.util.AuthUtil;
55
import edu.ucsb.nceas.metacat.util.DocumentUtil;
56
import edu.ucsb.nceas.metacat.util.MetacatUtil;
57
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
58

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

    
119
    // now additionalAccess will be explained as distribution access control
120
    // - data file
121
    private boolean processAdditionalAccess = false;
122

    
123
    private boolean processOtherAccess = false;
124

    
125
    private AccessSection accessObject = null;
126

    
127
    private AccessRule accessRule = null;
128

    
129
    private Vector describesId = new Vector(); // store the ids in
130
                                               //additionalmetadata/describes
131

    
132
    //store all distribution element id for online url. key is the distribution
133
    // id and  data  is url
134
    private Hashtable onlineURLDistributionIdList = new Hashtable();
135
    // distribution/oneline/url will store this vector if distribution doesn't
136
    // have a id.
137
    private Vector onlineURLDistributionListWithoutId = new Vector();
138

    
139
    //store all distribution element id for online other distribution, such as
140
    // connection or connectiondefination. key is the distribution id
141
    // and  data  is distribution id
142
    private Hashtable onlineOtherDistributionIdList = new Hashtable();
143

    
144
    //store all distribution element id for inline data.
145
    // key is the distribution id, data is the internal inline id
146
    private Hashtable inlineDistributionIdList = new Hashtable();
147

    
148
    //store all distribution element id for off line data.
149
    // key is the distribution id, data is the id too.
150
    private Hashtable offlineDistributionIdList = new Hashtable();
151

    
152
    // a hash to stored all distribution id, both key and value are id itself
153
    private Hashtable distributionAllIdList = new Hashtable();
154

    
155
    // temporarily store distribution id
156
    private String distributionId = null;
157

    
158
    // flag to indicate to handle distrubiton
159
    private boolean proccessDistribution = false;
160

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

    
172
    private boolean needCheckingAccessModule = false;
173

    
174
    private AccessSection unChangebleTopAccessSubTree = null;
175

    
176
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
177

    
178
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
179

    
180
    private AccessSection topAccessSection;
181

    
182
    private Vector addtionalAccessVector = new Vector();
183

    
184
    // key is subtree id and value is accessSection object
185
    private Hashtable possibleReferencedAccessHash = new Hashtable();
186

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

    
191
    // vector stored the data file id which will be write into relation table
192
    private Vector onlineDataFileIdInRelationVector = new Vector();
193

    
194
    // Indicator of inline data
195
    private boolean handleInlineData = false;
196

    
197
    private Hashtable inlineDataNameSpace = null;
198

    
199
    private FileWriter inlineDataFileWriter = null;
200

    
201
    private String inlineDataFileName = null;
202

    
203
    private int inLineDataIndex = 0;
204

    
205
    private Vector inlineFileIDList = new Vector();
206

    
207
    private boolean inAddtionalMetaData = false;
208

    
209
    //user has unwritable inline data object when it updates a document
210
    private boolean unWritableInlineDataObject = false;
211
    //user has unreadable inline data when it updates a dcoument
212
    private boolean unReadableInlineDataObject = false;
213

    
214
    // the hashtable contains the info from xml_access table which
215
    // inline data the user can't read when user update a document.
216
    // The key in hashtable is subtree id and data is the inline data internal
217
    // file name.
218

    
219
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
220

    
221
    // the hashtable contains the info from xml_access table which
222
    // inline data the user can't write when user update a document.
223
    // The key in hashtable is subtree id and data is the inline data internal
224
    // file name.
225
    private Hashtable previousUnwritableInlineDataObjectHash = new Hashtable();
226

    
227
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
228

    
229
    //This hashtable will stored the id which already has additional access
230
    // control. So the top level access control will ignore them.
231
    private Hashtable onlineURLIdHasAddtionalAccess   = new Hashtable();
232

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

    
247
    private int numberOfHitUnWritableInlineData = 0;
248

    
249
    // Constant
250
    private static final String EML = "eml";
251

    
252
    private static final String DESCRIBES = "describes";
253

    
254
    private static final String ADDITIONALMETADATA = "additionalMetadata";
255

    
256
    private static final String ORDER = "order";
257

    
258
    private static final String ID = "id";
259

    
260
    private static final String REFERENCES = "references";
261

    
262
    public static final String INLINE = "inline";
263

    
264
    private static final String ONLINE = "online";
265

    
266
    private static final String OFFLINE = "offline";
267

    
268
    private static final String CONNECTION = "connection";
269

    
270
    private static final String CONNECTIONDEFINITION = "connectionDefinition";
271

    
272
    private static final String URL = "url";
273

    
274
    private static final String PERMISSIONERROR = "User tried to update a subtree "
275
        + "when they don't have write permission!";
276

    
277
    private static final String UPDATEACCESSERROR = "User tried to update an "
278
        + "access module when they don't have \"ALL\" permission!";
279

    
280
    public static final String TOPLEVEL = "top";
281

    
282
    public static final String DATAACCESSLEVEL = "dataAccess";
283

    
284
    // this level is for the access module which is not in top or additional
285
    // place, but it was referenced by top or additional
286
    private static final String REFERENCEDLEVEL = "referenced";
287

    
288
    private static final String RELATION = "Provides info for";
289

    
290
    private static final String DISTRIBUTION = "distribution";
291

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

    
323
            //If the action is update and user doesn't have "ALL" permission
324
            // we need to check if user update access subtree
325
            if (action != null && action.equals("UPDATE")
326
                    && !control.hasPermission(user, groups,
327
                            AccessControlInterface.ALLSTRING) 
328
                            && !AuthUtil.isAdministrator(user, groups))
329
            {
330
                needCheckingAccessModule = true;
331
                unChangebleTopAccessSubTree = getTopAccessSubTreeFromDB();
332
                unChangebleAdditionalAccessSubTreeVector =
333
                                         getAdditionalAccessSubTreeListFromDB();
334
                unChangebleReferencedAccessSubTreeHash =
335
                                         getReferencedAccessSubTreeListFromDB();
336
            }
337

    
338
            //Here is for  data object checking.
339
            if (action != null && action.equals("UPDATE"))
340
            {
341
              //info about inline data object which user doesn't have read
342
              //permission the info come from xml_access table
343
              previousUnreadableInlineDataObjectHash = PermissionController.
344
                            getUnReadableInlineDataIdList(docid, user,
345
                                                          groups, true);
346

    
347
              //info about data object which user doesn't have write permission
348
              // the info come from xml_accesss table
349
              previousUnwritableInlineDataObjectHash = PermissionController.
350
                            getUnWritableInlineDataIdList(docid, user,
351
                                                          groups, true);
352

    
353
            }
354

    
355

    
356
        }
357
        catch (Exception e)
358
        {
359
            logMetacat.error("error in Eml200SAXHandler is " + e.getMessage());
360
            throw new SAXException(e.getMessage());
361
        }
362
    }
363

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

    
378

    
379
       try
380
       {
381
            pstmt = connection.prepareStatement(sql);
382
            // Increase DBConnection usage count
383
            connection.increaseUsageCount(1);
384
            // Bind the values to the query
385
            pstmt.setString(1, docid);
386
            pstmt.setString(2, TOPLEVEL);
387
            pstmt.execute();
388

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

    
427
     }
428

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

    
442
        try
443
        {
444

    
445
            pstmt = connection.prepareStatement(sql);
446
            // Increase DBConnection usage count
447
            connection.increaseUsageCount(1);
448
            // Bind the values to the query
449
            pstmt.setString(1, docid);
450
            pstmt.setString(2, DATAACCESSLEVEL);
451
            pstmt.execute();
452

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

    
470
            }
471
            pstmt.close();
472
        }//try
473
        catch (SQLException e)
474
        {
475
            throw new SAXException(
476
                    "EMLSAXHandler.getAddtionalAccessSubTreeListFromDB(): "
477
                            + e.getMessage());
478
        }//catch
479
        finally
480
        {
481
            try
482
            {
483
                pstmt.close();
484
            }
485
            catch (SQLException ee)
486
            {
487
                throw new SAXException(
488
                        "EMLSAXHandler.getAccessSubTreeListFromDB(): "
489
                                + ee.getMessage());
490
            }
491
        }//finally
492
        return result;
493
    }
494

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

    
508
       try
509
       {
510

    
511
           pstmt = connection.prepareStatement(sql);
512
           // Increase DBConnection usage count
513
           connection.increaseUsageCount(1);
514
           // Bind the values to the query
515
           pstmt.setString(1, docid);
516
           pstmt.setString(2, REFERENCEDLEVEL);
517
           pstmt.execute();
518

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

    
539
           }
540
           pstmt.close();
541
       }//try
542
       catch (SQLException e)
543
       {
544
           throw new SAXException(
545
                   "EMLSAXHandler.getReferencedAccessSubTreeListFromDB(): "
546
                           + e.getMessage());
547
       }//catch
548
       finally
549
       {
550
           try
551
           {
552
               pstmt.close();
553
           }
554
           catch (SQLException ee)
555
           {
556
               throw new SAXException(
557
                       "EMLSAXHandler.getReferencedSubTreeListFromDB(): "
558
                               + ee.getMessage());
559
           }
560
       }//finally
561
       return result;
562
   }
563

    
564

    
565

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

    
577
        DBSAXNode parentNode = null;
578
        DBSAXNode currentNode = null;
579
        // none inline part
580
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
581
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
582
        if (!handleInlineData)
583
        {
584
            // Get a reference to the parent node for the id
585
            try
586
            {
587
                parentNode = (DBSAXNode) nodeStack.peek();
588
            }
589
            catch (EmptyStackException e)
590
            {
591
                parentNode = null;
592
            }
593

    
594
            //start handle inline data
595
            //=====================================================
596
            if (qName.equals(INLINE) && !inAddtionalMetaData)
597
            {
598
                handleInlineData = true;
599
                inLineDataIndex++;
600
                //intitialize namespace hash for in line data
601
                inlineDataNameSpace = new Hashtable();
602
                //initialize file writer
603
                String docidWithoutRev = DocumentUtil.getDocIdFromString(docid);
604
                String seperator = ".";
605
                try {
606
					seperator = PropertyService.getProperty("document.accNumSeparator");
607
				} catch (PropertyNotFoundException pnfe) {
608
					logMetacat.error("Could not get property 'accNumSeparator'.  " 
609
							+ "Setting separator to '.': "+ pnfe.getMessage());
610
				}
611
                // the new file name will look like docid.rev.2
612
                inlineDataFileName = docidWithoutRev + seperator + revision
613
                        + seperator + inLineDataIndex;
614
                inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
615
                // put the inline file id into a vector. If upload failed,
616
                // metacat will
617
                // delete the inline data file
618
                inlineFileIDList.add(inlineDataFileName);
619

    
620
                // put distribution id and inline file id into a  hash
621
                if (distributionId != null)
622
                {
623
                  //check to see if this inline data is readable or writable to
624
                  // this user
625
                  if (!previousUnreadableInlineDataObjectHash.isEmpty() &&
626
                       previousUnreadableInlineDataObjectHash.containsKey(distributionId))
627
                  {
628
                      unReadableInlineDataObject = true;
629
                  }
630
                  if (!previousUnwritableInlineDataObjectHash.isEmpty() &&
631
                       previousUnwritableInlineDataObjectHash.containsKey(distributionId))
632
                  {
633
                     unWritableInlineDataObject = true;
634
                     numberOfHitUnWritableInlineData++;
635
                  }
636

    
637

    
638
                  // store the distributid and inlinedata filename into a hash
639
                  inlineDistributionIdList.put(distributionId, inlineDataFileName);
640
                }
641

    
642
            }
643
            //==============================================================
644

    
645

    
646
            // If hit a text node, we need write this text for current's parent
647
            // node
648
            // This will happend if the element is mixted
649
            //==============================================================
650
            if (hitTextNode && parentNode != null)
651
            {
652

    
653

    
654
                if (needCheckingAccessModule
655
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
656
                    // stored the pull out nodes into storedNode stack
657
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
658
                            null, null, MetacatUtil.normalize(textBuffer
659
                                    .toString()));
660
                    storedAccessNodeStack.push(nodeElement);
661

    
662
                }
663

    
664
                // write the textbuffer into db for parent node.
665
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
666
                        parentNode);
667
                // rest hitTextNode
668
                hitTextNode = false;
669
                // reset textbuffer
670
                textBuffer = null;
671
                textBuffer = new StringBuffer();
672

    
673
            }
674
            //==================================================================
675

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

    
715
                    try {
716
                        // Get dbconnection
717
                        dbConn = DBConnectionPool
718
                                .getDBConnection("DBSAXHandler.startElement");
719
                        serialNumber = dbConn.getCheckOutSerialNumber();
720

    
721
                        Statement stmt = dbConn.createStatement();
722
                        ResultSet rs = stmt
723
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
724
                                        + "WHERE entry_type = 'Schema' "
725
                                        + "AND public_id = '" + doctype + "'");
726
                        boolean hasRow = rs.next();
727
                        if (hasRow) {
728
                            catalogid = rs.getString(1);
729
                        }
730
                        stmt.close();
731
                        //System.out.println("here!!!!!!!!!!!!!!!!!!2");
732
                    }//try
733
                    finally {
734
                        // Return dbconnection
735
                        DBConnectionPool.returnDBConnection(dbConn,
736
                                serialNumber);
737
                    }//finally
738

    
739
                    //create documentImpl object by the constructor which can
740
                    // specify
741
                    //the revision
742
                    if (!super.getIsRevisionDoc())
743
                    {
744
                       
745
                       currentDocument = new DocumentImpl(connection, rootNode
746
                            .getNodeID(), docname, doctype, docid, revision,
747
                            action, user, this.pub, catalogid, this.serverCode, 
748
                            createDate, updateDate);
749
                    }
750
                   
751

    
752
                } catch (Exception ane) {
753
                    throw (new SAXException(
754
                            "Error in EMLSaxHandler.startElement " + action,
755
                            ane));
756
                }
757
                
758
            }
759
            //==================================================================
760

    
761
            // node
762
            //==================================================================
763
            // Create the current node representation
764
            currentNode = new DBSAXNode(connection, qName, localName,
765
                    parentNode, rootNode.getNodeID(), docid,
766
                    doctype);
767
            // Use a local variable to store the element node id
768
            // If this element is a start point of subtree(section), it will be
769
            // stored
770
            // otherwise, it will be discated
771
            long startNodeId = currentNode.getNodeID();
772
            // Add all of the namespaces
773
            String prefix = null;
774
            String nsuri = null;
775
            Enumeration prefixes = namespaces.keys();
776
            while (prefixes.hasMoreElements())
777
            {
778
                prefix = (String) prefixes.nextElement();
779
                nsuri = (String) namespaces.get(prefix);
780
                endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
781
            }
782

    
783
            //=================================================================
784
           // attributes
785
           // Add all of the attributes
786
          for (int i = 0; i < atts.getLength(); i++)
787
          {
788
              String attributeName = atts.getQName(i);
789
              String attributeValue = atts.getValue(i);
790
              endNodeId = currentNode.setAttribute(attributeName,
791
                      attributeValue, docid);
792

    
793
              // To handle name space and schema location if the attribute
794
              // name is
795
              // xsi:schemaLocation. If the name space is in not in catalog
796
              // table
797
              // it will be regeistered.
798
              if (attributeName != null
799
                      && attributeName
800
                              .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
801
                  SchemaLocationResolver resolver = new SchemaLocationResolver(
802
                          attributeValue);
803
                  resolver.resolveNameSpace();
804

    
805
              }
806
              else if (attributeName != null && attributeName.equals(ID) &&
807
                       currentNode.getTagName().equals(DISTRIBUTION) &&
808
                       !inAddtionalMetaData)
809
              {
810
                 // this is a distribution element and the id is distributionID
811
                 distributionId = attributeValue;
812
                 distributionAllIdList.put(distributionId, distributionId);
813

    
814
              }
815

    
816
          }//for
817

    
818

    
819
           //=================================================================
820

    
821
            // handle access stuff
822
            //==================================================================
823
            if (localName.equals(ACCESS))
824
            {
825
                //make sure the access is top level
826
                // this mean current node's parent's parent should be "eml"
827
                DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
828
                                                                    // parent
829
                                                                    // node
830
                //peek out grandParentNode
831
                DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
832
                // put parent node back
833
                nodeStack.push(tmpNode);
834
                String grandParentTag = grandParentNode.getTagName();
835
                if (grandParentTag.equals(EML) && !inAddtionalMetaData)
836
                {
837
                  processTopLeverAccess = true;
838

    
839
                }
840
                else if ( !inAddtionalMetaData )
841
                {
842
                  // process other access embedded into resource level
843
                  // module
844
                  processOtherAccess = true;
845
                }
846
                else
847
                {
848
                  // this for access in additional data which don't have
849
                  // described element. If it has a descirbed element,
850
                  // this code would hurt any thing
851
                  processAdditionalAccess = true;
852
                  logMetacat.warn("accessing process addtional access true when meet access");
853
                }
854

    
855

    
856
                // create access object
857
                accessObject = new AccessSection();
858
                // set permission order
859
                String permOrder = currentNode.getAttribute(ORDER);
860
                accessObject.setPermissionOrder(permOrder);
861
                // set access id
862
                String accessId = currentNode.getAttribute(ID);
863
                accessObject.setSubTreeId(accessId);
864
                // for additional access subtree, the  start of node id should
865
                // be describe element. We also stored the start access element
866
                // node id too.
867
                if (processAdditionalAccess)
868
                {
869
                  accessObject.setStartedDescribesNodeId(firstDescribesNodeId);
870
                  accessObject.setControlLevel(DATAACCESSLEVEL);
871
                }
872
                else if (processTopLeverAccess)
873
                {
874
                  accessObject.setControlLevel(TOPLEVEL);
875
                }
876
                else if (processOtherAccess)
877
                {
878
                  accessObject.setControlLevel(REFERENCEDLEVEL);
879
                }
880

    
881
                accessObject.setStartNodeId(startNodeId);
882
                accessObject.setDocId(docid);
883

    
884

    
885

    
886
            }
887
            // Set up a access rule for allow
888
            else if (parentNode.getTagName() != null
889
                    && (parentNode.getTagName()).equals(ACCESS)
890
                    && localName.equals(ALLOW))
891
           {
892

    
893
                accessRule = new AccessRule();
894

    
895
                //set permission type "allow"
896
                accessRule.setPermissionType(ALLOW);
897

    
898
            }
899
            // set up an access rule for den
900
            else if (parentNode.getTagName() != null
901
                    && (parentNode.getTagName()).equals(ACCESS)
902
                    && localName.equals(DENY))
903
           {
904
                accessRule = new AccessRule();
905
                //set permission type "allow"
906
                accessRule.setPermissionType(DENY);
907
            }
908

    
909
            //=================================================================
910
            // some other independ stuff
911

    
912
            // Add the node to the stack, so that any text data can be
913
            // added as it is encountered
914
            nodeStack.push(currentNode);
915
            // Add the node to the vector used by thread for writing XML Index
916
            nodeIndex.addElement(currentNode);
917

    
918
            // store access module element and attributes into stored stack
919
            if (needCheckingAccessModule
920
                    && (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
921
            {
922
                // stored the pull out nodes into storedNode stack
923
                NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
924
                        localName, prefix, MetacatUtil.normalize(null));
925
                storedAccessNodeStack.push(nodeElement);
926
                for (int i = 0; i < atts.getLength(); i++) {
927
                    String attributeName = atts.getQName(i);
928
                    String attributeValue = atts.getValue(i);
929
                    NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2,
930
                            "ATTRIBUTE", attributeName, null, MetacatUtil
931
                                    .normalize(attributeValue));
932
                    storedAccessNodeStack.push(nodeAttribute);
933
                }
934

    
935
            }
936

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

    
977

    
978
             //==================================================================
979
            // reset name space
980
            namespaces = null;
981
            namespaces = new Hashtable();
982

    
983
        }//not inline data
984
        // inline data
985
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
986
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
987
        else
988
        {
989
            // we don't buffer the inline data in characters() method
990
            // so start character don't need to hand text node.
991

    
992
            // inline data may be the xml format.
993
            StringBuffer inlineElements = new StringBuffer();
994
            inlineElements.append("<").append(qName);
995
            // append attributes
996
            for (int i = 0; i < atts.getLength(); i++) {
997
                String attributeName = atts.getQName(i);
998
                String attributeValue = atts.getValue(i);
999
                inlineElements.append(" ");
1000
                inlineElements.append(attributeName);
1001
                inlineElements.append("=\"");
1002
                inlineElements.append(attributeValue);
1003
                inlineElements.append("\"");
1004
            }
1005
            // append namespace
1006
            String prefix = null;
1007
            String nsuri = null;
1008
            Enumeration prefixes = inlineDataNameSpace.keys();
1009
            while (prefixes.hasMoreElements()) {
1010
                prefix = (String) prefixes.nextElement();
1011
                nsuri =  (String)  inlineDataNameSpace.get(prefix);
1012
                inlineElements.append(" ");
1013
                inlineElements.append("xmlns:");
1014
                inlineElements.append(prefix);
1015
                inlineElements.append("=\"");
1016
                inlineElements.append(nsuri);
1017
                inlineElements.append("\"");
1018
            }
1019
            inlineElements.append(">");
1020
            //reset inline data name space
1021
            inlineDataNameSpace = null;
1022
            inlineDataNameSpace = new Hashtable();
1023
            //write inline data into file
1024
            logMetacat.info("the inline element data is: "
1025
                    + inlineElements.toString());
1026
            writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
1027
        }//else
1028
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1029
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1030

    
1031
    }
1032

    
1033

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

    
1063
                }
1064
                textBuffer = null;
1065
                textBuffer = new StringBuffer();
1066
            }
1067
        }
1068
        else
1069
        {
1070
            // this is inline data and write file system directly
1071
            // we don't need to buffered it.
1072
            StringBuffer inlineText = new StringBuffer();
1073
            inlineText.append(new String(cbuf, start, len));
1074
            logMetacat.info(
1075
                    "The inline text data write into file system: "
1076
                            + inlineText.toString());
1077
            writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
1078
        }
1079
    }
1080

    
1081
    /** SAX Handler that is called at the end of each XML element */
1082
    public void endElement(String uri, String localName, String qName)
1083
            throws SAXException
1084
    {
1085
        logMetacat.info("End ELEMENT " + qName);
1086

    
1087
        // when close inline element
1088
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1089
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1090
        if (localName.equals(INLINE) && handleInlineData)
1091
        {
1092
            // Get the node from the stack
1093
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1094
            String currentTag = currentNode.getTagName();
1095
            logMetacat.info("End of inline data");
1096
            // close file writer
1097
            try
1098
            {
1099
                inlineDataFileWriter.close();
1100
                handleInlineData = false;
1101
            }
1102
            catch (IOException ioe)
1103
            {
1104
                throw new SAXException(ioe.getMessage());
1105
            }
1106

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

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

    
1160
            }//else
1161
            // put inline data file name into text buffer (without path)
1162
            textBuffer = new StringBuffer(inlineDataFileName);
1163
            // write file name into db
1164
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1165
                    currentNode);
1166
            // reset textbuff
1167
            textBuffer = null;
1168
            textBuffer = new StringBuffer();
1169
            // resetinlinedata file name
1170
            inlineDataFileName = null;
1171
            unWritableInlineDataObject = false;
1172
            unReadableInlineDataObject = false;
1173
            return;
1174
        }
1175
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1176
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1177

    
1178

    
1179

    
1180
        // close element which is not in inline data
1181
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1182
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1183
        if (!handleInlineData)
1184
        {
1185
            // Get the node from the stack
1186
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1187
            String currentTag = currentNode.getTagName();
1188

    
1189
            // If before the end element, the parser hit text nodes and store
1190
            // them
1191
            // into the buffer, write the buffer to data base. The reason we
1192
            // put
1193
            // write database here is for xerces some time split text node
1194
            if (hitTextNode)
1195
            {
1196
                // get access value
1197
                String data = null;
1198
                // add principal
1199
                if (currentTag.equals(PRINCIPAL) && accessRule != null)
1200
                {
1201
                    data = (textBuffer.toString()).trim();
1202
                    accessRule.addPrincipal(data);
1203

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

    
1245
                }
1246
                else if (currentTag.equals(REFERENCES) && proccessDistribution)
1247
                {
1248
                  // get reference for distribution
1249
                  data = (textBuffer.toString()).trim();
1250
                  // we only stored the distribution reference which itself
1251
                  // has a id
1252
                  if (distributionId != null)
1253
                  {
1254
                    distributionReferenceList.put(distributionId, data);
1255
                  }
1256

    
1257
                }
1258
                else if (currentTag.equals(URL) && !inAddtionalMetaData)
1259
                {
1260
                    //handle online data, make sure its'parent is online
1261
                    DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1262
                    if (parentNode != null && parentNode.getTagName() != null
1263
                            && parentNode.getTagName().equals(ONLINE))
1264
                    {
1265
                        data = (textBuffer.toString()).trim();
1266
                        if (distributionId != null)
1267
                        {
1268
                          onlineURLDistributionIdList.put(distributionId, data);
1269
                        }
1270
                        else
1271
                        {
1272
                          onlineURLDistributionListWithoutId.add(data);
1273
                        }
1274
                    }//if
1275
                }//else if
1276
                // write text to db if it is not inline data
1277

    
1278
                logMetacat.info(
1279
                            "Write text into DB in End Element");
1280

    
1281
                 // write text node into db
1282
                 endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1283
                            currentNode);
1284

    
1285
                if (needCheckingAccessModule
1286
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1287
                    // stored the pull out nodes into storedNode stack
1288
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1289
                            null, null, MetacatUtil.normalize(textBuffer
1290
                                    .toString()));
1291
                    storedAccessNodeStack.push(nodeElement);
1292

    
1293
                }
1294
            }//if handle text node
1295

    
1296

    
1297

    
1298
            //set hitText false
1299
            hitTextNode = false;
1300
            // reset textbuff
1301
            textBuffer = null;
1302
            textBuffer = new StringBuffer();
1303

    
1304

    
1305
            // access stuff
1306
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY))
1307
            {
1308
                // finish parser a ccess rule and assign it to new one
1309
                AccessRule newRule = accessRule;
1310
                //add the new rule to access section object
1311
                accessObject.addAccessRule(newRule);
1312
                // reset access rule
1313
                accessRule = null;
1314
            }// ALLOW or DENY
1315
            else if (currentTag.equals(ACCESS))
1316
            {
1317
                // finish parse a access setction and stored them into different
1318
                // places
1319

    
1320
                accessObject.setEndNodeId(endNodeId);
1321
                AccessSection newAccessObject = accessObject;
1322
                newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1323
                if (newAccessObject != null)
1324
                {
1325

    
1326
                    if (processTopLeverAccess)
1327
                    {
1328
                       topAccessSection = newAccessObject;
1329

    
1330
                    }//if
1331
                    else if (processAdditionalAccess)
1332
                    {
1333
                        // for additional control
1334
                        // put discribesId into the accessobject and put this
1335
                        // access object into vector
1336
                        newAccessObject.setDescribedIdList(describesId);
1337
                        addtionalAccessVector.add(newAccessObject);
1338

    
1339
                    }//if
1340
                    else if (processOtherAccess)
1341
                    {
1342
                      // we only stored the access object which has a id
1343
                      // because only the access object which has a id can
1344
                      // be reference
1345
                      if (newAccessObject.getSubTreeId() != null &&
1346
                          !newAccessObject.getSubTreeId().trim().equals(""))
1347
                      {
1348
                         possibleReferencedAccessHash.
1349
                           put(newAccessObject.getSubTreeId(), newAccessObject);
1350
                      }
1351
                    }
1352

    
1353
                }//if
1354
                //reset access section object
1355
                accessObject = null;
1356

    
1357
                // reset tmp stored node stack
1358
                storedAccessNodeStack = null;
1359
                storedAccessNodeStack = new Stack();
1360

    
1361
                // reset flag
1362
                processAdditionalAccess = false;
1363
                processTopLeverAccess = false;
1364
                processOtherAccess = false;
1365

    
1366
            }//access element
1367
            else if (currentTag.equals(ADDITIONALMETADATA))
1368
            {
1369
                //reset describesId
1370
                describesId = null;
1371
                describesId = new Vector();
1372
                inAddtionalMetaData = false;
1373
                firstDescribesNodeId = -1;
1374
                // reset tmp stored node stack
1375
                storedAccessNodeStack = null;
1376
                storedAccessNodeStack = new Stack();
1377

    
1378

    
1379
            }
1380
            else if (currentTag.equals(DISTRIBUTION) && !inAddtionalMetaData)
1381
            {
1382
               //reset distribution id
1383
               distributionId = null;
1384
               proccessDistribution = false;
1385
            }
1386
            else if (currentTag.equals(OFFLINE) && !inAddtionalMetaData)
1387
            {
1388
               if (distributionId != null)
1389
               {
1390
                 offlineDistributionIdList.put(distributionId, distributionId);
1391
               }
1392
            }
1393
            else if ((currentTag.equals(CONNECTION) || currentTag.equals(CONNECTIONDEFINITION))
1394
                     && !inAddtionalMetaData)
1395
            {
1396
              //handle online data, make sure its'parent is online
1397
                 DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1398
                 if (parentNode != null && parentNode.getTagName() != null
1399
                         && parentNode.getTagName().equals(ONLINE))
1400
                 {
1401
                     if (distributionId != null)
1402
                     {
1403
                        onlineOtherDistributionIdList.put(distributionId, distributionId);
1404
                     }
1405
                 }//if
1406

    
1407
            }//else if
1408
            else if (currentTag.equals(DESCRIBES))
1409
            {
1410
                firstDescribesInAdditionalMetadata = false;
1411

    
1412
            }
1413

    
1414

    
1415

    
1416
        }
1417
        // close elements which are in inline data (inline data can be xml doc)
1418
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1419
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1420
        else
1421
        {
1422
            // this is in inline part
1423
            StringBuffer endElement = new StringBuffer();
1424
            endElement.append("</");
1425
            endElement.append(qName);
1426
            endElement.append(">");
1427
            logMetacat.info("inline endElement: "
1428
                    + endElement.toString());
1429
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1430
        }
1431
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1432
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1433
    }
1434

    
1435

    
1436
    /*
1437
     * Method to check if the new line data is as same as the old one
1438
     */
1439
     private boolean modifiedInlineData(String inlineDistributionId,
1440
			String newInlineInternalFileName) throws SAXException {
1441
       boolean modified = true;
1442
       if (inlineDistributionId == null || newInlineInternalFileName == null)
1443
       {
1444
         return modified;
1445
       }
1446
       String oldInlineInternalFileName =
1447
            (String)previousUnwritableInlineDataObjectHash.get(inlineDistributionId);
1448
       if (oldInlineInternalFileName == null ||
1449
           oldInlineInternalFileName.trim().equals(""))
1450
       {
1451
         return modified;
1452
       }
1453
       logMetacat.info("in handle inline data");
1454
       logMetacat.info("the inline data file name from xml_access is: "
1455
                                    + oldInlineInternalFileName);
1456

    
1457
       try
1458
       {
1459
         if (!compareInlineDataFiles(oldInlineInternalFileName,
1460
                                     newInlineInternalFileName))
1461
         {
1462
           modified = true;
1463

    
1464
         }
1465
         else
1466
         {
1467
           modified = false;
1468
         }
1469
       }
1470
       catch(Exception e)
1471
       {
1472
         modified = true;
1473
       }
1474

    
1475
       // delete the inline data file already in file system
1476
       if (modified)
1477
       {
1478
         deleteInlineDataFile(newInlineInternalFileName);
1479

    
1480
       }
1481
       return modified;
1482
     }
1483

    
1484
     /*
1485
      * A method to check if a line file is empty
1486
      */
1487
     private boolean inlineDataIsEmpty(String fileName) throws SAXException
1488
     {
1489
        boolean isEmpty = true;
1490
        if ( fileName == null)
1491
        {
1492
          throw new SAXException("The inline file name is null");
1493
        }
1494
        
1495
        try {
1496
			String path = PropertyService.getProperty("application.inlinedatafilepath");
1497
			// the new file name will look like path/docid.rev.2
1498
			File inlineDataDirectory = new File(path);
1499
			File inlineDataFile = new File(inlineDataDirectory, fileName);
1500

    
1501
			FileReader inlineFileReader = new FileReader(inlineDataFile);
1502
			BufferedReader inlineStringReader = new BufferedReader(inlineFileReader);
1503
			String string = inlineStringReader.readLine();
1504
			// at the end oldstring will be null
1505
			while (string != null) {
1506
				string = inlineStringReader.readLine();
1507
				if (string != null && !string.trim().equals("")) {
1508
					isEmpty = false;
1509
					break;
1510
				}
1511
			}
1512

    
1513
		} catch (Exception e) {
1514
			throw new SAXException(e.getMessage());
1515
		}
1516
		return isEmpty;
1517

    
1518
     }
1519

    
1520

    
1521
    /**
1522
	 * SAX Handler that receives notification of comments in the DTD
1523
	 */
1524
    public void comment(char[] ch, int start, int length) throws SAXException
1525
    {
1526
        logMetacat.info("COMMENT");
1527
        if (!handleInlineData) {
1528
            if (!processingDTD) {
1529
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1530
                String str = new String(ch, start, length);
1531

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

    
1551
                }
1552
            }
1553
        } else {
1554
            // inline data comment
1555
            StringBuffer inlineComment = new StringBuffer();
1556
            inlineComment.append("<!--");
1557
            inlineComment.append(new String(ch, start, length));
1558
            inlineComment.append("-->");
1559
            logMetacat.info("inline data comment: "
1560
                    + inlineComment.toString());
1561
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1562
        }
1563
    }
1564

    
1565

    
1566

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

    
1592
    /** SAX Handler that is called at the start of Namespace */
1593
    public void startPrefixMapping(String prefix, String uri)
1594
            throws SAXException
1595
    {
1596
        logMetacat.info("NAMESPACE");
1597
        logMetacat.info("NAMESPACE prefix "+prefix);
1598
        logMetacat.info("NAMESPACE uri "+uri);
1599
        if (!handleInlineData) {
1600
            namespaces.put(prefix, uri);
1601
        } else {
1602
            inlineDataNameSpace.put(prefix, uri);
1603
        }
1604
    }
1605

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

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

    
1639
                //compare whitespace if need
1640
                /*if (startCriticalSubTree) {
1641
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1642
                            data, PERMISSIONERROR);
1643
                }//if*/
1644

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

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

    
1669
    }
1670

    
1671

    
1672
    /** SAX Handler that receives notification of end of the document */
1673
    public void endDocument() throws SAXException
1674
    {
1675
        logMetacat.info("end Document");
1676
        if (needCheckingAccessModule)
1677
        {
1678
          compareAllAccessModules();
1679
        }
1680

    
1681
        // user deleted some inline block which it counldn't delete
1682
        if (numberOfHitUnWritableInlineData !=
1683
            previousUnwritableInlineDataObjectHash.size())
1684
        {
1685
          throw new SAXException("user deleted some inline block it couldn't");
1686
        }
1687

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

    
1697
          //delete relation table
1698
          deleteRelations();
1699
          //write relations
1700
           for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1701
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1702
            writeOnlineDataFileIdIntoRelationTable(id);
1703
           }
1704
        }
1705

    
1706
        // clean the subtree record
1707
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1708
    }
1709

    
1710

    
1711

    
1712
    /* The method will compare all access modules in eml document -
1713
     * topLevel, additionalLevel(data access) and referenced access module*/
1714
    private void compareAllAccessModules() throws SAXException
1715
    {
1716
      //compare top level
1717
      compareAccessSubtree(unChangebleTopAccessSubTree, topAccessSection);
1718

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

    
1738
      //compare referenced level
1739
      Enumeration em = unChangebleReferencedAccessSubTreeHash.keys();
1740
      while (em.hasMoreElements())
1741
      {
1742
        String id = (String)em.nextElement();
1743
        AccessSection fromDB = (AccessSection)
1744
                               unChangebleReferencedAccessSubTreeHash.get(id);
1745
        AccessSection fromParser = (AccessSection)
1746
                               possibleReferencedAccessHash.get(id);
1747
        compareAccessSubtree(fromDB, fromParser);
1748
      }
1749
    }
1750

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

    
1766
       Stack tempStack = new Stack();
1767
       while(!nodeStackFromDBTable.isEmpty()){
1768
           tempStack.push(nodeStackFromDBTable.pop());
1769
       }
1770
       comparingNodeStacks(tempStack, nodeStackFromParser);
1771
    }
1772

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

    
1787
          // Pop an element from stack2(stack 2 maybe empty)
1788
          NodeRecord record2 = null;
1789
          try {
1790
              record2 = (NodeRecord) stack2.pop();
1791
          } catch (EmptyStackException ee) {
1792

    
1793
              logMetacat.error(
1794
                      "Node stack2 is empty but stack1 isn't!");
1795
              throw new SAXException(UPDATEACCESSERROR);
1796
          }
1797
          // if two records are not same throw a exception
1798
          if (!record1.contentEquals(record2)) {
1799
              logMetacat.info("Two records from new and old stack are not "
1800
                                      + "same!" + record1 + "--" +record2);
1801
              throw new SAXException(UPDATEACCESSERROR);
1802
          }//if
1803
      }//while
1804

    
1805
      // now stack1 is empty and we should make sure stack2 is empty too
1806
      if (!stack2.isEmpty()) {
1807

    
1808
          logMetacat.info(
1809
                  "stack2 still have some elements while stack1 "
1810
                          + "is empty! ");
1811
          throw new SAXException(UPDATEACCESSERROR);
1812
      }//if
1813
  }//comparingNodeStacks
1814

    
1815

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

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

    
1835

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

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

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

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

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

    
1942

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

    
1968
       if (describeIdList == null || describeIdList.isEmpty())
1969
       {
1970
         continue;
1971
       }
1972

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

    
2026
   }//writeAdditonalLevelAccessRuletoDB
2027

    
2028

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

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

    
2068
         }
2069
       }//while
2070

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

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

    
2106
       try
2107
       {
2108

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

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

    
2168
    }//writeGivenAccessRuleIntoDB
2169

    
2170

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

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

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

    
2223
    }
2224

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

    
2252
    }
2253

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

    
2265
          logMetacat.info("Access object is null and tried to write "+
2266
                                   "into access subtree table");
2267
          throw new SAXException("The access object is null to write access " +
2268
                                 "sbutree");
2269
        }
2270

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

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

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

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

    
2310
            }
2311

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

    
2350
    }//writeAccessSubtreeIntoDB
2351

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

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

    
2377
    // open a file writer for writing inline data to file
2378
    private FileWriter createInlineDataFileWriter(String fileName)
2379
            throws SAXException
2380
    {
2381
        FileWriter writer = null;
2382
        String path;
2383
        try {
2384
        	 path = PropertyService.getProperty("application.inlinedatafilepath");
2385
        } catch (PropertyNotFoundException pnfe) {
2386
            throw new SAXException(pnfe.getMessage());
2387
        }
2388
        /*
2389
         * File inlineDataDirectory = new File(path);
2390
         */
2391
        String newFile = path + "/" + fileName;
2392
        logMetacat.info("inline file name: " + newFile);
2393
        try {
2394
            // true means append
2395
            writer = new FileWriter(newFile, true);
2396
        } catch (IOException ioe) {
2397
            throw new SAXException(ioe.getMessage());
2398
        }
2399
        return writer;
2400
    }
2401

    
2402
    // write inline data into file system and return file name(without path)
2403
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2404
            throws SAXException
2405
    {
2406
        try {
2407
            writer.write(data.toString());
2408
            writer.flush();
2409
        } catch (Exception e) {
2410
            throw new SAXException(e.getMessage());
2411
        }
2412
    }
2413

    
2414

    
2415

    
2416
    /*
2417
     * In eml2, the inline data wouldn't store in db, it store in file system
2418
     * The db stores file name(without path). We got the old file name from db
2419
     * and compare to the new in line data file
2420
     */
2421
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2422
            throws McdbException
2423
    {
2424
        // this method need to be testing
2425
        boolean same = true;
2426
        String data = null;
2427
        try {
2428
        	String path = PropertyService.getProperty("application.inlinedatafilepath");
2429
			// the new file name will look like path/docid.rev.2
2430
			File inlineDataDirectory = new File(path);
2431
			File oldDataFile = new File(inlineDataDirectory, oldFileName);
2432
			File newDataFile = new File(inlineDataDirectory, newFileName);
2433

    
2434
            FileReader oldFileReader = new FileReader(oldDataFile);
2435
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2436
            FileReader newFileReader = new FileReader(newDataFile);
2437
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2438
            // read first line of data
2439
            String oldString = oldStringReader.readLine();
2440
            String newString = newStringReader.readLine();
2441

    
2442
            // at the end oldstring will be null
2443
            while (oldString != null) {
2444
                oldString = oldStringReader.readLine();
2445
                newString = newStringReader.readLine();
2446
                if (!oldString.equals(newString)) {
2447
                    same = false;
2448
                    break;
2449
                }
2450
            }
2451

    
2452
            // if oldString is null but newString is not null, they are same
2453
            if (same) {
2454
                if (newString != null) {
2455
                    same = false;
2456
                }
2457
            }
2458

    
2459
        } catch (Exception e) {
2460
            throw new McdbException(e.getMessage());
2461
        }
2462
        logMetacat.info("the inline data retrieve from file: " + data);
2463
        return same;
2464
    }
2465

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

    
2479
		if (oldInlineInternalFileName == null
2480
				|| oldInlineInternalFileName.trim().equals("")) {
2481
			throw new SAXException("Could not copy inline file from old one to new "
2482
					+ "one because can't find old file name");
2483
		}
2484
		logMetacat.info("in handle inline data");
2485
		logMetacat.info("the inline data file name from xml_access is: "
2486
				+ oldInlineInternalFileName);
2487

    
2488
		FileReader oldFileReader = null;
2489
		FileWriter newFileWriter = null;
2490
		try {
2491
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2492
			// the new file name will look like path/docid.rev.2
2493
			File inlineDataDirectory = new File(path);
2494
			File oldDataFile = new File(inlineDataDirectory, oldInlineInternalFileName);
2495
			File newDataFile = new File(inlineDataDirectory, newFileName);
2496

    
2497
			oldFileReader = new FileReader(oldDataFile);
2498
			newFileWriter = new FileWriter(newDataFile);
2499
			char[] buf = new char[4 * 1024]; // 4K buffer
2500
			int b = oldFileReader.read(buf);
2501
			while (b != -1) {
2502
				newFileWriter.write(buf, 0, b);
2503
				b = oldFileReader.read(buf);
2504
			}
2505
		} catch (Exception e) {
2506
			throw new SAXException(e.getMessage());
2507
		} finally {
2508
			if (oldFileReader != null) {
2509
				try {
2510
					oldFileReader.close();
2511
				} catch (Exception ee) {
2512
					throw new SAXException(ee.getMessage());
2513
				}
2514

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

    
2523
			}
2524
		}
2525
	}
2526

    
2527

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

    
2540
    /* delete the inline data file */
2541
    private void deleteInlineDataFile(String fileName) throws SAXException
2542
    {
2543
    	String path;
2544
    	try {
2545
    		path = PropertyService.getProperty("application.inlinedatafilepath");
2546
    	} catch (PropertyNotFoundException pnfe) {
2547
    		throw new SAXException ("Could not find inline data file path: " 
2548
    				+ pnfe.getMessage());
2549
    	}
2550
        File inlineDataDirectory = new File(path);
2551
        File newFile = new File(inlineDataDirectory, fileName);
2552
        newFile.delete();
2553

    
2554
    }
2555

    
2556
    /*
2557
	 * In eml2, the inline data wouldn't store in db, it store in file system
2558
	 * The db stores file name(without path).
2559
	 */
2560
	public static Reader readInlineDataFromFileSystem(String fileName)
2561
			throws McdbException {
2562
		// BufferedReader stringReader = null;
2563
		FileReader fileReader = null;
2564
		try {
2565
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2566
			// the new file name will look like path/docid.rev.2
2567
			File inlineDataDirectory = new File(path);
2568
			File dataFile = new File(inlineDataDirectory, fileName);
2569

    
2570
			fileReader = new FileReader(dataFile);
2571
			// stringReader = new BufferedReader(fileReader);
2572
		} catch (Exception e) {
2573
			throw new McdbException(e.getMessage());
2574
		}
2575
		// return stringReader;
2576
		return fileReader;
2577
	}
2578

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

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

    
2644
    }//writeOnlineDataFileIdIntoRelationTable
2645

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

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

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

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

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

    
2778
        }//while
2779

    
2780
        //compare attributes
2781
        for (int i = 0; i < attributes.getLength(); i++) {
2782
            NodeRecord attriNode = null;
2783
            try {
2784
                attriNode = (NodeRecord) unchangableNodeStack.pop();
2785

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

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

    
2828
    }
2829

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

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

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

    
2928

    
2929

    
2930
}
(36-36/63)