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-12-18 13:36:43 -0800 (Fri, 18 Dec 2009) $'
11
 * '$Revision: 5166 $'
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.accesscontrol.AccessControlInterface;
52
import edu.ucsb.nceas.metacat.accesscontrol.AccessRule;
53
import edu.ucsb.nceas.metacat.accesscontrol.AccessSection;
54
import edu.ucsb.nceas.metacat.database.DBConnection;
55
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
56
import edu.ucsb.nceas.metacat.properties.PropertyService;
57
import edu.ucsb.nceas.metacat.util.AuthUtil;
58
import edu.ucsb.nceas.metacat.util.DocumentUtil;
59
import edu.ucsb.nceas.metacat.util.MetacatUtil;
60
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
61

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

    
122
    // now additionalAccess will be explained as distribution access control
123
    // - data file
124
    private boolean processAdditionalAccess = false;
125

    
126
    private boolean processOtherAccess = false;
127

    
128
    private AccessSection accessObject = null;
129

    
130
    private AccessRule accessRule = null;
131

    
132
    private Vector describesId = new Vector(); // store the ids in
133
                                               //additionalmetadata/describes
134

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

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

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

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

    
155
    // a hash to stored all distribution id, both key and value are id itself
156
    private Hashtable distributionAllIdList = new Hashtable();
157

    
158
    // temporarily store distribution id
159
    private String distributionId = null;
160

    
161
    // flag to indicate to handle distrubiton
162
    private boolean proccessDistribution = false;
163

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

    
175
    private boolean needCheckingAccessModule = false;
176

    
177
    private AccessSection unChangebleTopAccessSubTree = null;
178

    
179
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
180

    
181
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
182

    
183
    private AccessSection topAccessSection;
184

    
185
    private Vector additionalAccessVector = new Vector();
186

    
187
    // key is subtree id and value is accessSection object
188
    private Hashtable possibleReferencedAccessHash = new Hashtable();
189

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

    
194
    // vector stored the data file id which will be write into relation table
195
    private Vector onlineDataFileIdInRelationVector = new Vector();
196

    
197
    // Indicator of inline data
198
    private boolean handleInlineData = false;
199

    
200
    private Hashtable inlineDataNameSpace = null;
201

    
202
    private FileWriter inlineDataFileWriter = null;
203

    
204
    private String inlineDataFileName = null;
205

    
206
    private int inLineDataIndex = 0;
207

    
208
    private Vector inlineFileIDList = new Vector();
209

    
210
    private boolean inadditionalMetaData = false;
211

    
212
    //user has unwritable inline data object when it updates a document
213
    private boolean unWritableInlineDataObject = false;
214
    //user has unreadable inline data when it updates a dcoument
215
    private boolean unReadableInlineDataObject = false;
216

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

    
222
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
223

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

    
230
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
231

    
232
    //This hashtable will stored the id which already has additional access
233
    // control. So the top level access control will ignore them.
234
    private Hashtable onlineURLIdHasadditionalAccess   = new Hashtable();
235

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

    
250
    private int numberOfHitUnWritableInlineData = 0;
251

    
252
    // Constant
253
    private static final String EML = "eml";
254

    
255
    private static final String DESCRIBES = "describes";
256

    
257
    private static final String ADDITIONALMETADATA = "additionalMetadata";
258

    
259
    private static final String ORDER = "order";
260

    
261
    private static final String ID = "id";
262

    
263
    private static final String REFERENCES = "references";
264

    
265
    public static final String INLINE = "inline";
266

    
267
    private static final String ONLINE = "online";
268

    
269
    private static final String OFFLINE = "offline";
270

    
271
    private static final String CONNECTION = "connection";
272

    
273
    private static final String CONNECTIONDEFINITION = "connectionDefinition";
274

    
275
    private static final String URL = "url";
276

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

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

    
283
    public static final String TOPLEVEL = "top";
284

    
285
    public static final String DATAACCESSLEVEL = "dataAccess";
286

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

    
291
    private static final String RELATION = "Provides info for";
292

    
293
    private static final String DISTRIBUTION = "distribution";
294

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

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

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

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

    
356
            }
357

    
358

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

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

    
381

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

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

    
430
     }
431

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

    
445
        try
446
        {
447

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

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

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

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

    
511
       try
512
       {
513

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

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

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

    
567

    
568

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

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

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

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

    
640

    
641
                  // store the distributid and inlinedata filename into a hash
642
                  inlineDistributionIdList.put(distributionId, inlineDataFileName);
643
                }
644

    
645
            }
646
            //==============================================================
647

    
648

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

    
656

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

    
665
                }
666

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

    
676
            }
677
            //==================================================================
678

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

    
718
                    try {
719
                        // Get dbconnection
720
                        dbConn = DBConnectionPool
721
                                .getDBConnection("DBSAXHandler.startElement");
722
                        serialNumber = dbConn.getCheckOutSerialNumber();
723

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

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

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

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

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

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

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

    
817
              }
818

    
819
          }//for
820

    
821

    
822
           //=================================================================
823

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

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

    
858

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

    
884
                accessObject.setStartNodeId(startNodeId);
885
                accessObject.setDocId(docid);
886

    
887

    
888

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

    
896
                accessRule = new AccessRule();
897

    
898
                //set permission type "allow"
899
                accessRule.setPermissionType(ALLOW);
900

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

    
912
            //=================================================================
913
            // some other independ stuff
914

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

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

    
938
            }
939

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

    
980

    
981
             //==================================================================
982
            // reset name space
983
            namespaces = null;
984
            namespaces = new Hashtable();
985

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

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

    
1034
    }
1035

    
1036

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

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

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

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

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

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

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

    
1181

    
1182

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

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

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

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

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

    
1281
                logMetacat.info(
1282
                            "Write text into DB in End Element");
1283

    
1284
                 // write text node into db
1285
                 endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1286
                            currentNode);
1287

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

    
1296
                }
1297
            }//if handle text node
1298

    
1299

    
1300

    
1301
            //set hitText false
1302
            hitTextNode = false;
1303
            // reset textbuff
1304
            textBuffer = null;
1305
            textBuffer = new StringBuffer();
1306

    
1307

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

    
1323
                accessObject.setEndNodeId(endNodeId);
1324
                AccessSection newAccessObject = accessObject;
1325
                newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1326
                if (newAccessObject != null)
1327
                {
1328

    
1329
                    if (processTopLeverAccess)
1330
                    {
1331
                       topAccessSection = newAccessObject;
1332

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

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

    
1356
                }//if
1357
                //reset access section object
1358
                accessObject = null;
1359

    
1360
                // reset tmp stored node stack
1361
                storedAccessNodeStack = null;
1362
                storedAccessNodeStack = new Stack();
1363

    
1364
                // reset flag
1365
                processAdditionalAccess = false;
1366
                processTopLeverAccess = false;
1367
                processOtherAccess = false;
1368

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

    
1381

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

    
1410
            }//else if
1411
            else if (currentTag.equals(DESCRIBES))
1412
            {
1413
                firstDescribesInAdditionalMetadata = false;
1414

    
1415
            }
1416

    
1417

    
1418

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

    
1438

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

    
1460
       try
1461
       {
1462
         if (!compareInlineDataFiles(oldInlineInternalFileName,
1463
                                     newInlineInternalFileName))
1464
         {
1465
           modified = true;
1466

    
1467
         }
1468
         else
1469
         {
1470
           modified = false;
1471
         }
1472
       }
1473
       catch(Exception e)
1474
       {
1475
         modified = true;
1476
       }
1477

    
1478
       // delete the inline data file already in file system
1479
       if (modified)
1480
       {
1481
         deleteInlineDataFile(newInlineInternalFileName);
1482

    
1483
       }
1484
       return modified;
1485
     }
1486

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

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

    
1516
		} catch (Exception e) {
1517
			throw new SAXException(e.getMessage());
1518
		}
1519
		return isEmpty;
1520

    
1521
     }
1522

    
1523

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

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

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

    
1568

    
1569

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

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

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

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

    
1642
                //compare whitespace if need
1643
                /*if (startCriticalSubTree) {
1644
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1645
                            data, PERMISSIONERROR);
1646
                }//if*/
1647

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

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

    
1672
    }
1673

    
1674

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

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

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

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

    
1709
        // clean the subtree record
1710
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1711
    }
1712

    
1713

    
1714

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

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

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

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

    
1769
       Stack tempStack = new Stack();
1770
       while(!nodeStackFromDBTable.isEmpty()){
1771
           tempStack.push(nodeStackFromDBTable.pop());
1772
       }
1773
       comparingNodeStacks(tempStack, nodeStackFromParser);
1774
    }
1775

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

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

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

    
1808
      // now stack1 is empty and we should make sure stack2 is empty too
1809
      if (!stack2.isEmpty()) {
1810

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

    
1818

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

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

    
1838

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

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

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

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

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

    
1945

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

    
1971
       if (describeIdList == null || describeIdList.isEmpty())
1972
       {
1973
         continue;
1974
       }
1975

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

    
2029
   }//writeAdditonalLevelAccessRuletoDB
2030

    
2031

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

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

    
2071
         }
2072
       }//while
2073

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

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

    
2109
       try
2110
       {
2111

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

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

    
2171
    }//writeGivenAccessRuleIntoDB
2172

    
2173

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

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

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

    
2226
    }
2227

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

    
2255
    }
2256

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

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

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

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

    
2305
            long endNodeId = accessSection.getEndNodeId();
2306
            String sectionId = accessSection.getSubTreeId();
2307

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

    
2313
            }
2314

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

    
2353
    }//writeAccessSubtreeIntoDB
2354

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

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

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

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

    
2417

    
2418

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

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

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

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

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

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

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

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

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

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

    
2526
			}
2527
		}
2528
	}
2529

    
2530

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

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

    
2557
    }
2558

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

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

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

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

    
2647
    }//writeOnlineDataFileIdIntoRelationTable
2648

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

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

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

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

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

    
2781
        }//while
2782

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

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

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

    
2831
    }
2832

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

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

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

    
2931

    
2932

    
2933
}
(32-32/59)