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: 2008-12-09 14:56:50 -0800 (Tue, 09 Dec 2008) $'
11
 * '$Revision: 4661 $'
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.service.PropertyService;
52
import edu.ucsb.nceas.metacat.util.AuthUtil;
53
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
54
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55

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

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

    
120
    private boolean processOtherAccess = false;
121

    
122
    private AccessSection accessObject = null;
123

    
124
    private AccessRule accessRule = null;
125

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

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

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

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

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

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

    
152
    // temporarily store distribution id
153
    private String distributionId = null;
154

    
155
    // flag to indicate to handle distrubiton
156
    private boolean proccessDistribution = false;
157

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

    
169
    private boolean needCheckingAccessModule = false;
170

    
171
    private AccessSection unChangebleTopAccessSubTree = null;
172

    
173
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
174

    
175
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
176

    
177
    private AccessSection topAccessSection;
178

    
179
    private Vector addtionalAccessVector = new Vector();
180

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

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

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

    
191
    // Indicator of inline data
192
    private boolean handleInlineData = false;
193

    
194
    private Hashtable inlineDataNameSpace = null;
195

    
196
    private FileWriter inlineDataFileWriter = null;
197

    
198
    private String inlineDataFileName = null;
199

    
200
    private int inLineDataIndex = 0;
201

    
202
    private Vector inlineFileIDList = new Vector();
203

    
204
    private boolean inAddtionalMetaData = false;
205

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

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

    
216
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
217

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

    
224
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
225

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

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

    
244
    private int numberOfHitUnWritableInlineData = 0;
245

    
246
    // Constant
247
    private static final String EML = "eml";
248

    
249
    private static final String DESCRIBES = "describes";
250

    
251
    private static final String ADDITIONALMETADATA = "additionalMetadata";
252

    
253
    private static final String ORDER = "order";
254

    
255
    private static final String ID = "id";
256

    
257
    private static final String REFERENCES = "references";
258

    
259
    public static final String INLINE = "inline";
260

    
261
    private static final String ONLINE = "online";
262

    
263
    private static final String OFFLINE = "offline";
264

    
265
    private static final String CONNECTION = "connection";
266

    
267
    private static final String CONNECTIONDEFINITION = "connectionDefinition";
268

    
269
    private static final String URL = "url";
270

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

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

    
277
    public static final String TOPLEVEL = "top";
278

    
279
    public static final String DATAACCESSLEVEL = "dataAccess";
280

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

    
285
    private static final String RELATION = "Provides info for";
286

    
287
    private static final String DISTRIBUTION = "distribution";
288

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

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

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

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

    
350
            }
351

    
352

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

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

    
375

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

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

    
424
     }
425

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

    
439
        try
440
        {
441

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

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

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

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

    
505
       try
506
       {
507

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

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

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

    
561

    
562

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

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

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

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

    
634

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

    
639
            }
640
            //==============================================================
641

    
642

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

    
650

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

    
659
                }
660

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

    
670
            }
671
            //==================================================================
672

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

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

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

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

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

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

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

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

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

    
811
              }
812

    
813
          }//for
814

    
815

    
816
           //=================================================================
817

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

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

    
852

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

    
878
                accessObject.setStartNodeId(startNodeId);
879
                accessObject.setDocId(docid);
880

    
881

    
882

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

    
890
                accessRule = new AccessRule();
891

    
892
                //set permission type "allow"
893
                accessRule.setPermissionType(ALLOW);
894

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

    
906
            //=================================================================
907
            // some other independ stuff
908

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

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

    
932
            }
933

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

    
974

    
975
             //==================================================================
976
            // reset name space
977
            namespaces = null;
978
            namespaces = new Hashtable();
979

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

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

    
1028
    }
1029

    
1030

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

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

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

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

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

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

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

    
1175

    
1176

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

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

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

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

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

    
1275
                logMetacat.info(
1276
                            "Write text into DB in End Element");
1277

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

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

    
1290
                }
1291
            }//if handle text node
1292

    
1293

    
1294

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

    
1301

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

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

    
1323
                    if (processTopLeverAccess)
1324
                    {
1325
                       topAccessSection = newAccessObject;
1326

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

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

    
1350
                }//if
1351
                //reset access section object
1352
                accessObject = null;
1353

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

    
1358
                // reset flag
1359
                processAdditionalAccess = false;
1360
                processTopLeverAccess = false;
1361
                processOtherAccess = false;
1362

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

    
1375

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

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

    
1409
            }
1410

    
1411

    
1412

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

    
1432

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

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

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

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

    
1477
       }
1478
       return modified;
1479
     }
1480

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

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

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

    
1515
     }
1516

    
1517

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

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

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

    
1562

    
1563

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

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

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

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

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

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

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

    
1666
    }
1667

    
1668

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

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

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

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

    
1703
        // clean the subtree record
1704
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1705
    }
1706

    
1707

    
1708

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

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

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

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

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

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

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

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

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

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

    
1812

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

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

    
1832

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

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

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

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

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

    
1939

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

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

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

    
2023
   }//writeAdditonalLevelAccessRuletoDB
2024

    
2025

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

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

    
2065
         }
2066
       }//while
2067

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

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

    
2103
       try
2104
       {
2105

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

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

    
2165
    }//writeGivenAccessRuleIntoDB
2166

    
2167

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

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

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

    
2220
    }
2221

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

    
2249
    }
2250

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

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

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

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

    
2299
            long endNodeId = accessSection.getEndNodeId();
2300
            String sectionId = accessSection.getSubTreeId();
2301

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

    
2307
            }
2308

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

    
2347
    }//writeAccessSubtreeIntoDB
2348

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

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

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

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

    
2411

    
2412

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

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

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

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

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

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

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

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

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

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

    
2520
			}
2521
		}
2522
	}
2523

    
2524

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

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

    
2551
    }
2552

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

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

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

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

    
2641
    }//writeOnlineDataFileIdIntoRelationTable
2642

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

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

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

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

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

    
2775
        }//while
2776

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

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

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

    
2825
    }
2826

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

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

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

    
2925

    
2926

    
2927
}
(37-37/69)