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-02-03 13:29:30 -0800 (Wed, 03 Feb 2010) $'
11
 * '$Revision: 5208 $'
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 bethods 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 "<describ>" 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 intrested senario: 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 permssion, but has write premission 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
    private boolean processTopLeverAccess = false;
120

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

    
125
    private boolean processOtherAccess = false;
126

    
127
    private AccessSection accessObject = null;
128

    
129
    private AccessRule accessRule = null;
130

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

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

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

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

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

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

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

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

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

    
174
    private boolean needCheckingAccessModule = false;
175

    
176
    private AccessSection unChangebleTopAccessSubTree = null;
177

    
178
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
179

    
180
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
181

    
182
    private AccessSection topAccessSection;
183

    
184
    private Vector additionalAccessVector = new Vector();
185

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

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

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

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

    
199
    private Hashtable inlineDataNameSpace = null;
200

    
201
    private FileWriter inlineDataFileWriter = null;
202

    
203
    private String inlineDataFileName = null;
204

    
205
    private int inLineDataIndex = 0;
206

    
207
    private Vector inlineFileIDList = new Vector();
208

    
209
    private boolean inadditionalMetaData = false;
210

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

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

    
221
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
222

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

    
229
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
230

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

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

    
249
    private int numberOfHitUnWritableInlineData = 0;
250

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
355
            }
356

    
357

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

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

    
380

    
381
       try
382
       {
383
            pstmt = connection.prepareStatement(sql);
384
            // Increase DBConnection usage count
385
            connection.increaseUsageCount(1);
386
            // Bind the values to the query
387
            pstmt.setString(1, docid);
388
            pstmt.setString(2, TOPLEVEL);
389
            logMetacat.debug("Eml200SAXHandler.getTopAccessSubTreeFromDB - executing SQL: " + pstmt.toString());
390
            pstmt.execute();
391

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

    
430
     }
431

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

    
445
        try
446
        {
447

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

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

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

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

    
511
       try
512
       {
513

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

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

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

    
567

    
568

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

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

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

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

    
640

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

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

    
648

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

    
656

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

    
665
                }
666

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

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

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

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

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

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

    
755
                } catch (Exception ane) {
756
                    throw (new SAXException("EML200SaxHandler.startElement - error with action " + 
757
                    		action + " : " + ane.getMessage()));
758
                }
759
                
760
            }
761
            //==================================================================
762

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

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

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

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

    
816
              }
817

    
818
          }//for
819

    
820

    
821
           //=================================================================
822

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

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

    
857

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

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

    
886

    
887

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

    
895
                accessRule = new AccessRule();
896

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

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

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

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

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

    
937
            }
938

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

    
979

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

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

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

    
1033
    }
1034

    
1035

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

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

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

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

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

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

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

    
1180

    
1181

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

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

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

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

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

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

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

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

    
1295
                }
1296
            }//if handle text node
1297

    
1298

    
1299

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

    
1306

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

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

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

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

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

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

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

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

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

    
1380

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

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

    
1414
            }
1415

    
1416

    
1417

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

    
1437

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

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

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

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

    
1482
       }
1483
       return modified;
1484
     }
1485

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

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

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

    
1520
     }
1521

    
1522

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

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

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

    
1567

    
1568

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

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

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

    
1623
                //compare whitespace in access top module
1624
                if (processTopLeverAccess && needCheckingAccessModule) {
1625
                    /*compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1626
                            data, UPDATEACCESSERROR);*/
1627
                }
1628
                // Write the content of the node to the database
1629
                if (needCheckingAccessModule
1630
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1631
                    // stored the pull out nodes into storedNode stack
1632
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1633
                            null, null, MetacatUtil.normalize(data));
1634
                    storedAccessNodeStack.push(nodeElement);
1635

    
1636
                }
1637
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1638
                        docid);
1639
        } else {
1640
            //This is inline data write to file directly
1641
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1642
                    start, len));
1643
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1644
        }
1645

    
1646
    }
1647

    
1648

    
1649
    /** SAX Handler that receives notification of end of the document */
1650
    public void endDocument() throws SAXException
1651
    {
1652
        logMetacat.info("end Document");
1653
        if (needCheckingAccessModule)
1654
        {
1655
          compareAllAccessModules();
1656
        }
1657

    
1658
        // user deleted some inline block which it counldn't delete
1659
        if (numberOfHitUnWritableInlineData !=
1660
            previousUnwritableInlineDataObjectHash.size())
1661
        {
1662
          throw new SAXException("user deleted some inline block it couldn't");
1663
        }
1664

    
1665
        if (!super.getIsRevisionDoc())
1666
        {
1667
          // write access rule to xml_access table which include both top level
1668
          // and additional level(data access level). It also write access subtree
1669
          // info into xml_accesssubtree about the top access, additional access
1670
          // and some third place access modules which are referenced by top
1671
          // level or additional level
1672
          writeAccessRuleToDB();
1673

    
1674
          //delete relation table
1675
          deleteRelations();
1676
          //write relations
1677
           for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1678
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1679
            writeOnlineDataFileIdIntoRelationTable(id);
1680
           }
1681
        }
1682

    
1683
        // clean the subtree record
1684
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1685
    }
1686

    
1687

    
1688

    
1689
    /* The method will compare all access modules in eml document -
1690
     * topLevel, additionalLevel(data access) and referenced access module*/
1691
    private void compareAllAccessModules() throws SAXException
1692
    {
1693
      //compare top level
1694
      compareAccessSubtree(unChangebleTopAccessSubTree, topAccessSection);
1695

    
1696
      //compare additional level
1697
      int oldSize = unChangebleAdditionalAccessSubTreeVector.size();
1698
      int newSize = additionalAccessVector.size();
1699
      // if size is different, use deleted or added rules, so throw a exception
1700
      if (oldSize != newSize)
1701
      {
1702
        throw new SAXException(UPDATEACCESSERROR);
1703
      }
1704
      //because access modules are both ordered in ASC in vectors, so we can
1705
      // compare one bye one
1706
      for ( int i = 0; i < newSize; i++)
1707
      {
1708
        AccessSection fromDB = (AccessSection)
1709
                          unChangebleAdditionalAccessSubTreeVector.elementAt(i);
1710
        AccessSection fromParser = (AccessSection)
1711
                                additionalAccessVector.elementAt(i);
1712
        compareAccessSubtree(fromDB, fromParser);
1713
      }
1714

    
1715
      //compare referenced level
1716
      Enumeration em = unChangebleReferencedAccessSubTreeHash.keys();
1717
      while (em.hasMoreElements())
1718
      {
1719
        String id = (String)em.nextElement();
1720
        AccessSection fromDB = (AccessSection)
1721
                               unChangebleReferencedAccessSubTreeHash.get(id);
1722
        AccessSection fromParser = (AccessSection)
1723
                               possibleReferencedAccessHash.get(id);
1724
        compareAccessSubtree(fromDB, fromParser);
1725
      }
1726
    }
1727

    
1728
    /* The method will compare two access subtree. Currently they compare to
1729
     * nodes one by one. It also can be changed to parse the node first, then
1730
     * compare the parsed result
1731
     */
1732
    private void compareAccessSubtree(AccessSection fromDBTable,
1733
                                       AccessSection fromParser)
1734
                                      throws SAXException
1735
    {
1736
       if (fromDBTable == null || fromParser == null)
1737
       {
1738
         throw new SAXException(UPDATEACCESSERROR);
1739
       }
1740
       Stack nodeStackFromDBTable = fromDBTable.getSubTreeNodeStack();
1741
       Stack nodeStackFromParser  = fromParser.getStoredTmpNodeStack();
1742

    
1743
       Stack tempStack = new Stack();
1744
       while(!nodeStackFromDBTable.isEmpty()){
1745
           tempStack.push(nodeStackFromDBTable.pop());
1746
       }
1747
       comparingNodeStacks(tempStack, nodeStackFromParser);
1748
    }
1749

    
1750
    /* Compare two node stacks to see if they are same */
1751
  private void comparingNodeStacks(Stack stack1, Stack stack2)
1752
          throws SAXException
1753
  {
1754
      // make sure stack1 and stack2 are not empty
1755
      if (stack1.isEmpty() || stack2.isEmpty()) {
1756
          logMetacat.info("Because stack is empty!");
1757
          throw new SAXException(UPDATEACCESSERROR);
1758
      }
1759
      // go throw two stacks and compare every element
1760
      while (!stack1.isEmpty()) {
1761
          // Pop an element from stack1
1762
          NodeRecord record1 = (NodeRecord) stack1.pop();
1763

    
1764
          // Pop an element from stack2(stack 2 maybe empty)
1765
          NodeRecord record2 = null;
1766
          try {
1767
              record2 = (NodeRecord) stack2.pop();
1768
          } catch (EmptyStackException ee) {
1769

    
1770
              logMetacat.error(
1771
                      "Node stack2 is empty but stack1 isn't!");
1772
              throw new SAXException(UPDATEACCESSERROR);
1773
          }
1774
          // if two records are not same throw a exception
1775
          if (!record1.contentEquals(record2)) {
1776
              logMetacat.info("Two records from new and old stack are not "
1777
                                      + "same!" + record1 + "--" +record2);
1778
              throw new SAXException(UPDATEACCESSERROR);
1779
          }//if
1780
      }//while
1781

    
1782
      // now stack1 is empty and we should make sure stack2 is empty too
1783
      if (!stack2.isEmpty()) {
1784

    
1785
          logMetacat.info(
1786
                  "stack2 still have some elements while stack1 "
1787
                          + "is empty! ");
1788
          throw new SAXException(UPDATEACCESSERROR);
1789
      }//if
1790
  }//comparingNodeStacks
1791

    
1792

    
1793
    /* The method to write all access rule into db */
1794
    private void writeAccessRuleToDB() throws SAXException
1795
    {
1796
        // delete xml_accesssubtree table record for this docid
1797
        deleteAccessSubTreeRecord(docid);
1798
        //write additional access rule, and old records in xml_access will be
1799
        //deleted too
1800
        //System.out.println("before write additional access rules");
1801
        writeadditionalAccessRuleToDB();
1802
        //System.out.println("after write additional access rules");
1803
        //write top leve access rule, and old records in xml_access will be
1804
        //deleted too
1805

    
1806
        if (topAccessSection != null){
1807
          writeTopLevelAccessRuleToDB();
1808
        }
1809
        //System.out.println("after write top access rules");
1810
    }//writeAccessRuleToDB
1811

    
1812

    
1813
    /* The method will figure out access reference for given access section -
1814
     * return a new AccessSection which contain access rules that be referenced.
1815
     * And will write the access subtree into xml_access table.
1816
     * this is a recursive method
1817
     */
1818
   private AccessSection resolveAccessRuleReference(AccessSection access)
1819
                                                    throws SAXException
1820
   {
1821
     if (access == null)
1822
     {
1823
       logMetacat.info("access module is null in " +
1824
                                "resolveAccessRulesReference");
1825
       throw new SAXException("An access modules is null");
1826
     }
1827
     String subTreeId = access.getSubTreeId();
1828
     if (subTreeId == null ||
1829
         (subTreeId != null && !accessSubTreeAlreadyWriteDBList.contains(subTreeId)))
1830
     {
1831
        // we should record this access subtree into accesssubtree table.
1832
        // subtreeId is null means it can't be referenced. So this tree couldn't
1833
        // be stored twise in the table. Subtree is not null, but it is in
1834
        // hash yet, so it is new one.
1835
        writeAccessSubTreeIntoDB(access);
1836
        if (subTreeId != null)
1837
        {
1838
          accessSubTreeAlreadyWriteDBList.put(subTreeId, subTreeId);
1839
        }
1840
     }
1841

    
1842
     String reference = access.getReferences();
1843
     if (reference != null)
1844
     {
1845
       // find the reference in top level
1846
       String topSubtreeId = topAccessSection.getSubTreeId();
1847
       if (topSubtreeId != null && topSubtreeId.equals(reference))
1848
       {
1849
          return resolveAccessRuleReference(topAccessSection);
1850
       }
1851
       else
1852
       {
1853
           // search it the additional access
1854
           for ( int i = 0; i <additionalAccessVector.size(); i++)
1855
           {
1856
             AccessSection additionalAccess = (AccessSection)
1857
                           additionalAccessVector.elementAt(i);
1858
             String additionId = additionalAccess.getSubTreeId();
1859
             if (additionId != null && additionId.equals(reference))
1860
             {
1861
               return resolveAccessRuleReference(additionalAccess);
1862
             }// if
1863
           }// for
1864

    
1865
           // search possible referenced access hashtable
1866
           if (possibleReferencedAccessHash.containsKey(reference))
1867
           {
1868
             AccessSection referenceAccess = (AccessSection)
1869
                         possibleReferencedAccessHash.get(reference);
1870
             return resolveAccessRuleReference(referenceAccess);
1871
           }
1872

    
1873
           // if hit here, this means you don't find any id match the reference
1874
           // throw a exception
1875
           throw new SAXException("No access module's id match the reference id");
1876
       }
1877
     }
1878
     else
1879
     {
1880
       // base line reference == null
1881
       AccessSection newAccessSection = new AccessSection();
1882
       access.copyPermOrderAndAccessRules(newAccessSection);
1883
       return newAccessSection;
1884
     }
1885
   }//resolveAccessRuleReference
1886

    
1887
   /* This method will return a id which points a real distribution block if
1888
    *  given a distribution id which is a reference. If the given id is a real
1889
    *  distribution the id itself will be returned.
1890
    *  Here is segment of eml
1891
    *   <distribution id ="100"><online><url>abc</url></online></distribution>
1892
    *   <distribution id ="200"><reference>100</reference></distribution>
1893
    * if the given value is 200, 100 will be returned.
1894
    * if the given value is 100, 100 will be returned.
1895
    */
1896
   private String resolveDistributionReference(String givenId)
1897
   {
1898
      if (givenId == null )
1899
      {
1900
        return null;
1901
      }
1902
      if (!distributionReferenceList.containsKey(givenId))
1903
      {
1904
        //this is not reference distribution block, return given id
1905
        return givenId;
1906
      }
1907
      else
1908
      {
1909
         String referencedId = (String) distributionReferenceList.get(givenId);
1910
         // search util the referenced id is not in dsitribtionReferenceList
1911
         while (distributionReferenceList.containsKey(referencedId))
1912
         {
1913
           referencedId = (String) distributionReferenceList.get(referencedId);
1914
         }
1915
         return referencedId;
1916
      }
1917
   }
1918

    
1919

    
1920
  /* The method to write top level access rule into db. The old rules will be
1921
   * deleted
1922
   * If no describedId in the access object, this access rules will be ingorned
1923
   */
1924
  private void writeadditionalAccessRuleToDB() throws SAXException
1925
  {
1926
     //System.out.println("in write additional");
1927
     // we should delete all inline access rules in xml_access if
1928
     // user has all permission
1929
     if (!needCheckingAccessModule)
1930
     {
1931
       deleteAllInlineDataAccessRules();
1932
     }
1933
     for (int i=0; i < additionalAccessVector.size(); i++)
1934
     {
1935
       //System.out.println("in for loop of write additional");
1936
       AccessSection access = (AccessSection)additionalAccessVector.elementAt(i);
1937
       Vector describeIdList = access.getDescribedIdList();
1938
       // if this access is a reference, a new access object will be created
1939
       // which contains the real access rules referenced. Also, each access tree
1940
       // will be write into xml_accesssubtee table
1941
       AccessSection newAccess = resolveAccessRuleReference(access);
1942
       String permOrder = newAccess.getPermissionOrder();
1943
       Vector accessRule = newAccess.getAccessRules();
1944

    
1945
       if (describeIdList == null || describeIdList.isEmpty())
1946
       {
1947
         continue;
1948
       }
1949

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

    
2003
   }//writeAdditonalLevelAccessRuletoDB
2004

    
2005

    
2006
    /* The method to write additional access rule into db. */
2007
    private void writeTopLevelAccessRuleToDB() throws SAXException
2008
    {
2009
       // if top access is reference, we need figure out the real access rules
2010
       // it points to
2011
       //System.out.println("permorder in top level" + topAccessSection.getPermissionOrder());
2012
       AccessSection newAccess = resolveAccessRuleReference(topAccessSection);
2013
       //System.out.println("permorder in new level" + newAccess.getPermissionOrder());
2014
       String permOrder = newAccess.getPermissionOrder();
2015
       Vector accessRule = newAccess.getAccessRules();
2016
       String subtree     = null;
2017
       // document itself
2018
       deletePermissionsInAccessTableForDoc(docid);
2019
       writeGivenAccessRuleIntoDB(permOrder, accessRule, docid, subtree);
2020
       // for online data, it includes with id and without id.
2021
       // 1. for the data with subtree id, we should ignore the ones already in
2022
       // the hash - onlineURLIdHasAddionalAccess.
2023
       // 2. for those without subreeid, it couldn't have additional access and we
2024
       // couldn't ignore it.
2025
       // 3. for inline data, we need do nothing because if it doesn't have
2026
       // additional access, it default value is the top one.
2027

    
2028
       // here is the online url with id
2029
       Enumeration em = onlineURLDistributionIdList.keys();
2030
       while (em.hasMoreElements())
2031
       {
2032
         String onlineSubtreeId = (String)em.nextElement();
2033
         if (!onlineURLIdHasadditionalAccess.containsKey(onlineSubtreeId))
2034
         {
2035
            String url =
2036
                       (String)onlineURLDistributionIdList.get(onlineSubtreeId);
2037
            String onlineDataId = handleOnlineUrlDataFile(url);
2038
            if (onlineDataId != null)
2039
            {
2040
              deletePermissionsInAccessTableForDoc(onlineDataId);
2041
              writeGivenAccessRuleIntoDB(permOrder, accessRule,
2042
                                         onlineDataId, subtree);
2043
            }
2044

    
2045
         }
2046
       }//while
2047

    
2048
       // here is the onlineURL without id
2049
       for (int i= 0; i < onlineURLDistributionListWithoutId.size(); i++)
2050
       {
2051
         String url = (String)onlineURLDistributionListWithoutId.elementAt(i);
2052
         String onlineDataId = handleOnlineUrlDataFile(url);
2053
         if (onlineDataId != null)
2054
         {
2055
           deletePermissionsInAccessTableForDoc(onlineDataId);
2056
           writeGivenAccessRuleIntoDB(permOrder, accessRule,
2057
                                         onlineDataId, subtree);
2058
         }
2059
       }//for
2060
    }//writeTopAccessRuletoDB
2061

    
2062
    /* Write a gaven access rule into db */
2063
    private void writeGivenAccessRuleIntoDB(String permOrder, Vector accessRules,
2064
                     String dataId, String subTreeId) throws SAXException
2065
    {
2066
      if (permOrder == null || permOrder.trim().equals("") || dataId == null ||
2067
          dataId.trim().equals("") || accessRules == null ||
2068
          accessRules.isEmpty())
2069
      {
2070
        logMetacat.info("The access object is null and tried to " +
2071
                                  " write to xml_access table");
2072
        throw new SAXException("The access object is null");
2073
      }
2074
       // get rid of rev from dataId
2075
       //dataId = MetacatUtil.getDocIdFromString(dataId);
2076
       //String permOrder = accessSection.getPermissionOrder();
2077
       String sql = null;
2078
       PreparedStatement pstmt = null;
2079
       sql = "INSERT INTO xml_access (docid, principal_name, permission, "
2080
               + "perm_type, perm_order, accessfileid, subtreeid) VALUES "
2081
               + " (?, ?, ?, ?, ?, ?, ?)";
2082

    
2083
       try
2084
       {
2085

    
2086
           pstmt = connection.prepareStatement(sql);
2087
           // Increase DBConnection usage count
2088
           connection.increaseUsageCount(1);
2089
           // Bind the values to the query
2090
           pstmt.setString(1, dataId);
2091
           logMetacat.info("Docid in accesstable: " + docid);
2092
           pstmt.setString(6, docid);
2093
           logMetacat.info("Accessfileid in accesstable: " + docid);
2094
           pstmt.setString(5, permOrder);
2095
           logMetacat.info("PermOder in accesstable: " + permOrder);
2096
           pstmt.setString(7, subTreeId);
2097
           logMetacat.info("subtree id in accesstable: " + subTreeId);
2098
           // if it is not top level, set s id
2099

    
2100
           //Vector accessRules = accessSection.getAccessRules();
2101
           // go through every rule
2102
           for (int i = 0; i < accessRules.size(); i++)
2103
           {
2104
               AccessRule rule = (AccessRule) accessRules.elementAt(i);
2105
               String permType = rule.getPermissionType();
2106
               int permission = rule.getPermission();
2107
               pstmt.setInt(3, permission);
2108
               logMetacat.info("permission in accesstable: "
2109
                       + permission);
2110
               pstmt.setString(4, permType);
2111
               logMetacat.info(
2112
                       "Permtype in accesstable: " + permType);
2113
               // go through every principle in rule
2114
               Vector nameVector = rule.getPrincipal();
2115
               for (int j = 0; j < nameVector.size(); j++)
2116
               {
2117
                   String prName = (String) nameVector.elementAt(j);
2118
                   pstmt.setString(2, prName);
2119
                   logMetacat.info("Principal in accesstable: "
2120
                           + prName);
2121
                   logMetacat.debug("running sql: " + pstmt.toString());
2122
                   pstmt.execute();
2123
               }//for
2124
           }//for
2125
           pstmt.close();
2126
       }//try
2127
       catch (SQLException e)
2128
       {
2129
           throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
2130
                   + e.getMessage());
2131
       }//catch
2132
       finally
2133
       {
2134
           try
2135
           {
2136
               pstmt.close();
2137
           }
2138
           catch (SQLException ee)
2139
           {
2140
               throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
2141
                       + ee.getMessage());
2142
           }
2143
       }//finally
2144

    
2145
    }//writeGivenAccessRuleIntoDB
2146

    
2147

    
2148
    /* Delete from db all permission for resources related to @docid if any. */
2149
    private void deletePermissionsInAccessTableForDoc(String docid)
2150
            throws SAXException
2151
    {
2152
        Statement stmt = null;
2153
        try {
2154
            // delete all acl records for resources related to @aclid if any
2155
            stmt = connection.createStatement();
2156
            // Increase DBConnection usage count
2157
            connection.increaseUsageCount(1);
2158
            stmt.execute("DELETE FROM xml_access WHERE docid = '"
2159
                    + docid + "'");
2160

    
2161
        } catch (SQLException e) {
2162
            throw new SAXException(e.getMessage());
2163
        } finally {
2164
            try {
2165
                stmt.close();
2166
            } catch (SQLException ee) {
2167
                throw new SAXException(ee.getMessage());
2168
            }
2169
        }
2170
    }//deletePermissionsInAccessTable
2171

    
2172
    /* Delete access rules from xml_access for a subtee id */
2173
    private void deleteSubtreeAccessRule(String subtreeid) throws SAXException
2174
    {
2175
      Statement stmt = null;
2176
       try
2177
       {
2178
           stmt = connection.createStatement();
2179
           // Increase DBConnection usage count
2180
           connection.increaseUsageCount(1);
2181
           stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
2182
                   + docid + "' AND subtreeid ='" + subtreeid +"'");
2183
       }
2184
       catch (SQLException e)
2185
       {
2186
           throw new SAXException(e.getMessage());
2187
       }
2188
       finally
2189
       {
2190
           try
2191
           {
2192
               stmt.close();
2193
           }
2194
           catch (SQLException ee)
2195
           {
2196
               throw new SAXException(ee.getMessage());
2197
           }
2198
       }
2199

    
2200
    }
2201

    
2202
    private void deleteAllInlineDataAccessRules() throws SAXException
2203
    {
2204
      Statement stmt = null;
2205
       try
2206
       {
2207
           stmt = connection.createStatement();
2208
           // Increase DBConnection usage count
2209
           connection.increaseUsageCount(1);
2210
           stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
2211
                   + docid + "' AND subtreeid IS NOT NULL");
2212
       }
2213
       catch (SQLException e)
2214
       {
2215
           throw new SAXException(e.getMessage());
2216
       }
2217
       finally
2218
       {
2219
           try
2220
           {
2221
               stmt.close();
2222
           }
2223
           catch (SQLException ee)
2224
           {
2225
               throw new SAXException(ee.getMessage());
2226
           }
2227
       }
2228

    
2229
    }
2230

    
2231
    /*
2232
     * In order to make sure only usr has "all" permission can update access
2233
     * subtree in eml document we need to keep access subtree info in
2234
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
2235
     */
2236
    private void writeAccessSubTreeIntoDB(AccessSection accessSection)
2237
                                          throws SAXException
2238
    {
2239
        if (accessSection == null)
2240
        {
2241

    
2242
          logMetacat.info("Access object is null and tried to write "+
2243
                                   "into access subtree table");
2244
          throw new SAXException("The access object is null to write access " +
2245
                                 "sbutree");
2246
        }
2247

    
2248
        String sql = null;
2249
        PreparedStatement pstmt = null;
2250
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
2251
                + "subtreeid, startnodeid, endnodeid) VALUES "
2252
                + " (?, ?, ?, ?, ?, ?)";
2253
        try
2254
        {
2255

    
2256
            pstmt = connection.prepareStatement(sql);
2257
            // Increase DBConnection usage count
2258
            connection.increaseUsageCount(1);
2259
            String level = accessSection.getControlLevel();
2260
            long startNodeId = -1;
2261
            if (level != null && level.equals(DATAACCESSLEVEL))
2262
            {
2263
              // for additional access module the start node id should be
2264
              // descirbes element id
2265
              startNodeId = accessSection.getStartedDescribesNodeId();
2266
              // if in additional access, there is not describes element,
2267
              // in this senario, describesNodeId will be -1. Then we should
2268
              // the start access element id
2269
              if (startNodeId == -1)
2270
              {
2271
                startNodeId = accessSection.getStartNodeId();
2272
              }
2273
            }
2274
            else
2275
            {
2276
                startNodeId = accessSection.getStartNodeId();
2277
            }
2278

    
2279
            long endNodeId = accessSection.getEndNodeId();
2280
            String sectionId = accessSection.getSubTreeId();
2281

    
2282
            if (startNodeId ==-1 || endNodeId == -1)
2283
            {
2284
              throw new SAXException("Don't find start node or end node id " +
2285
                                      "for the access subtee");
2286

    
2287
            }
2288

    
2289
            // Bind the values to the query
2290
            pstmt.setString(1, docid);
2291
            logMetacat.info("Docid in access-subtreetable: " + docid);
2292
            pstmt.setInt(2, (new Integer(revision)).intValue());
2293
            logMetacat.info("rev in accesssubtreetable: " + revision);
2294
            pstmt.setString(3, level);
2295
            logMetacat.info("contorl level in access-subtree table: "
2296
                    + level);
2297
            pstmt.setString(4, sectionId);
2298
            logMetacat.info("Subtree id in access-subtree table: "
2299
                    + sectionId);
2300
            pstmt.setLong(5, startNodeId);
2301
            logMetacat.info("Start node id is: " + startNodeId);
2302
            pstmt.setLong(6, endNodeId);
2303
            logMetacat.info("End node id is: " + endNodeId);
2304
            logMetacat.debug("Eml200SAXHandler.writeAccessSubTreeIntoDB - executing SQL: " + pstmt.toString());
2305
            pstmt.execute();
2306
            pstmt.close();
2307
        }//try
2308
        catch (SQLException e)
2309
        {
2310
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
2311
                    + e.getMessage());
2312
        }//catch
2313
        finally
2314
        {
2315
            try
2316
            {
2317
                pstmt.close();
2318
            }
2319
            catch (SQLException ee)
2320
            {
2321
                throw new SAXException(
2322
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
2323
                                + ee.getMessage());
2324
            }
2325
        }//finally
2326

    
2327
    }//writeAccessSubtreeIntoDB
2328

    
2329
    /* Delete every access subtree record from xml_accesssubtree. */
2330
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
2331
    {
2332
        Statement stmt = null;
2333
        try {
2334
            // delete all acl records for resources related to @aclid if any
2335
            stmt = connection.createStatement();
2336
            // Increase DBConnection usage count
2337
            connection.increaseUsageCount(1);                   
2338
            logMetacat.debug("running sql: DELETE FROM xml_accesssubtree WHERE docid = '"
2339
                    + docId + "'");
2340
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
2341
                    + docId + "'");
2342

    
2343
        } catch (SQLException e) {
2344
            throw new SAXException(e.getMessage());
2345
        } finally {
2346
            try {
2347
                stmt.close();
2348
            } catch (SQLException ee) {
2349
                throw new SAXException(ee.getMessage());
2350
            }
2351
        }
2352
    }//deleteAccessSubTreeRecord
2353

    
2354
    // open a file writer for writing inline data to file
2355
    private FileWriter createInlineDataFileWriter(String fileName)
2356
            throws SAXException
2357
    {
2358
        FileWriter writer = null;
2359
        String path;
2360
        try {
2361
        	 path = PropertyService.getProperty("application.inlinedatafilepath");
2362
        } catch (PropertyNotFoundException pnfe) {
2363
            throw new SAXException(pnfe.getMessage());
2364
        }
2365
        /*
2366
         * File inlineDataDirectory = new File(path);
2367
         */
2368
        String newFile = path + "/" + fileName;
2369
        logMetacat.info("inline file name: " + newFile);
2370
        try {
2371
            // true means append
2372
            writer = new FileWriter(newFile, true);
2373
        } catch (IOException ioe) {
2374
            throw new SAXException(ioe.getMessage());
2375
        }
2376
        return writer;
2377
    }
2378

    
2379
    // write inline data into file system and return file name(without path)
2380
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2381
            throws SAXException
2382
    {
2383
        try {
2384
            writer.write(data.toString());
2385
            writer.flush();
2386
        } catch (Exception e) {
2387
            throw new SAXException(e.getMessage());
2388
        }
2389
    }
2390

    
2391

    
2392

    
2393
    /*
2394
     * In eml2, the inline data wouldn't store in db, it store in file system
2395
     * The db stores file name(without path). We got the old file name from db
2396
     * and compare to the new in line data file
2397
     */
2398
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2399
            throws McdbException
2400
    {
2401
        // this method need to be testing
2402
        boolean same = true;
2403
        String data = null;
2404
        try {
2405
        	String path = PropertyService.getProperty("application.inlinedatafilepath");
2406
			// the new file name will look like path/docid.rev.2
2407
			File inlineDataDirectory = new File(path);
2408
			File oldDataFile = new File(inlineDataDirectory, oldFileName);
2409
			File newDataFile = new File(inlineDataDirectory, newFileName);
2410

    
2411
            FileReader oldFileReader = new FileReader(oldDataFile);
2412
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2413
            FileReader newFileReader = new FileReader(newDataFile);
2414
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2415
            // read first line of data
2416
            String oldString = oldStringReader.readLine();
2417
            String newString = newStringReader.readLine();
2418

    
2419
            // at the end oldstring will be null
2420
            while (oldString != null) {
2421
                oldString = oldStringReader.readLine();
2422
                newString = newStringReader.readLine();
2423
                if (!oldString.equals(newString)) {
2424
                    same = false;
2425
                    break;
2426
                }
2427
            }
2428

    
2429
            // if oldString is null but newString is not null, they are same
2430
            if (same) {
2431
                if (newString != null) {
2432
                    same = false;
2433
                }
2434
            }
2435

    
2436
        } catch (Exception e) {
2437
            throw new McdbException(e.getMessage());
2438
        }
2439
        logMetacat.info("the inline data retrieve from file: " + data);
2440
        return same;
2441
    }
2442

    
2443
   /*
2444
	 * Copy a old line file to a new inline file
2445
	 */
2446
	public void copyInlineFile(String inlineDistributionId, String newFileName)
2447
			throws SAXException {
2448
		if (inlineDistributionId == null || newFileName == null) {
2449
			throw new SAXException("Could not copy inline file from old one to new "
2450
					+ "one!");
2451
		}
2452
		// get old file id from previousUnreadable data object
2453
		String oldInlineInternalFileName = (String) previousUnreadableInlineDataObjectHash
2454
				.get(inlineDistributionId);
2455

    
2456
		if (oldInlineInternalFileName == null
2457
				|| oldInlineInternalFileName.trim().equals("")) {
2458
			throw new SAXException("Could not copy inline file from old one to new "
2459
					+ "one because can't find old file name");
2460
		}
2461
		logMetacat.info("in handle inline data");
2462
		logMetacat.info("the inline data file name from xml_access is: "
2463
				+ oldInlineInternalFileName);
2464

    
2465
		FileReader oldFileReader = null;
2466
		FileWriter newFileWriter = null;
2467
		try {
2468
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2469
			// the new file name will look like path/docid.rev.2
2470
			File inlineDataDirectory = new File(path);
2471
			File oldDataFile = new File(inlineDataDirectory, oldInlineInternalFileName);
2472
			File newDataFile = new File(inlineDataDirectory, newFileName);
2473

    
2474
			oldFileReader = new FileReader(oldDataFile);
2475
			newFileWriter = new FileWriter(newDataFile);
2476
			char[] buf = new char[4 * 1024]; // 4K buffer
2477
			int b = oldFileReader.read(buf);
2478
			while (b != -1) {
2479
				newFileWriter.write(buf, 0, b);
2480
				b = oldFileReader.read(buf);
2481
			}
2482
		} catch (Exception e) {
2483
			throw new SAXException(e.getMessage());
2484
		} finally {
2485
			if (oldFileReader != null) {
2486
				try {
2487
					oldFileReader.close();
2488
				} catch (Exception ee) {
2489
					throw new SAXException(ee.getMessage());
2490
				}
2491

    
2492
			}
2493
			if (newFileWriter != null) {
2494
				try {
2495
					newFileWriter.close();
2496
				} catch (Exception ee) {
2497
					throw new SAXException(ee.getMessage());
2498
				}
2499

    
2500
			}
2501
		}
2502
	}
2503

    
2504

    
2505
    // if xml file failed to upload, we need to call this method to delete
2506
    // the inline data already in file system
2507
    public void deleteInlineFiles() throws SAXException
2508
    {
2509
        if (!inlineFileIDList.isEmpty()) {
2510
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2511
                String fileName = (String) inlineFileIDList.elementAt(i);
2512
                deleteInlineDataFile(fileName);
2513
            }
2514
        }
2515
    }
2516

    
2517
    /* delete the inline data file */
2518
    private void deleteInlineDataFile(String fileName) throws SAXException
2519
    {
2520
    	String path;
2521
    	try {
2522
    		path = PropertyService.getProperty("application.inlinedatafilepath");
2523
    	} catch (PropertyNotFoundException pnfe) {
2524
    		throw new SAXException ("Could not find inline data file path: " 
2525
    				+ pnfe.getMessage());
2526
    	}
2527
        File inlineDataDirectory = new File(path);
2528
        File newFile = new File(inlineDataDirectory, fileName);
2529
        newFile.delete();
2530

    
2531
    }
2532

    
2533
    /*
2534
	 * In eml2, the inline data wouldn't store in db, it store in file system
2535
	 * The db stores file name(without path).
2536
	 */
2537
	public static Reader readInlineDataFromFileSystem(String fileName)
2538
			throws McdbException {
2539
		// BufferedReader stringReader = null;
2540
		FileReader fileReader = null;
2541
		try {
2542
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2543
			// the new file name will look like path/docid.rev.2
2544
			File inlineDataDirectory = new File(path);
2545
			File dataFile = new File(inlineDataDirectory, fileName);
2546

    
2547
			fileReader = new FileReader(dataFile);
2548
			// stringReader = new BufferedReader(fileReader);
2549
		} catch (Exception e) {
2550
			throw new McdbException(e.getMessage());
2551
		}
2552
		// return stringReader;
2553
		return fileReader;
2554
	}
2555

    
2556
    /* Delete relations */
2557
    private void deleteRelations() throws SAXException
2558
    {
2559
        PreparedStatement pStmt = null;
2560
        String sql = "DELETE FROM xml_relation where docid =?";
2561
        try {
2562
            pStmt = connection.prepareStatement(sql);
2563
            //bind variable
2564
            pStmt.setString(1, docid);
2565
            //execute query
2566
            logMetacat.debug("Eml200SAXHandler.deleteRelations - executing SQL: " + pStmt.toString());
2567
            pStmt.execute();
2568
            pStmt.close();
2569
        }//try
2570
        catch (SQLException e) {
2571
            throw new SAXException("EMLSAXHandler.deleteRelations(): "
2572
                    + e.getMessage());
2573
        }//catch
2574
        finally {
2575
            try {
2576
                pStmt.close();
2577
            }//try
2578
            catch (SQLException ee) {
2579
                throw new SAXException("EMLSAXHandler.deleteRelations: "
2580
                        + ee.getMessage());
2581
            }//catch
2582
        }//finally
2583
    }
2584

    
2585
    /* Write an online data file id into xml_relation table. The dataId shouldnot
2586
     * have the revision
2587
     */
2588
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2589
            throws SAXException
2590
    {
2591
        PreparedStatement pStmt = null;
2592
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2593
                + "relationship, object) values (?, ?, ?, ?, ?)";
2594
        try {
2595
            pStmt = connection.prepareStatement(sql);
2596
            //bind variable
2597
            pStmt.setString(1, docid);
2598
            pStmt.setString(2, doctype);
2599
            pStmt.setString(3, docid);
2600
            pStmt.setString(4, RELATION);
2601
            pStmt.setString(5, dataId);
2602
            //execute query
2603
            logMetacat.debug("Eml200SAXHandler.writeOnlineDataFileIdIntoRelationTable - executing SQL: " + pStmt.toString());
2604
            pStmt.execute();
2605
            pStmt.close();
2606
        }//try
2607
        catch (SQLException e) {
2608
            throw new SAXException(
2609
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2610
                            + e.getMessage());
2611
        }//catch
2612
        finally {
2613
            try {
2614
                pStmt.close();
2615
            }//try
2616
            catch (SQLException ee) {
2617
                throw new SAXException(
2618
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2619
                                + ee.getMessage());
2620
            }//catch
2621
        }//finally
2622

    
2623
    }//writeOnlineDataFileIdIntoRelationTable
2624

    
2625
    /*
2626
     * This method will handle data file in online url. If the data file is in
2627
     * ecogrid protocol, then the datafile identifier(without rev) be returned.
2628
     * otherwise, null will be returned.
2629
     * If the data file doesn't exsit in xml_documents or
2630
     * xml_revision table, or the user has all permission to the data file if
2631
     * the docid already existed, the data file id (without rev)will be returned
2632
     * NEED to do:
2633
     * We should also need to implement http and ftp. Those
2634
     * external files should be download and assign a data file id to it.
2635
     */
2636
    private String handleOnlineUrlDataFile(String url) throws SAXException
2637
    {
2638
      logMetacat.warn("The url is "+ url);
2639
      String docid = null;
2640
      // if the url is not a ecogrid protocol, null will be getten
2641
      String accessionNumber =
2642
    	  DocumentUtil.getAccessionNumberFromEcogridIdentifier(url);
2643
      if (accessionNumber != null)
2644
      {
2645
        // handle ecogrid protocol
2646
        // get rid of revision number to get the docid.
2647
        docid = DocumentUtil.getDocIdFromAccessionNumber(accessionNumber);
2648
        onlineDataFileIdInRelationVector.add(docid);
2649
        try
2650
        {
2651

    
2652
          if (!AccessionNumber.accNumberUsed(docid))
2653
          {
2654
            return docid;
2655
          }
2656
          PermissionController controller = new
2657
              PermissionController(accessionNumber);
2658
          if (controller.hasPermission(
2659
              user, groups, AccessControlInterface.ALLSTRING))
2660
          {
2661
            return docid;
2662
          }
2663
          else
2664
          {
2665
            throw new SAXException("User: " + user + " does not have permission to update " +
2666
                  "access rules for data file "+ docid);
2667
          }
2668
        }//try
2669
        catch(Exception e)
2670
        {
2671
          logMetacat.error("Error in " +
2672
                                "Eml200SAXHanlder.handleOnlineUrlDataFile is " +
2673
                                 e.getMessage());
2674
          throw new SAXException(e.getMessage());
2675
        }
2676
      }
2677
      return docid;
2678
    }
2679

    
2680
    private void compareElementNameSpaceAttributes(Stack unchangableNodeStack,
2681
            Hashtable nameSpaces, Attributes attributes, String localName,
2682
            String error) throws SAXException
2683
    {
2684
        //Get element subtree node stack (element node)
2685
        NodeRecord elementNode = null;
2686
        try {
2687
            elementNode = (NodeRecord) unchangableNodeStack.pop();
2688
        } catch (EmptyStackException ee) {
2689
            logMetacat.error("Node stack is empty for element data");
2690
            throw new SAXException(error);
2691
        }
2692
        logMetacat.info("current node type from xml is ELEMENT");
2693
        logMetacat.info("node type from stack: "
2694
                + elementNode.getNodeType());
2695
        logMetacat.info("node name from xml document: " + localName);
2696
        logMetacat.info("node name from stack: "
2697
                + elementNode.getNodeName());
2698
        logMetacat.info("node data from stack: "
2699
                + elementNode.getNodeData());
2700
        logMetacat.info("node id is: " + elementNode.getNodeId());
2701
        // if this node is not element or local name not equal or name space
2702
        // not
2703
        // equals, throw an exception
2704
        if (!elementNode.getNodeType().equals("ELEMENT")
2705
                || !localName.equals(elementNode.getNodeName()))
2706
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
2707
        {
2708
            logMetacat.info("Inconsistence happend: ");
2709
            logMetacat.info("current node type from xml is ELEMENT");
2710
            logMetacat.info("node type from stack: "
2711
                    + elementNode.getNodeType());
2712
            logMetacat.info("node name from xml document: "
2713
                    + localName);
2714
            logMetacat.info("node name from stack: "
2715
                    + elementNode.getNodeName());
2716
            logMetacat.info("node data from stack: "
2717
                    + elementNode.getNodeData());
2718
            logMetacat.info("node id is: " + elementNode.getNodeId());
2719
            throw new SAXException(error);
2720
        }
2721

    
2722
        //compare namespace
2723
        Enumeration nameEn = nameSpaces.keys();
2724
        while (nameEn.hasMoreElements()) {
2725
            //Get namespacke node stack (element node)
2726
            NodeRecord nameNode = null;
2727
            try {
2728
                nameNode = (NodeRecord) unchangableNodeStack.pop();
2729
            } catch (EmptyStackException ee) {
2730
                logMetacat.error(
2731
                        "Node stack is empty for namespace data");
2732
                throw new SAXException(error);
2733
            }
2734

    
2735
            String prefixName = (String) nameEn.nextElement();
2736
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
2737
            if (!nameNode.getNodeType().equals("NAMESPACE")
2738
                    || !prefixName.equals(nameNode.getNodeName())
2739
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
2740
                logMetacat.info("Inconsistence happend: ");
2741
                logMetacat.info(
2742
                        "current node type from xml is NAMESPACE");
2743
                logMetacat.info("node type from stack: "
2744
                        + nameNode.getNodeType());
2745
                logMetacat.info("current node name from xml is: "
2746
                        + prefixName);
2747
                logMetacat.info("node name from stack: "
2748
                        + nameNode.getNodeName());
2749
                logMetacat.info("current node data from xml is: "
2750
                        + nameSpaceUri);
2751
                logMetacat.info("node data from stack: "
2752
                        + nameNode.getNodeData());
2753
                logMetacat.info("node id is: " + nameNode.getNodeId());
2754
                throw new SAXException(error);
2755
            }
2756

    
2757
        }//while
2758

    
2759
        //compare attributes
2760
        for (int i = 0; i < attributes.getLength(); i++) {
2761
            NodeRecord attriNode = null;
2762
            try {
2763
                attriNode = (NodeRecord) unchangableNodeStack.pop();
2764

    
2765
            } catch (EmptyStackException ee) {
2766
                logMetacat.error(
2767
                        "Node stack is empty for attribute data");
2768
                throw new SAXException(error);
2769
            }
2770
            String attributeName = attributes.getQName(i);
2771
            String attributeValue = attributes.getValue(i);
2772
            logMetacat.info(
2773
                    "current node type from xml is ATTRIBUTE ");
2774
            logMetacat.info("node type from stack: "
2775
                    + attriNode.getNodeType());
2776
            logMetacat.info("current node name from xml is: "
2777
                    + attributeName);
2778
            logMetacat.info("node name from stack: "
2779
                    + attriNode.getNodeName());
2780
            logMetacat.info("current node data from xml is: "
2781
                    + attributeValue);
2782
            logMetacat.info("node data from stack: "
2783
                    + attriNode.getNodeData());
2784
            logMetacat.info("node id  is: " + attriNode.getNodeId());
2785

    
2786
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
2787
                    || !attributeName.equals(attriNode.getNodeName())
2788
                    || !attributeValue.equals(attriNode.getNodeData())) {
2789
                logMetacat.info("Inconsistence happend: ");
2790
                logMetacat.info(
2791
                        "current node type from xml is ATTRIBUTE ");
2792
                logMetacat.info("node type from stack: "
2793
                        + attriNode.getNodeType());
2794
                logMetacat.info("current node name from xml is: "
2795
                        + attributeName);
2796
                logMetacat.info("node name from stack: "
2797
                        + attriNode.getNodeName());
2798
                logMetacat.info("current node data from xml is: "
2799
                        + attributeValue);
2800
                logMetacat.info("node data from stack: "
2801
                        + attriNode.getNodeData());
2802
                logMetacat.info("node is: " + attriNode.getNodeId());
2803
                throw new SAXException(error);
2804
            }
2805
        }//for
2806

    
2807
    }
2808

    
2809
    /* mehtod to compare current text node and node in db */
2810
    private void compareTextNode(Stack nodeStack, StringBuffer text,
2811
            String error) throws SAXException
2812
    {
2813
        NodeRecord node = null;
2814
        //get node from current stack
2815
        try {
2816
            node = (NodeRecord) nodeStack.pop();
2817
        } catch (EmptyStackException ee) {
2818
            logMetacat.error(
2819
                    "Node stack is empty for text data in startElement");
2820
            throw new SAXException(error);
2821
        }
2822
        logMetacat.info(
2823
                "current node type from xml is TEXT in start element");
2824
        logMetacat.info("node type from stack: " + node.getNodeType());
2825
        logMetacat.info("current node data from xml is: "
2826
                + text.toString());
2827
        logMetacat.info("node data from stack: " + node.getNodeData());
2828
        logMetacat.info("node name from stack: " + node.getNodeName());
2829
        logMetacat.info("node is: " + node.getNodeId());
2830
        if (!node.getNodeType().equals("TEXT")
2831
                || !(text.toString()).equals(node.getNodeData())) {
2832
            logMetacat.info("Inconsistence happend: ");
2833
            logMetacat.info(
2834
                    "current node type from xml is TEXT in start element");
2835
            logMetacat.info("node type from stack: "
2836
                    + node.getNodeType());
2837
            logMetacat.info("current node data from xml is: "
2838
                    + text.toString());
2839
            logMetacat.info("node data from stack: "
2840
                    + node.getNodeData());
2841
            logMetacat.info("node name from stack: "
2842
                    + node.getNodeName());
2843
            logMetacat.info("node is: " + node.getNodeId());
2844
            throw new SAXException(error);
2845
        }//if
2846
    }
2847

    
2848
    /* Comparet comment from xml and db */
2849
    private void compareCommentNode(Stack nodeStack, String string, String error)
2850
            throws SAXException
2851
    {
2852
        NodeRecord node = null;
2853
        try {
2854
            node = (NodeRecord) nodeStack.pop();
2855
        } catch (EmptyStackException ee) {
2856
            logMetacat.error("the stack is empty for comment data");
2857
            throw new SAXException(error);
2858
        }
2859
        logMetacat.info("current node type from xml is COMMENT");
2860
        logMetacat.info("node type from stack: " + node.getNodeType());
2861
        logMetacat.info("current node data from xml is: " + string);
2862
        logMetacat.info("node data from stack: " + node.getNodeData());
2863
        logMetacat.info("node is from stack: " + node.getNodeId());
2864
        // if not consistent terminate program and throw a exception
2865
        if (!node.getNodeType().equals("COMMENT")
2866
                || !string.equals(node.getNodeData())) {
2867
            logMetacat.info("Inconsistence happend: ");
2868
            logMetacat.info("current node type from xml is COMMENT");
2869
            logMetacat.info("node type from stack: "
2870
                    + node.getNodeType());
2871
            logMetacat.info(
2872
                    "current node data from xml is: " + string);
2873
            logMetacat.info("node data from stack: "
2874
                    + node.getNodeData());
2875
            logMetacat.info("node is from stack: " + node.getNodeId());
2876
            throw new SAXException(error);
2877
        }//if
2878
    }
2879

    
2880
    /* Compare whitespace from xml and db */
2881
   private void compareWhiteSpace(Stack nodeStack, String string, String error)
2882
           throws SAXException
2883
   {
2884
       NodeRecord node = null;
2885
       try {
2886
           node = (NodeRecord) nodeStack.pop();
2887
       } catch (EmptyStackException ee) {
2888
           logMetacat.error("the stack is empty for whitespace data");
2889
           throw new SAXException(error);
2890
       }
2891
       if (!node.getNodeType().equals("TEXT")
2892
               || !string.equals(node.getNodeData())) {
2893
           logMetacat.info("Inconsistence happend: ");
2894
           logMetacat.info(
2895
                   "current node type from xml is WHITESPACE TEXT");
2896
           logMetacat.info("node type from stack: "
2897
                   + node.getNodeType());
2898
           logMetacat.info(
2899
                   "current node data from xml is: " + string);
2900
           logMetacat.info("node data from stack: "
2901
                   + node.getNodeData());
2902
           logMetacat.info("node is from stack: " + node.getNodeId());
2903
           throw new SAXException(error);
2904
       }//if
2905
   }
2906

    
2907

    
2908

    
2909
}
(32-32/61)