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: 2010-04-14 11:31:03 -0700 (Wed, 14 Apr 2010) $'
11
 * '$Revision: 5311 $'
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.File;
32
import java.io.FileReader;
33
import java.io.FileWriter;
34
import java.io.IOException;
35
import java.io.Reader;
36
import java.sql.PreparedStatement;
37
import java.sql.ResultSet;
38
import java.sql.SQLException;
39
import java.sql.Statement;
40
import java.util.EmptyStackException;
41
import java.util.Enumeration;
42
import java.util.Hashtable;
43
import java.util.Stack;
44
import java.util.Vector;
45

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

    
50
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
51
import edu.ucsb.nceas.metacat.accesscontrol.AccessRule;
52
import edu.ucsb.nceas.metacat.accesscontrol.AccessSection;
53
import edu.ucsb.nceas.metacat.database.DBConnection;
54
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
55
import edu.ucsb.nceas.metacat.properties.PropertyService;
56
import edu.ucsb.nceas.metacat.util.AuthUtil;
57
import edu.ucsb.nceas.metacat.util.DocumentUtil;
58
import edu.ucsb.nceas.metacat.util.MetacatUtil;
59
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
60

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

    
125
    // now additionalAccess will be explained as distribution access control
126
    // - data file
127
    private boolean processAdditionalAccess = false;
128

    
129
	// Boolean that tells whether we are processing other access. This is true when 
130
    // we find an 'access' element inside an 'additionalMetadata' element.  Set back
131
    // to false in endElement
132
    private boolean processOtherAccess = false;
133

    
134
    // if we are inside an 'access' element, we use this object to hold the 
135
    // current access info
136
    private AccessSection accessObject = null;
137

    
138
    // for each 'access/allow' and 'access/deny' we create a new access Rule to hold
139
    // the info
140
    private AccessRule accessRule = null;
141

    
142
    private Vector describesId = new Vector(); // store the ids in
143
                                               //additionalmetadata/describes
144

    
145
    //store all distribution element id for online url. key is the distribution
146
    // id and  data  is url
147
    private Hashtable onlineURLDistributionIdList = new Hashtable();
148
    // distribution/oneline/url will store this vector if distribution doesn't
149
    // have a id.
150
    private Vector onlineURLDistributionListWithoutId = new Vector();
151

    
152
    //store all distribution element id for online other distribution, such as
153
    // connection or connectiondefination. key is the distribution id
154
    // and  data  is distribution id
155
    private Hashtable onlineOtherDistributionIdList = new Hashtable();
156

    
157
    //store all distribution element id for inline data.
158
    // key is the distribution id, data is the internal inline id
159
    private Hashtable inlineDistributionIdList = new Hashtable();
160

    
161
    //store all distribution element id for off line data.
162
    // key is the distribution id, data is the id too.
163
    private Hashtable offlineDistributionIdList = new Hashtable();
164

    
165
    // a hash to stored all distribution id, both key and value are id itself
166
    private Hashtable distributionAllIdList = new Hashtable();
167

    
168
    // temporarily store distribution id
169
    private String distributionId = null;
170

    
171
    // flag to indicate to handle distribution
172
    private boolean proccessDistribution = false;
173

    
174
    // a hash table to stored the distribution which is a reference and this
175
    // distribution has a id too. The key is itself id of this distribution,
176
    // the value is the referenced id.
177
    // So, we only stored the format like this:
178
    // <distribution id ="100"><reference>300</reference></distribution>
179
    // the reason is:
180
    // if not id in distribution, then the distribution couldn't be added
181
    // to additional access module. The distribution block which was referenced
182
    // id (300) will be stored in above distribution lists.
183
    private Hashtable distributionReferenceList = new Hashtable();
184

    
185
    // if the action is update and the user does not have ALL permission 
186
    // and the user is not an administrator, then we will need to compare 
187
    // access modules to make sure the user has update permissions
188
    private boolean needToCheckAccessModule = false;
189

    
190
    private AccessSection topAccessSubTreeFromDB = null;
191

    
192
    private Vector additionalAccessSubTreeListFromDB = new Vector();
193

    
194
    private Hashtable referencedAccessSubTreeListFromDB = new Hashtable();
195

    
196
    // this holds the top level (document level) access section.
197
    private AccessSection topAccessSection;
198

    
199
    private Vector additionalAccessVector = new Vector();
200

    
201
    // key is subtree id and value is accessSection object
202
    private Hashtable possibleReferencedAccessHash = new Hashtable();
203

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

    
208
    // vector stored the data file id which will be write into relation table
209
    private Vector onlineDataFileIdInRelationVector = new Vector();
210

    
211
    // Indicator of inline data
212
    private boolean handleInlineData = false;
213

    
214
    private Hashtable inlineDataNameSpace = null;
215

    
216
    private FileWriter inlineDataFileWriter = null;
217

    
218
    private String inlineDataFileName = null;
219

    
220
    private int inLineDataIndex = 0;
221

    
222
    private Vector inlineFileIDList = new Vector();
223

    
224
    private boolean inAdditionalMetaData = false;
225

    
226
    //user has unwritable inline data object when it updates a document
227
    private boolean unWritableInlineDataObject = false;
228
    //user has unreadable inline data when it updates a dcoument
229
    private boolean unReadableInlineDataObject = false;
230

    
231
    // the hashtable contains the info from xml_access table which
232
    // inline data the user can't read when user update a document.
233
    // The key in hashtable is subtree id and data is the inline data internal
234
    // file name.
235

    
236
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
237

    
238
    // the hashtable contains the info from xml_access table which
239
    // inline data the user can't write when user update a document.
240
    // The key in hashtable is subtree id and data is the inline data internal
241
    // file name.
242
    private Hashtable previousUnwritableInlineDataObjectHash = new Hashtable();
243

    
244
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
245

    
246
    //This hashtable will stored the id which already has additional access
247
    // control. So the top level access control will ignore them.
248
    private Hashtable onlineURLIdHasadditionalAccess   = new Hashtable();
249

    
250
    // additional access module will be in additionalMetadata part. Its format
251
    // look like
252
    //<additionalMetadata>
253
    //   <describes>100</describes>
254
    //   <describes>300</describes>
255
    //   <access>rulesone</access>
256
    //</additionalMetadata>
257
    // If user couldn't have all permission to update access rules, he/she could
258
    // not update access module, but also couldn't update "describes".
259
    // So the start node id for additional access section is the first describes
260
    // element
261
    private boolean firstDescribesInAdditionalMetadata = true;
262
    private long    firstDescribesNodeId               = -1;
263

    
264
    private int numberOfHitUnWritableInlineData = 0;
265

    
266
    // Constant
267
    private static final String EML = "eml";
268

    
269
    private static final String DESCRIBES = "describes";
270

    
271
    private static final String ADDITIONALMETADATA = "additionalMetadata";
272

    
273
    private static final String ORDER = "order";
274

    
275
    private static final String ID = "id";
276

    
277
    private static final String REFERENCES = "references";
278

    
279
    public static final String INLINE = "inline";
280

    
281
    private static final String ONLINE = "online";
282

    
283
    private static final String OFFLINE = "offline";
284

    
285
    private static final String CONNECTION = "connection";
286

    
287
    private static final String CONNECTIONDEFINITION = "connectionDefinition";
288

    
289
    private static final String URL = "url";
290

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

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

    
297
    public static final String TOPLEVEL = "top";
298

    
299
    public static final String DATAACCESSLEVEL = "dataAccess";
300

    
301
    // this level is for the access module which is not in top or additional
302
    // place, but it was referenced by top or additional
303
    private static final String REFERENCEDLEVEL = "referenced";
304

    
305
    private static final String RELATION = "Provides info for";
306

    
307
    private static final String DISTRIBUTION = "distribution";
308

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

    
340
            // If the action is update and user doesn't have "ALL" permission
341
            // we need to check if user update access subtree
342
            if (action != null && action.equals("UPDATE")
343
                    && !control.hasPermission(user, groups,
344
                            AccessControlInterface.ALLSTRING) 
345
                            && !AuthUtil.isAdministrator(user, groups))
346
            {
347
                needToCheckAccessModule = true;
348
                topAccessSubTreeFromDB = getTopAccessSubTreeFromDB();
349
                additionalAccessSubTreeListFromDB =
350
                                         getAdditionalAccessSubTreeListFromDB();
351
                referencedAccessSubTreeListFromDB =
352
                                         getReferencedAccessSubTreeListFromDB();
353
            }
354

    
355
            //Here is for  data object checking.
356
            if (action != null && action.equals("UPDATE"))
357
            {
358
              //info about inline data object which user doesn't have read
359
              //permission the info come from xml_access table
360
              previousUnreadableInlineDataObjectHash = PermissionController.
361
                            getUnReadableInlineDataIdList(docid, user,
362
                                                          groups, true);
363

    
364
              //info about data object which user doesn't have write permission
365
              // the info come from xml_accesss table
366
              previousUnwritableInlineDataObjectHash = PermissionController.
367
                            getUnWritableInlineDataIdList(docid, user,
368
                                                          groups, true);
369

    
370
            }
371

    
372

    
373
        }
374
        catch (Exception e)
375
        {
376
            logMetacat.error("error in Eml200SAXHandler is " + e.getMessage());
377
            throw new SAXException(e.getMessage());
378
        }
379
    }
380

    
381
    /*
382
     * Get the top level access subtree info from xml_accesssubtree table.
383
     * If no top access subtree found, null will be return.
384
     */
385
     private AccessSection getTopAccessSubTreeFromDB()
386
                                                       throws SAXException
387
     {
388
       AccessSection topAccess = null;
389
       PreparedStatement pstmt = null;
390
       ResultSet rs = null;
391
       String sql = "SELECT subtreeid, startnodeid, endnodeid "
392
                + "FROM xml_accesssubtree WHERE docid like ? "
393
                + "AND controllevel like ?";
394

    
395

    
396
       try
397
       {
398
            pstmt = connection.prepareStatement(sql);
399
            // Increase DBConnection usage count
400
            connection.increaseUsageCount(1);
401
            // Bind the values to the query
402
            pstmt.setString(1, docid);
403
            pstmt.setString(2, TOPLEVEL);
404
            logMetacat.debug("Eml200SAXHandler.getTopAccessSubTreeFromDB - executing SQL: " + pstmt.toString());
405
            pstmt.execute();
406

    
407
            // Get result set
408
            rs = pstmt.getResultSet();
409
            if (rs.next())
410
            {
411
                String sectionId = rs.getString(1);
412
                long startNodeId = rs.getLong(2);
413
                long endNodeId = rs.getLong(3);
414
                // create a new access section
415
                topAccess = new AccessSection();
416
                topAccess.setControlLevel(TOPLEVEL);
417
                topAccess.setDocId(docid);
418
                topAccess.setSubTreeId(sectionId);
419
                topAccess.setStartNodeId(startNodeId);
420
                topAccess.setEndNodeId(endNodeId);
421
            }
422
            pstmt.close();
423
        }//try
424
        catch (SQLException e)
425
        {
426
            throw new SAXException(
427
                    "EMLSAXHandler.getTopAccessSubTreeFromDB(): "
428
                            + e.getMessage());
429
        }//catch
430
        finally
431
        {
432
            try
433
            {
434
                pstmt.close();
435
            }
436
            catch (SQLException ee)
437
            {
438
                throw new SAXException(
439
                        "EMLSAXHandler.getTopAccessSubTreeFromDB(): "
440
                                + ee.getMessage());
441
            }
442
        }//finally
443
        return topAccess;
444

    
445
     }
446

    
447
    /*
448
     * Get the subtree node info from xml_accesssubtree table
449
     */
450
    private Vector getAdditionalAccessSubTreeListFromDB() throws Exception
451
    {
452
        Vector result = new Vector();
453
        PreparedStatement pstmt = null;
454
        ResultSet rs = null;
455
        String sql = "SELECT subtreeid, startnodeid, endnodeid "
456
                + "FROM xml_accesssubtree WHERE docid like ? "
457
                + "AND controllevel like ? "
458
                + "ORDER BY startnodeid ASC";
459

    
460
        try
461
        {
462

    
463
            pstmt = connection.prepareStatement(sql);
464
            // Increase DBConnection usage count
465
            connection.increaseUsageCount(1);
466
            // Bind the values to the query
467
            pstmt.setString(1, docid);
468
            pstmt.setString(2, DATAACCESSLEVEL);
469
            pstmt.execute();
470

    
471
            // Get result set
472
            rs = pstmt.getResultSet();
473
            while (rs.next())
474
            {
475
                String sectionId = rs.getString(1);
476
                long startNodeId = rs.getLong(2);
477
                long endNodeId = rs.getLong(3);
478
                // create a new access section
479
                AccessSection accessObj = new AccessSection();
480
                accessObj.setControlLevel(DATAACCESSLEVEL);
481
                accessObj.setDocId(docid);
482
                accessObj.setSubTreeId(sectionId);
483
                accessObj.setStartNodeId(startNodeId);
484
                accessObj.setEndNodeId(endNodeId);
485
                // add this access obj into vector
486
                result.add(accessObj);
487

    
488
            }
489
            pstmt.close();
490
        }//try
491
        catch (SQLException e)
492
        {
493
            throw new SAXException(
494
                    "EMLSAXHandler.getadditionalAccessSubTreeListFromDB(): "
495
                            + e.getMessage());
496
        }//catch
497
        finally
498
        {
499
            try
500
            {
501
                pstmt.close();
502
            }
503
            catch (SQLException ee)
504
            {
505
                throw new SAXException(
506
                        "EMLSAXHandler.getAccessSubTreeListFromDB(): "
507
                                + ee.getMessage());
508
            }
509
        }//finally
510
        return result;
511
    }
512

    
513
   /*
514
    * Get the access subtree for referenced info from xml_accesssubtree table
515
    */
516
   private Hashtable getReferencedAccessSubTreeListFromDB() throws Exception
517
   {
518
       Hashtable result = new Hashtable();
519
       PreparedStatement pstmt = null;
520
       ResultSet rs = null;
521
       String sql = "SELECT subtreeid, startnodeid, endnodeid "
522
               + "FROM xml_accesssubtree WHERE docid like ? "
523
               + "AND controllevel like ? "
524
               + "ORDER BY startnodeid ASC";
525

    
526
       try
527
       {
528

    
529
           pstmt = connection.prepareStatement(sql);
530
           // Increase DBConnection usage count
531
           connection.increaseUsageCount(1);
532
           // Bind the values to the query
533
           pstmt.setString(1, docid);
534
           pstmt.setString(2, REFERENCEDLEVEL);
535
           pstmt.execute();
536

    
537
           // Get result set
538
           rs = pstmt.getResultSet();
539
           while (rs.next())
540
           {
541
               String sectionId = rs.getString(1);
542
               long startNodeId = rs.getLong(2);
543
               long endNodeId = rs.getLong(3);
544
               // create a new access section
545
               AccessSection accessObj = new AccessSection();
546
               accessObj.setControlLevel(DATAACCESSLEVEL);
547
               accessObj.setDocId(docid);
548
               accessObj.setSubTreeId(sectionId);
549
               accessObj.setStartNodeId(startNodeId);
550
               accessObj.setEndNodeId(endNodeId);
551
               // add this access obj into hastable
552
               if ( sectionId != null && !sectionId.trim().equals(""))
553
               {
554
                 result.put(sectionId, accessObj);
555
               }
556

    
557
           }
558
           pstmt.close();
559
       }//try
560
       catch (SQLException e)
561
       {
562
           throw new SAXException(
563
                   "EMLSAXHandler.getReferencedAccessSubTreeListFromDB(): "
564
                           + e.getMessage());
565
       }//catch
566
       finally
567
       {
568
           try
569
           {
570
               pstmt.close();
571
           }
572
           catch (SQLException ee)
573
           {
574
               throw new SAXException(
575
                       "EMLSAXHandler.getReferencedSubTreeListFromDB(): "
576
                               + ee.getMessage());
577
           }
578
       }//finally
579
       return result;
580
   }
581

    
582

    
583

    
584
    /** SAX Handler that is called at the start of each XML element */
585
    public void startElement(String uri, String localName, String qName,
586
            Attributes atts) throws SAXException
587
    {
588
        // for element <eml:eml...> qname is "eml:eml", local name is "eml"
589
        // for element <acl....> both qname and local name is "eml"
590
        // uri is namesapce
591
        logMetacat.debug("Start ELEMENT(qName) " + qName);
592
        logMetacat.debug("Start ELEMENT(localName) " + localName);
593
        logMetacat.debug("Start ELEMENT(uri) " + uri);
594

    
595
        DBSAXNode parentNode = null;
596
        DBSAXNode currentNode = null;
597
        // none inline part
598
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
599
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
600
        if (!handleInlineData)
601
        {
602
            // Get a reference to the parent node for the id
603
            try
604
            {
605
                parentNode = (DBSAXNode) nodeStack.peek();
606
            }
607
            catch (EmptyStackException e)
608
            {
609
                parentNode = null;
610
            }
611

    
612
            //start handle inline data
613
            //=====================================================
614
            if (qName.equals(INLINE) && !inAdditionalMetaData)
615
            {
616
                handleInlineData = true;
617
                inLineDataIndex++;
618
                //intitialize namespace hash for in line data
619
                inlineDataNameSpace = new Hashtable();
620
                //initialize file writer
621
                String docidWithoutRev = DocumentUtil.getDocIdFromString(docid);
622
                String seperator = ".";
623
                try {
624
					seperator = PropertyService.getProperty("document.accNumSeparator");
625
				} catch (PropertyNotFoundException pnfe) {
626
					logMetacat.error("Could not get property 'accNumSeparator'.  " 
627
							+ "Setting separator to '.': "+ pnfe.getMessage());
628
				}
629
                // the new file name will look like docid.rev.2
630
                inlineDataFileName = docidWithoutRev + seperator + revision
631
                        + seperator + inLineDataIndex;
632
                inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
633
                // put the inline file id into a vector. If upload failed,
634
                // metacat will
635
                // delete the inline data file
636
                inlineFileIDList.add(inlineDataFileName);
637

    
638
                // put distribution id and inline file id into a  hash
639
                if (distributionId != null)
640
                {
641
                  //check to see if this inline data is readable or writable to
642
                  // this user
643
                  if (!previousUnreadableInlineDataObjectHash.isEmpty() &&
644
                       previousUnreadableInlineDataObjectHash.containsKey(distributionId))
645
                  {
646
                      unReadableInlineDataObject = true;
647
                  }
648
                  if (!previousUnwritableInlineDataObjectHash.isEmpty() &&
649
                       previousUnwritableInlineDataObjectHash.containsKey(distributionId))
650
                  {
651
                     unWritableInlineDataObject = true;
652
                     numberOfHitUnWritableInlineData++;
653
                  }
654

    
655

    
656
                  // store the distributid and inlinedata filename into a hash
657
                  inlineDistributionIdList.put(distributionId, inlineDataFileName);
658
                }
659

    
660
            }
661
            //==============================================================
662

    
663

    
664
            // If hit a text node, we need write this text for current's parent
665
            // node
666
            // This will happend if the element is mixted
667
            //==============================================================
668
            if (hitTextNode && parentNode != null)
669
            {
670

    
671

    
672
                if (needToCheckAccessModule
673
                        && (processAdditionalAccess || processOtherAccess || processTopLevelAccess)) {
674
                    // stored the pull out nodes into storedNode stack
675
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
676
                            null, null, MetacatUtil.normalize(textBuffer
677
                                    .toString()));
678
                    storedAccessNodeStack.push(nodeElement);
679

    
680
                }
681

    
682
                // write the textbuffer into db for parent node.
683
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
684
                        parentNode);
685
                // rest hitTextNode
686
                hitTextNode = false;
687
                // reset textbuffer
688
                textBuffer = null;
689
                textBuffer = new StringBuffer();
690

    
691
            }
692
            //==================================================================
693

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

    
733
                    try {
734
                        // Get dbconnection
735
                        dbConn = DBConnectionPool
736
                                .getDBConnection("DBSAXHandler.startElement");
737
                        serialNumber = dbConn.getCheckOutSerialNumber();
738

    
739
                        Statement stmt = dbConn.createStatement();
740
                        ResultSet rs = stmt
741
                                .executeQuery("SELECT catalog_id FROM xml_catalog "
742
                                        + "WHERE entry_type = 'Schema' "
743
                                        + "AND public_id = '" + doctype + "'");
744
                        boolean hasRow = rs.next();
745
                        if (hasRow) {
746
                            catalogid = rs.getString(1);
747
                        }
748
                        stmt.close();
749
                        //System.out.println("here!!!!!!!!!!!!!!!!!!2");
750
                    }//try
751
                    finally {
752
                        // Return dbconnection
753
                        DBConnectionPool.returnDBConnection(dbConn,
754
                                serialNumber);
755
                    }//finally
756

    
757
                    //create documentImpl object by the constructor which can
758
                    // specify
759
                    //the revision
760
                    if (!super.getIsRevisionDoc())
761
                    {
762
                       logMetacat.debug("EML200SaxHandler.startElement - creating new DocumentImple for " + docid);
763
                       currentDocument = new DocumentImpl(connection, rootNode
764
                            .getNodeID(), docname, doctype, docid, revision,
765
                            action, user, this.pub, catalogid, this.serverCode, 
766
                            createDate, updateDate);
767
                    }
768
                   
769

    
770
                } catch (Exception ane) {
771
                    throw (new SAXException("EML200SaxHandler.startElement - error with action " + 
772
                    		action + " : " + ane.getMessage()));
773
                }
774
                
775
            }
776
            //==================================================================
777

    
778
            // node
779
            //==================================================================
780
            // Create the current node representation
781
            currentNode = new DBSAXNode(connection, qName, localName,
782
                    parentNode, rootNode.getNodeID(), docid,
783
                    doctype);
784
            // Use a local variable to store the element node id
785
            // If this element is a start point of subtree(section), it will be
786
            // stored
787
            // otherwise, it will be discated
788
            long startNodeId = currentNode.getNodeID();
789
            // Add all of the namespaces
790
            String prefix = null;
791
            String nsuri = null;
792
            Enumeration prefixes = namespaces.keys();
793
            while (prefixes.hasMoreElements())
794
            {
795
                prefix = (String) prefixes.nextElement();
796
                nsuri = (String) namespaces.get(prefix);
797
                endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
798
            }
799

    
800
            //=================================================================
801
           // attributes
802
           // Add all of the attributes
803
          for (int i = 0; i < atts.getLength(); i++)
804
          {
805
              String attributeName = atts.getQName(i);
806
              String attributeValue = atts.getValue(i);
807
              endNodeId = currentNode.setAttribute(attributeName,
808
                      attributeValue, docid);
809

    
810
              // To handle name space and schema location if the attribute
811
              // name is
812
              // xsi:schemaLocation. If the name space is in not in catalog
813
              // table
814
              // it will be regeistered.
815
              if (attributeName != null
816
                      && attributeName
817
                              .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
818
                  SchemaLocationResolver resolver = new SchemaLocationResolver(
819
                          attributeValue);
820
                  resolver.resolveNameSpace();
821

    
822
              }
823
              else if (attributeName != null && attributeName.equals(ID) &&
824
                       currentNode.getTagName().equals(DISTRIBUTION) &&
825
                       !inAdditionalMetaData)
826
              {
827
                 // this is a distribution element and the id is distributionID
828
                 distributionId = attributeValue;
829
                 distributionAllIdList.put(distributionId, distributionId);
830

    
831
              }
832

    
833
          }//for
834

    
835

    
836
           //=================================================================
837

    
838
            // handle access stuff
839
            //==================================================================
840
            if (localName.equals(ACCESS))
841
            {
842
                //make sure the access is top level
843
                // this mean current node's parent's parent should be "eml"
844
                DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
845
                                                                    // parent
846
                                                                    // node
847
                //peek out grandParentNode
848
                DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
849
                // put parent node back
850
                nodeStack.push(tmpNode);
851
                String grandParentTag = grandParentNode.getTagName();
852
                if (grandParentTag.equals(EML) && !inAdditionalMetaData)
853
                {
854
                  processTopLevelAccess = true;
855

    
856
                }
857
                else if ( !inAdditionalMetaData )
858
                {
859
                  // process other access embedded into resource level
860
                  // module
861
                  processOtherAccess = true;
862
                }
863
                else
864
                {
865
                  // this for access in additional data which doesn't have a
866
                  // described element. If it has a described element,
867
                  // this code won't hurt any thing
868
                  processAdditionalAccess = true;
869
                }
870

    
871

    
872
                // create access object
873
                accessObject = new AccessSection();
874
                // set permission order
875
                String permOrder = currentNode.getAttribute(ORDER);
876
                accessObject.setPermissionOrder(permOrder);
877
                // set access id
878
                String accessId = currentNode.getAttribute(ID);
879
                accessObject.setSubTreeId(accessId);
880
                // for additional access subtree, the  start of node id should
881
                // be describe element. We also stored the start access element
882
                // node id too.
883
                if (processAdditionalAccess)
884
                {
885
                  accessObject.setStartedDescribesNodeId(firstDescribesNodeId);
886
                  accessObject.setControlLevel(DATAACCESSLEVEL);
887
                }
888
                else if (processTopLevelAccess)
889
                {
890
                  accessObject.setControlLevel(TOPLEVEL);
891
                }
892
                else if (processOtherAccess)
893
                {
894
                  accessObject.setControlLevel(REFERENCEDLEVEL);
895
                }
896

    
897
                accessObject.setStartNodeId(startNodeId);
898
                accessObject.setDocId(docid);
899

    
900

    
901

    
902
            }
903
            // Set up a access rule for allow
904
            else if (parentNode.getTagName() != null
905
                    && (parentNode.getTagName()).equals(ACCESS)
906
                    && localName.equals(ALLOW))
907
           {
908

    
909
                accessRule = new AccessRule();
910

    
911
                //set permission type "allow"
912
                accessRule.setPermissionType(ALLOW);
913

    
914
            }
915
            // set up an access rule for den
916
            else if (parentNode.getTagName() != null
917
                    && (parentNode.getTagName()).equals(ACCESS)
918
                    && localName.equals(DENY))
919
           {
920
                accessRule = new AccessRule();
921
                //set permission type "allow"
922
                accessRule.setPermissionType(DENY);
923
            }
924

    
925
            //=================================================================
926
            // some other independ stuff
927

    
928
            // Add the node to the stack, so that any text data can be
929
            // added as it is encountered
930
            nodeStack.push(currentNode);
931
            // Add the node to the vector used by thread for writing XML Index
932
            nodeIndex.addElement(currentNode);
933

    
934
            // store access module element and attributes into stored stack
935
            if (needToCheckAccessModule
936
                    && (processAdditionalAccess || processOtherAccess || processTopLevelAccess))
937
            {
938
                // stored the pull out nodes into storedNode stack
939
                NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
940
                        localName, prefix, MetacatUtil.normalize(null));
941
                storedAccessNodeStack.push(nodeElement);
942
                for (int i = 0; i < atts.getLength(); i++) {
943
                    String attributeName = atts.getQName(i);
944
                    String attributeValue = atts.getValue(i);
945
                    NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2,
946
                            "ATTRIBUTE", attributeName, null, MetacatUtil
947
                                    .normalize(attributeValue));
948
                    storedAccessNodeStack.push(nodeAttribute);
949
                }
950

    
951
            }
952

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

    
993

    
994
             //==================================================================
995
            // reset name space
996
            namespaces = null;
997
            namespaces = new Hashtable();
998

    
999
        }//not inline data
1000
        // inline data
1001
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1002
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1003
        else
1004
        {
1005
            // we don't buffer the inline data in characters() method
1006
            // so start character don't need to hand text node.
1007

    
1008
            // inline data may be the xml format.
1009
            StringBuffer inlineElements = new StringBuffer();
1010
            inlineElements.append("<").append(qName);
1011
            // append attributes
1012
            for (int i = 0; i < atts.getLength(); i++) {
1013
                String attributeName = atts.getQName(i);
1014
                String attributeValue = atts.getValue(i);
1015
                inlineElements.append(" ");
1016
                inlineElements.append(attributeName);
1017
                inlineElements.append("=\"");
1018
                inlineElements.append(attributeValue);
1019
                inlineElements.append("\"");
1020
            }
1021
            // append namespace
1022
            String prefix = null;
1023
            String nsuri = null;
1024
            Enumeration prefixes = inlineDataNameSpace.keys();
1025
            while (prefixes.hasMoreElements()) {
1026
                prefix = (String) prefixes.nextElement();
1027
                nsuri =  (String)  inlineDataNameSpace.get(prefix);
1028
                inlineElements.append(" ");
1029
                inlineElements.append("xmlns:");
1030
                inlineElements.append(prefix);
1031
                inlineElements.append("=\"");
1032
                inlineElements.append(nsuri);
1033
                inlineElements.append("\"");
1034
            }
1035
            inlineElements.append(">");
1036
            //reset inline data name space
1037
            inlineDataNameSpace = null;
1038
            inlineDataNameSpace = new Hashtable();
1039
            //write inline data into file
1040
            logMetacat.info("the inline element data is: "
1041
                    + inlineElements.toString());
1042
            writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
1043
        }//else
1044
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1045
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1046

    
1047
    }
1048

    
1049

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

    
1079
                }
1080
                textBuffer = null;
1081
                textBuffer = new StringBuffer();
1082
            }
1083
        }
1084
        else
1085
        {
1086
            // this is inline data and write file system directly
1087
            // we don't need to buffered it.
1088
            StringBuffer inlineText = new StringBuffer();
1089
            inlineText.append(new String(cbuf, start, len));
1090
            logMetacat.info(
1091
                    "The inline text data write into file system: "
1092
                            + inlineText.toString());
1093
            writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
1094
        }
1095
    }
1096

    
1097
    /** SAX Handler that is called at the end of each XML element */
1098
    public void endElement(String uri, String localName, String qName)
1099
            throws SAXException
1100
    {
1101
        logMetacat.info("End ELEMENT " + qName);
1102

    
1103
        // when close inline element
1104
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1105
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1106
        if (localName.equals(INLINE) && handleInlineData)
1107
        {
1108
            // Get the node from the stack
1109
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1110
            String currentTag = currentNode.getTagName();
1111
            logMetacat.info("End of inline data");
1112
            // close file writer
1113
            try
1114
            {
1115
                inlineDataFileWriter.close();
1116
                handleInlineData = false;
1117
            }
1118
            catch (IOException ioe)
1119
            {
1120
                throw new SAXException(ioe.getMessage());
1121
            }
1122

    
1123
            //check if user changed inine data or not if user doesn't have
1124
            // write permission for this inline block
1125
            // if some error happends, we would delete the inline data file here,
1126
            // we will call a method named deletedInlineFiles in DocumentImple
1127
            if (unWritableInlineDataObject)
1128
            {
1129
                if (unReadableInlineDataObject)
1130
                {
1131
                  // now user just got a empty string in linline part
1132
                  // so if the user send back a empty string is fine and we will
1133
                  // copy the old file to new file. If he send something else,
1134
                  // the document will be rejected
1135
                  if (inlineDataIsEmpty(inlineDataFileName))
1136
                  {
1137
                    copyInlineFile(distributionId, inlineDataFileName);
1138
                  }
1139
                  else
1140
                  {
1141
                    logMetacat.info(
1142
                               "inline data was changed by a user"
1143
                                       + " who doesn't have permission");
1144
                    throw new SAXException(PERMISSIONERROR);
1145

    
1146
                  }
1147
                }//if
1148
                else
1149
                {
1150
                  // user get the inline data
1151
                  if (modifiedInlineData(distributionId, inlineDataFileName))
1152
                  {
1153
                    logMetacat.info(
1154
                                "inline data was changed by a user"
1155
                                        + " who doesn't have permission");
1156
                    throw new SAXException(PERMISSIONERROR);
1157
                  }//if
1158
                }//else
1159
            }//if
1160
            else
1161
            {
1162
               //now user can update file.
1163
               if (unReadableInlineDataObject)
1164
               {
1165
                  // now user just got a empty string in linline part
1166
                  // so if the user send back a empty string is fine and we will
1167
                  // copy the old file to new file. If he send something else,
1168
                  // the new inline data will overwite the old one(here we need
1169
                  // do nothing because the new inline data already existed
1170
                  if (inlineDataIsEmpty(inlineDataFileName))
1171
                  {
1172
                    copyInlineFile(distributionId, inlineDataFileName);
1173
                  }
1174
                }//if
1175

    
1176
            }//else
1177
            // put inline data file name into text buffer (without path)
1178
            textBuffer = new StringBuffer(inlineDataFileName);
1179
            // write file name into db
1180
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1181
                    currentNode);
1182
            // reset textbuff
1183
            textBuffer = null;
1184
            textBuffer = new StringBuffer();
1185
            // resetinlinedata file name
1186
            inlineDataFileName = null;
1187
            unWritableInlineDataObject = false;
1188
            unReadableInlineDataObject = false;
1189
            return;
1190
        }
1191
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1192
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1193

    
1194

    
1195

    
1196
        // close element which is not in inline data
1197
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1198
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1199
        if (!handleInlineData)
1200
        {
1201
            // Get the node from the stack
1202
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1203
            String currentTag = currentNode.getTagName();
1204

    
1205
            // If before the end element, the parser hit text nodes and store
1206
            // them
1207
            // into the buffer, write the buffer to data base. The reason we
1208
            // put
1209
            // write database here is for xerces some time split text node
1210
            if (hitTextNode)
1211
            {
1212
                // get access value
1213
                String data = null;
1214
                // add principal
1215
                if (currentTag.equals(PRINCIPAL) && accessRule != null)
1216
                {
1217
                    data = (textBuffer.toString()).trim();
1218
                    accessRule.addPrincipal(data);
1219

    
1220
                }
1221
                else if (currentTag.equals(PERMISSION) && accessRule != null)
1222
                {
1223
                    data = (textBuffer.toString()).trim();
1224
                    // we conbine different a permission into one value
1225
                    int permission = accessRule.getPermission();
1226
                    // add permision
1227
                    if (data.toUpperCase().equals(READSTRING))
1228
                    {
1229
                        permission = permission | READ;
1230
                    }
1231
                    else if (data.toUpperCase().equals(WRITESTRING))
1232
                    {
1233
                        permission = permission | WRITE;
1234
                    }
1235
                    else if (data.toUpperCase().equals(CHMODSTRING))
1236
                    {
1237
                        permission = permission | CHMOD;
1238
                    }
1239
                    else if (data.toUpperCase().equals(ALLSTRING))
1240
                    {
1241
                        permission = permission | ALL;
1242
                    }
1243
                    accessRule.setPermission(permission);
1244
                }
1245
                // put additionalmetadata/describes into vector
1246
                else if (currentTag.equals(DESCRIBES))
1247
                {
1248
                    data = (textBuffer.toString()).trim();
1249
                    describesId.add(data);
1250
                    //firstDescribesInAdditionalMetadata = false;
1251
                    //firstDescribesNodeId = 0;
1252
                }
1253
                else if (currentTag.equals(REFERENCES)
1254
                        && (processTopLevelAccess || processAdditionalAccess || processOtherAccess))
1255
                {
1256
                    // get reference
1257
                    data = (textBuffer.toString()).trim();
1258
                    // put reference id into accessSection
1259
                    accessObject.setReferences(data);
1260

    
1261
                }
1262
                else if (currentTag.equals(REFERENCES) && proccessDistribution)
1263
                {
1264
                  // get reference for distribution
1265
                  data = (textBuffer.toString()).trim();
1266
                  // we only stored the distribution reference which itself
1267
                  // has a id
1268
                  if (distributionId != null)
1269
                  {
1270
                    distributionReferenceList.put(distributionId, data);
1271
                  }
1272

    
1273
                }
1274
                else if (currentTag.equals(URL) && !inAdditionalMetaData)
1275
                {
1276
                    //handle online data, make sure its'parent is online
1277
                    DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1278
                    if (parentNode != null && parentNode.getTagName() != null
1279
                            && parentNode.getTagName().equals(ONLINE))
1280
                    {
1281
                        data = (textBuffer.toString()).trim();
1282
                        if (distributionId != null)
1283
                        {
1284
                          onlineURLDistributionIdList.put(distributionId, data);
1285
                        }
1286
                        else
1287
                        {
1288
                          onlineURLDistributionListWithoutId.add(data);
1289
                        }
1290
                    }//if
1291
                }//else if
1292
                // write text to db if it is not inline data
1293

    
1294
                logMetacat.info(
1295
                            "Write text into DB in End Element");
1296

    
1297
                 // write text node into db
1298
                 endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1299
                            currentNode);
1300

    
1301
                if (needToCheckAccessModule
1302
                        && (processAdditionalAccess || processOtherAccess || processTopLevelAccess)) {
1303
                    // stored the pull out nodes into storedNode stack
1304
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1305
                            null, null, MetacatUtil.normalize(textBuffer
1306
                                    .toString()));
1307
                    storedAccessNodeStack.push(nodeElement);
1308

    
1309
                }
1310
            }//if handle text node
1311

    
1312

    
1313

    
1314
            //set hitText false
1315
            hitTextNode = false;
1316
            // reset textbuff
1317
            textBuffer = null;
1318
            textBuffer = new StringBuffer();
1319

    
1320

    
1321
            // access stuff
1322
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY))
1323
            {
1324
                // finish parser a ccess rule and assign it to new one
1325
                AccessRule newRule = accessRule;
1326
                //add the new rule to access section object
1327
                accessObject.addAccessRule(newRule);
1328
                // reset access rule
1329
                accessRule = null;
1330
            }// ALLOW or DENY
1331
            else if (currentTag.equals(ACCESS))
1332
            {
1333
                // finish parse a access setction and stored them into different
1334
                // places
1335

    
1336
                accessObject.setEndNodeId(endNodeId);
1337
                AccessSection newAccessObject = accessObject;
1338
                newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1339
                if (newAccessObject != null)
1340
                {
1341

    
1342
                    if (processTopLevelAccess)
1343
                    {
1344
                       topAccessSection = newAccessObject;
1345

    
1346
                    }//if
1347
                    else if (processAdditionalAccess)
1348
                    {
1349
                        // for additional control
1350
                        // put discribesId into the accessobject and put this
1351
                        // access object into vector
1352
                        newAccessObject.setDescribedIdList(describesId);
1353
                        additionalAccessVector.add(newAccessObject);
1354

    
1355
                    }//if
1356
                    else if (processOtherAccess)
1357
                    {
1358
                      // we only stored the access object which has a id
1359
                      // because only the access object which has a id can
1360
                      // be reference
1361
                      if (newAccessObject.getSubTreeId() != null &&
1362
                          !newAccessObject.getSubTreeId().trim().equals(""))
1363
                      {
1364
                         possibleReferencedAccessHash.
1365
                           put(newAccessObject.getSubTreeId(), newAccessObject);
1366
                      }
1367
                    }
1368

    
1369
                }//if
1370
                //reset access section object
1371
                accessObject = null;
1372

    
1373
                // reset tmp stored node stack
1374
                storedAccessNodeStack = null;
1375
                storedAccessNodeStack = new Stack();
1376

    
1377
                // reset flag
1378
                processAdditionalAccess = false;
1379
                processTopLevelAccess = false;
1380
                processOtherAccess = false;
1381

    
1382
            }//access element
1383
            else if (currentTag.equals(ADDITIONALMETADATA))
1384
            {
1385
                //reset describesId
1386
                describesId = null;
1387
                describesId = new Vector();
1388
                inAdditionalMetaData = false;
1389
                firstDescribesNodeId = -1;
1390
                // reset tmp stored node stack
1391
                storedAccessNodeStack = null;
1392
                storedAccessNodeStack = new Stack();
1393

    
1394

    
1395
            }
1396
            else if (currentTag.equals(DISTRIBUTION) && !inAdditionalMetaData)
1397
            {
1398
               //reset distribution id
1399
               distributionId = null;
1400
               proccessDistribution = false;
1401
            }
1402
            else if (currentTag.equals(OFFLINE) && !inAdditionalMetaData)
1403
            {
1404
               if (distributionId != null)
1405
               {
1406
                 offlineDistributionIdList.put(distributionId, distributionId);
1407
               }
1408
            }
1409
            else if ((currentTag.equals(CONNECTION) || currentTag.equals(CONNECTIONDEFINITION))
1410
                     && !inAdditionalMetaData)
1411
            {
1412
              //handle online data, make sure its'parent is online
1413
                 DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1414
                 if (parentNode != null && parentNode.getTagName() != null
1415
                         && parentNode.getTagName().equals(ONLINE))
1416
                 {
1417
                     if (distributionId != null)
1418
                     {
1419
                        onlineOtherDistributionIdList.put(distributionId, distributionId);
1420
                     }
1421
                 }//if
1422

    
1423
            }//else if
1424
            else if (currentTag.equals(DESCRIBES))
1425
            {
1426
                firstDescribesInAdditionalMetadata = false;
1427

    
1428
            }
1429

    
1430

    
1431

    
1432
        }
1433
        // close elements which are in inline data (inline data can be xml doc)
1434
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1435
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1436
        else
1437
        {
1438
            // this is in inline part
1439
            StringBuffer endElement = new StringBuffer();
1440
            endElement.append("</");
1441
            endElement.append(qName);
1442
            endElement.append(">");
1443
            logMetacat.info("inline endElement: "
1444
                    + endElement.toString());
1445
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1446
        }
1447
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1448
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1449
    }
1450

    
1451

    
1452
    /*
1453
     * Method to check if the new line data is as same as the old one
1454
     */
1455
     private boolean modifiedInlineData(String inlineDistributionId,
1456
			String newInlineInternalFileName) throws SAXException {
1457
       boolean modified = true;
1458
       if (inlineDistributionId == null || newInlineInternalFileName == null)
1459
       {
1460
         return modified;
1461
       }
1462
       String oldInlineInternalFileName =
1463
            (String)previousUnwritableInlineDataObjectHash.get(inlineDistributionId);
1464
       if (oldInlineInternalFileName == null ||
1465
           oldInlineInternalFileName.trim().equals(""))
1466
       {
1467
         return modified;
1468
       }
1469
       logMetacat.info("in handle inline data");
1470
       logMetacat.info("the inline data file name from xml_access is: "
1471
                                    + oldInlineInternalFileName);
1472

    
1473
       try
1474
       {
1475
         if (!compareInlineDataFiles(oldInlineInternalFileName,
1476
                                     newInlineInternalFileName))
1477
         {
1478
           modified = true;
1479

    
1480
         }
1481
         else
1482
         {
1483
           modified = false;
1484
         }
1485
       }
1486
       catch(Exception e)
1487
       {
1488
         modified = true;
1489
       }
1490

    
1491
       // delete the inline data file already in file system
1492
       if (modified)
1493
       {
1494
         deleteInlineDataFile(newInlineInternalFileName);
1495

    
1496
       }
1497
       return modified;
1498
     }
1499

    
1500
     /*
1501
      * A method to check if a line file is empty
1502
      */
1503
     private boolean inlineDataIsEmpty(String fileName) throws SAXException
1504
     {
1505
        boolean isEmpty = true;
1506
        if ( fileName == null)
1507
        {
1508
          throw new SAXException("The inline file name is null");
1509
        }
1510
        
1511
        try {
1512
			String path = PropertyService.getProperty("application.inlinedatafilepath");
1513
			// the new file name will look like path/docid.rev.2
1514
			File inlineDataDirectory = new File(path);
1515
			File inlineDataFile = new File(inlineDataDirectory, fileName);
1516

    
1517
			FileReader inlineFileReader = new FileReader(inlineDataFile);
1518
			BufferedReader inlineStringReader = new BufferedReader(inlineFileReader);
1519
			String string = inlineStringReader.readLine();
1520
			// at the end oldstring will be null
1521
			while (string != null) {
1522
				string = inlineStringReader.readLine();
1523
				if (string != null && !string.trim().equals("")) {
1524
					isEmpty = false;
1525
					break;
1526
				}
1527
			}
1528

    
1529
		} catch (Exception e) {
1530
			throw new SAXException(e.getMessage());
1531
		}
1532
		return isEmpty;
1533

    
1534
     }
1535

    
1536

    
1537
    /**
1538
	 * SAX Handler that receives notification of comments in the DTD
1539
	 */
1540
    public void comment(char[] ch, int start, int length) throws SAXException
1541
    {
1542
        logMetacat.info("COMMENT");
1543
        if (!handleInlineData) {
1544
            if (!processingDTD) {
1545
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1546
                String str = new String(ch, start, length);
1547

    
1548
                //compare comment if need
1549
                /*if (startCriticalSubTree) {
1550
                    compareCommentNode(currentUnChangedableSubtreeNodeStack,
1551
                            str, PERMISSIONERROR);
1552
                }//if*/
1553
                //compare top level access module
1554
                if (processTopLevelAccess && needToCheckAccessModule) {
1555
                    /*compareCommentNode(currentUnchangableAccessModuleNodeStack,
1556
                            str, UPDATEACCESSERROR);*/
1557
                }
1558
                endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
1559
                        str, docid);
1560
                if (needToCheckAccessModule
1561
                        && (processAdditionalAccess || processOtherAccess || processTopLevelAccess)) {
1562
                    // stored the pull out nodes into storedNode stack
1563
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2,
1564
                            "COMMENT", null, null, MetacatUtil.normalize(str));
1565
                    storedAccessNodeStack.push(nodeElement);
1566

    
1567
                }
1568
            }
1569
        } else {
1570
            // inline data comment
1571
            StringBuffer inlineComment = new StringBuffer();
1572
            inlineComment.append("<!--");
1573
            inlineComment.append(new String(ch, start, length));
1574
            inlineComment.append("-->");
1575
            logMetacat.info("inline data comment: "
1576
                    + inlineComment.toString());
1577
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1578
        }
1579
    }
1580

    
1581

    
1582

    
1583
    /**
1584
     * SAX Handler called once for each processing instruction found: node that
1585
     * PI may occur before or after the root element.
1586
     */
1587
    public void processingInstruction(String target, String data)
1588
            throws SAXException
1589
    {
1590
        logMetacat.info("PI");
1591
        if (!handleInlineData) {
1592
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1593
            endNodeId = currentNode.writeChildNodeToDB("PI", target, data,
1594
                    docid);
1595
        } else {
1596
            StringBuffer inlinePI = new StringBuffer();
1597
            inlinePI.append("<?");
1598
            inlinePI.append(target);
1599
            inlinePI.append(" ");
1600
            inlinePI.append(data);
1601
            inlinePI.append("?>");
1602
            logMetacat.info("inline data pi is: "
1603
                    + inlinePI.toString());
1604
            writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1605
        }
1606
    }
1607

    
1608
    /** SAX Handler that is called at the start of Namespace */
1609
    public void startPrefixMapping(String prefix, String uri)
1610
            throws SAXException
1611
    {
1612
        logMetacat.info("NAMESPACE");
1613
        logMetacat.info("NAMESPACE prefix "+prefix);
1614
        logMetacat.info("NAMESPACE uri "+uri);
1615
        if (!handleInlineData) {
1616
            namespaces.put(prefix, uri);
1617
        } else {
1618
            inlineDataNameSpace.put(prefix, uri);
1619
        }
1620
    }
1621

    
1622
    /**
1623
     * SAX Handler that is called for each XML text node that is Ignorable
1624
     * white space
1625
     */
1626
    public void ignorableWhitespace(char[] cbuf, int start, int len)
1627
            throws SAXException
1628
    {
1629
        // When validation is turned "on", white spaces are reported here
1630
        // When validation is turned "off" white spaces are not reported here,
1631
        // but through characters() callback
1632
        logMetacat.info("IGNORABLEWHITESPACE");
1633
        if (!handleInlineData) {
1634
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1635
            String data = new String(cbuf, start, len);
1636

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

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

    
1660
    }
1661

    
1662

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

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

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

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

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

    
1701

    
1702

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

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

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

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

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

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

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

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

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

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

    
1806

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

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

    
1826

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

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

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

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

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

    
1933

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

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

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

    
2017
   }//writeAdditonalLevelAccessRuletoDB
2018

    
2019

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

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

    
2059
         }
2060
       }//while
2061

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

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

    
2097
       try
2098
       {
2099

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

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

    
2159
    }//writeGivenAccessRuleIntoDB
2160

    
2161

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

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

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

    
2214
    }
2215

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

    
2243
    }
2244

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

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

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

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

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

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

    
2301
            }
2302

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

    
2341
    }//writeAccessSubtreeIntoDB
2342

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

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

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

    
2393
    // write inline data into file system and return file name(without path)
2394
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2395
            throws SAXException
2396
    {
2397
        try {
2398
            writer.write(data.toString());
2399
            writer.flush();
2400
        } catch (Exception e) {
2401
            throw new SAXException(e.getMessage());
2402
        }
2403
    }
2404

    
2405

    
2406

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

    
2425
            FileReader oldFileReader = new FileReader(oldDataFile);
2426
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2427
            FileReader newFileReader = new FileReader(newDataFile);
2428
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2429
            // read first line of data
2430
            String oldString = oldStringReader.readLine();
2431
            String newString = newStringReader.readLine();
2432

    
2433
            // at the end oldstring will be null
2434
            while (oldString != null) {
2435
                oldString = oldStringReader.readLine();
2436
                newString = newStringReader.readLine();
2437
                if (!oldString.equals(newString)) {
2438
                    same = false;
2439
                    break;
2440
                }
2441
            }
2442

    
2443
            // if oldString is null but newString is not null, they are same
2444
            if (same) {
2445
                if (newString != null) {
2446
                    same = false;
2447
                }
2448
            }
2449

    
2450
        } catch (Exception e) {
2451
            throw new McdbException(e.getMessage());
2452
        }
2453
        logMetacat.info("the inline data retrieve from file: " + data);
2454
        return same;
2455
    }
2456

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

    
2470
		if (oldInlineInternalFileName == null
2471
				|| oldInlineInternalFileName.trim().equals("")) {
2472
			throw new SAXException("Could not copy inline file from old one to new "
2473
					+ "one because can't find old file name");
2474
		}
2475
		logMetacat.info("in handle inline data");
2476
		logMetacat.info("the inline data file name from xml_access is: "
2477
				+ oldInlineInternalFileName);
2478

    
2479
		FileReader oldFileReader = null;
2480
		FileWriter newFileWriter = null;
2481
		try {
2482
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2483
			// the new file name will look like path/docid.rev.2
2484
			File inlineDataDirectory = new File(path);
2485
			File oldDataFile = new File(inlineDataDirectory, oldInlineInternalFileName);
2486
			File newDataFile = new File(inlineDataDirectory, newFileName);
2487

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

    
2506
			}
2507
			if (newFileWriter != null) {
2508
				try {
2509
					newFileWriter.close();
2510
				} catch (Exception ee) {
2511
					throw new SAXException(ee.getMessage());
2512
				}
2513

    
2514
			}
2515
		}
2516
	}
2517

    
2518

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

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

    
2545
    }
2546

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

    
2561
			fileReader = new FileReader(dataFile);
2562
			// stringReader = new BufferedReader(fileReader);
2563
		} catch (Exception e) {
2564
			throw new McdbException(e.getMessage());
2565
		}
2566
		// return stringReader;
2567
		return fileReader;
2568
	}
2569

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

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

    
2637
    }//writeOnlineDataFileIdIntoRelationTable
2638

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

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

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

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

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

    
2771
        }//while
2772

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

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

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

    
2821
    }
2822

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

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

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

    
2921

    
2922

    
2923
}
(32-32/62)