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-04 14:32:58 -0700 (Tue, 04 Aug 2009) $'
11
 * '$Revision: 5015 $'
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.service.PropertyService;
54
import edu.ucsb.nceas.metacat.util.AuthUtil;
55
import edu.ucsb.nceas.metacat.util.MetacatUtil;
56
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
57

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

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

    
122
    private boolean processOtherAccess = false;
123

    
124
    private AccessSection accessObject = null;
125

    
126
    private AccessRule accessRule = null;
127

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

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

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

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

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

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

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

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

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

    
171
    private boolean needCheckingAccessModule = false;
172

    
173
    private AccessSection unChangebleTopAccessSubTree = null;
174

    
175
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
176

    
177
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
178

    
179
    private AccessSection topAccessSection;
180

    
181
    private Vector addtionalAccessVector = new Vector();
182

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

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

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

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

    
196
    private Hashtable inlineDataNameSpace = null;
197

    
198
    private FileWriter inlineDataFileWriter = null;
199

    
200
    private String inlineDataFileName = null;
201

    
202
    private int inLineDataIndex = 0;
203

    
204
    private Vector inlineFileIDList = new Vector();
205

    
206
    private boolean inAddtionalMetaData = false;
207

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

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

    
218
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
219

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

    
226
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
227

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

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

    
246
    private int numberOfHitUnWritableInlineData = 0;
247

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
352
            }
353

    
354

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

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

    
377

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

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

    
426
     }
427

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

    
441
        try
442
        {
443

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

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

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

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

    
507
       try
508
       {
509

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

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

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

    
563

    
564

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

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

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

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

    
636

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

    
641
            }
642
            //==============================================================
643

    
644

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

    
652

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

    
661
                }
662

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

    
672
            }
673
            //==================================================================
674

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

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

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

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

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

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

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

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

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

    
813
              }
814

    
815
          }//for
816

    
817

    
818
           //=================================================================
819

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

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

    
854

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

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

    
883

    
884

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

    
892
                accessRule = new AccessRule();
893

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

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

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

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

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

    
934
            }
935

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

    
976

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

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

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

    
1030
    }
1031

    
1032

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

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

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

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

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

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

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

    
1177

    
1178

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

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

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

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

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

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

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

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

    
1292
                }
1293
            }//if handle text node
1294

    
1295

    
1296

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

    
1303

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

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

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

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

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

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

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

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

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

    
1377

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

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

    
1411
            }
1412

    
1413

    
1414

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

    
1434

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

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

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

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

    
1479
       }
1480
       return modified;
1481
     }
1482

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

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

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

    
1517
     }
1518

    
1519

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

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

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

    
1564

    
1565

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

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

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

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

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

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

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

    
1668
    }
1669

    
1670

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

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

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

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

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

    
1709

    
1710

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

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

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

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

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

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

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

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

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

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

    
1814

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

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

    
1834

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

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

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

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

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

    
1941

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

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

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

    
2025
   }//writeAdditonalLevelAccessRuletoDB
2026

    
2027

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

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

    
2067
         }
2068
       }//while
2069

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

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

    
2105
       try
2106
       {
2107

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

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

    
2167
    }//writeGivenAccessRuleIntoDB
2168

    
2169

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

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

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

    
2222
    }
2223

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

    
2251
    }
2252

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

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

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

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

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

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

    
2309
            }
2310

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

    
2349
    }//writeAccessSubtreeIntoDB
2350

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

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

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

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

    
2413

    
2414

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

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

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

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

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

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

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

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

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

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

    
2522
			}
2523
		}
2524
	}
2525

    
2526

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

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

    
2553
    }
2554

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

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

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

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

    
2643
    }//writeOnlineDataFileIdIntoRelationTable
2644

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

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

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

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

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

    
2777
        }//while
2778

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

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

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

    
2827
    }
2828

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

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

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

    
2927

    
2928

    
2929
}
(36-36/63)