Project

General

Profile

1 2161 tao
/**
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 2245 sgarg
 *    Authors: Jing Tao
8 2161 tao
 *
9
 *   '$Author$'
10
 *     '$Date$'
11
 * '$Revision$'
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 2245 sgarg
import java.io.BufferedWriter;
32 2161 tao
import java.io.File;
33
import java.io.FileReader;
34
import java.io.FileWriter;
35
import java.io.IOException;
36
import java.io.Reader;
37
import java.sql.PreparedStatement;
38
import java.sql.ResultSet;
39
import java.sql.SQLException;
40
import java.sql.Statement;
41
import java.util.EmptyStackException;
42
import java.util.Enumeration;
43
import java.util.Hashtable;
44
import java.util.Stack;
45
import java.util.Vector;
46
47 2663 sgarg
import org.apache.log4j.Logger;
48 2161 tao
import org.xml.sax.Attributes;
49
import org.xml.sax.SAXException;
50
51 5090 daigle
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
52
import edu.ucsb.nceas.metacat.accesscontrol.AccessRule;
53
import edu.ucsb.nceas.metacat.accesscontrol.AccessSection;
54 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
55
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
56 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
57 4589 daigle
import edu.ucsb.nceas.metacat.util.AuthUtil;
58 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
59 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
60 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
61
62 2161 tao
/**
63
 * A database aware Class implementing callback bethods for the SAX parser to
64
 * call when processing the XML stream and generating events
65 2245 sgarg
 * Here is the rules for user which has write permission in top level access
66
 * rules(he can update metadata but can't update access module) try to update
67
 * a document:
68
 * 1. Checking access part (both in top level and addtional level, node by node)
69
 *    If something was modified, reject the document. Note: for additional part
70
 *    The access subtree startnode starts at "<describ>" rather than <access>.
71
 *    This is because make sure ids wouldn't be mess up by user.
72
 * 2. Checking ids in additional access part, if they points a distribution
73
 *    module with online or inline. If some ids don't, reject the documents.
74
 * 3. For inline distribution:
75
 *    If user can't read the inline data, the empty string in inline element
76
 *    will be send to user if he read this eml document(user has read access
77
 *    at top level - metadata, but user couldn't read inline data).
78
 *    Here is some intrested senario: If user does have read and write
79
 *    permission in top level access rules(for metadata)
80
 *    but 1) user doesn't have read and write permission in inline data block,
81
 *    so if user update the document with some inline data rather than
82
 *    empty string in same inline data block(same distribution inline id),
83
 *    this means user updated the inline data. So the document should be
84
 *    rejected.
85
 *    2) user doesn't have read permssion, but has write premission in
86
 *    inline data block. If user send back inline data block with empty
87
 *    string, we will think user doesn't update inline data and we will
88
 *    copy old inline data back to the new one. If user send something
89
 *    else, we will overwrite the old inline data by new one.
90
 * 4. For online distribution:
91
 *    It is easy than inline distribution. When the user try to change a external
92
 *    document id, we will checking if the user have "all" permission to it.
93
 *    If don't have, reject the document. If have, delete the old rules and apply
94
 *    The new rules.
95
 *
96
 *
97
 * Here is some info about addtional access rules ( data object rules):
98
 *  The data access rules format looks like:
99
 *  <additionalMetadata>
100
 *    <describes>100</describes>
101
 *    <describes>300</describes>
102
 *    <access>rulesone</access>
103
 *  </additionalMetadata>
104
 *  <additionalMetadata>
105
 *    <describes>200</describes>
106
 *    <access>rulesthree</access>
107
 *  </additionalMetadata>
108
 *  Because eml additionalMetadata is (describes+, any) and any ocurrence is 1.
109
 *  So following xml will be rejected by xerces.
110
 *  <additionalMetadata>
111
 *    <describes>100</describes>
112
 *    <describes>300</describes>
113
 *    <other>....</other>
114
 *    <access>rulesone</access>
115
 *  </additionalMetadata>
116 2161 tao
 */
117
public class Eml200SAXHandler extends DBSAXHandler implements
118
        AccessControlInterface
119
{
120
    private boolean processTopLeverAccess = false;
121
122 2188 tao
    // now additionalAccess will be explained as distribution access control
123
    // - data file
124 2161 tao
    private boolean processAdditionalAccess = false;
125
126
    private boolean processOtherAccess = false;
127
128
    private AccessSection accessObject = null;
129
130
    private AccessRule accessRule = null;
131
132 2245 sgarg
    private Vector describesId = new Vector(); // store the ids in
133
                                               //additionalmetadata/describes
134 2161 tao
135 2245 sgarg
    //store all distribution element id for online url. key is the distribution
136
    // id and  data  is url
137
    private Hashtable onlineURLDistributionIdList = new Hashtable();
138
    // distribution/oneline/url will store this vector if distribution doesn't
139
    // have a id.
140 4501 daigle
    private Vector onlineURLDistributionListWithoutId = new Vector();
141 2161 tao
142 2245 sgarg
    //store all distribution element id for online other distribution, such as
143
    // connection or connectiondefination. key is the distribution id
144
    // and  data  is distribution id
145
    private Hashtable onlineOtherDistributionIdList = new Hashtable();
146 2161 tao
147 2245 sgarg
    //store all distribution element id for inline data.
148
    // key is the distribution id, data is the internal inline id
149
    private Hashtable inlineDistributionIdList = new Hashtable();
150 2161 tao
151 2245 sgarg
    //store all distribution element id for off line data.
152
    // key is the distribution id, data is the id too.
153
    private Hashtable offlineDistributionIdList = new Hashtable();
154 2161 tao
155 2245 sgarg
    // a hash to stored all distribution id, both key and value are id itself
156
    private Hashtable distributionAllIdList = new Hashtable();
157 2161 tao
158 2245 sgarg
    // temporarily store distribution id
159
    private String distributionId = null;
160 2161 tao
161 2245 sgarg
    // flag to indicate to handle distrubiton
162
    private boolean proccessDistribution = false;
163 2161 tao
164 2245 sgarg
    // a hash table to stored the distribution which is a reference and this
165
    // distribution has a id too. The key is itself id of this distribution,
166
    // the value is the referenced id.
167
    // So, we only stored the format like this:
168
    // <distribution id ="100"><reference>300</reference></distribution>
169
    // the reason is:
170
    // if not id in distribution, then the distribution couldn't be added
171
    // to additional access module. The distribution block which was referenced
172
    // id (300) will be stored in above distribution lists.
173
    private Hashtable distributionReferenceList = new Hashtable();
174 2161 tao
175 2245 sgarg
    private boolean needCheckingAccessModule = false;
176 2161 tao
177 2245 sgarg
    private AccessSection unChangebleTopAccessSubTree = null;
178 2161 tao
179 2245 sgarg
    private Vector unChangebleAdditionalAccessSubTreeVector = new Vector();
180 2161 tao
181 2245 sgarg
    private Hashtable unChangebleReferencedAccessSubTreeHash = new Hashtable();
182 2161 tao
183 2245 sgarg
    private AccessSection topAccessSection;
184 2161 tao
185 2245 sgarg
    private Vector addtionalAccessVector = new Vector();
186 2161 tao
187 2245 sgarg
    // key is subtree id and value is accessSection object
188
    private Hashtable possibleReferencedAccessHash = new Hashtable();
189 2161 tao
190
    // we need an another stack to store the access node which we pull out just
191
    // from xml. If a reference happend, we can use the stack the compare nodes
192
    private Stack storedAccessNodeStack = new Stack();
193
194
    // vector stored the data file id which will be write into relation table
195 2165 tao
    private Vector onlineDataFileIdInRelationVector = new Vector();
196 2161 tao
197
    // Indicator of inline data
198
    private boolean handleInlineData = false;
199
200
    private Hashtable inlineDataNameSpace = null;
201
202
    private FileWriter inlineDataFileWriter = null;
203
204
    private String inlineDataFileName = null;
205
206
    private int inLineDataIndex = 0;
207
208
    private Vector inlineFileIDList = new Vector();
209
210 2245 sgarg
    private boolean inAddtionalMetaData = false;
211 2165 tao
212 2245 sgarg
    //user has unwritable inline data object when it updates a document
213
    private boolean unWritableInlineDataObject = false;
214
    //user has unreadable inline data when it updates a dcoument
215
    private boolean unReadableInlineDataObject = false;
216
217
    // the hashtable contains the info from xml_access table which
218
    // inline data the user can't read when user update a document.
219
    // The key in hashtable is subtree id and data is the inline data internal
220
    // file name.
221
222
    private Hashtable previousUnreadableInlineDataObjectHash = new Hashtable();
223
224
    // the hashtable contains the info from xml_access table which
225
    // inline data the user can't write when user update a document.
226
    // The key in hashtable is subtree id and data is the inline data internal
227
    // file name.
228
    private Hashtable previousUnwritableInlineDataObjectHash = new Hashtable();
229
230
    private Hashtable accessSubTreeAlreadyWriteDBList = new Hashtable();
231
232
    //This hashtable will stored the id which already has additional access
233
    // control. So the top level access control will ignore them.
234
    private Hashtable onlineURLIdHasAddtionalAccess   = new Hashtable();
235
236
    // additional access module will be in additionalMetadata part. Its format
237
    // look like
238
    //<additionalMetadata>
239
    //   <describes>100</describes>
240
    //   <describes>300</describes>
241
    //   <access>rulesone</access>
242
    //</additionalMetadata>
243
    // If user couldn't have all permission to update access rules, he/she could
244
    // not update access module, but also couldn't update "describes".
245
    // So the start node id for additional access section is the first describes
246
    // element
247
    private boolean firstDescribesInAdditionalMetadata = true;
248
    private long    firstDescribesNodeId               = -1;
249
250
    private int numberOfHitUnWritableInlineData = 0;
251
252 2161 tao
    // Constant
253
    private static final String EML = "eml";
254
255
    private static final String DESCRIBES = "describes";
256
257
    private static final String ADDITIONALMETADATA = "additionalMetadata";
258
259
    private static final String ORDER = "order";
260
261
    private static final String ID = "id";
262
263
    private static final String REFERENCES = "references";
264
265
    public static final String INLINE = "inline";
266
267
    private static final String ONLINE = "online";
268
269 2245 sgarg
    private static final String OFFLINE = "offline";
270
271
    private static final String CONNECTION = "connection";
272
273
    private static final String CONNECTIONDEFINITION = "connectionDefinition";
274
275 2161 tao
    private static final String URL = "url";
276
277 4471 daigle
    private static final String PERMISSIONERROR = "User tried to update a subtree "
278
        + "when they don't have write permission!";
279 2161 tao
280 4471 daigle
    private static final String UPDATEACCESSERROR = "User tried to update an "
281
        + "access module when they don't have \"ALL\" permission!";
282 2161 tao
283 2245 sgarg
    public static final String TOPLEVEL = "top";
284 2161 tao
285 2245 sgarg
    public static final String DATAACCESSLEVEL = "dataAccess";
286 2161 tao
287 2245 sgarg
    // this level is for the access module which is not in top or additional
288
    // place, but it was referenced by top or additional
289
    private static final String REFERENCEDLEVEL = "referenced";
290
291 2161 tao
    private static final String RELATION = "Provides info for";
292
293 2245 sgarg
    private static final String DISTRIBUTION = "distribution";
294
295 2663 sgarg
    private Logger logMetacat = Logger.getLogger(Eml200SAXHandler.class);
296
297 2161 tao
    /**
298
     * Construct an instance of the handler class In this constructor, user can
299
     * specify the version need to upadate
300
     *
301
     * @param conn the JDBC connection to which information is written
302
     * @param action - "INSERT" or "UPDATE"
303
     * @param docid to be inserted or updated into JDBC connection
304
     * @param revision, the user specified the revision need to be update
305
     * @param user the user connected to MetaCat servlet and owns the document
306
     * @param groups the groups to which user belongs
307
     * @param pub flag for public "read" access on document
308
     * @param serverCode the serverid from xml_replication on which this
309
     *            document resides.
310
     *
311
     */
312
    public Eml200SAXHandler(DBConnection conn, String action, String docid,
313
            String revision, String user, String[] groups, String pub,
314 2623 tao
            int serverCode, String createDate, String updateDate) throws SAXException
315 2161 tao
    {
316 2623 tao
        super(conn, action, docid, revision, user, groups, pub,
317
                serverCode, createDate, updateDate);
318 2161 tao
        // Get the unchangable subtrees (user doesn't have write permission)
319 2245 sgarg
        try
320
        {
321 2161 tao
            PermissionController control = new PermissionController(docid
322 4212 daigle
                    + PropertyService.getProperty("document.accNumSeparator") + revision);
323 2161 tao
            //unChangableSubTreeHash = getUnchangableSubTree(control, user,
324
            // groups);
325
326
            //If the action is update and user doesn't have "ALL" permission
327
            // we need to check if user update access subtree
328 2245 sgarg
            if (action != null && action.equals("UPDATE")
329 2161 tao
                    && !control.hasPermission(user, groups,
330 3004 sgarg
                            AccessControlInterface.ALLSTRING)
331 4589 daigle
                            && !AuthUtil.isAdministrator(user, groups))
332 2245 sgarg
            {
333 2161 tao
                needCheckingAccessModule = true;
334 2245 sgarg
                unChangebleTopAccessSubTree = getTopAccessSubTreeFromDB();
335
                unChangebleAdditionalAccessSubTreeVector =
336
                                         getAdditionalAccessSubTreeListFromDB();
337
                unChangebleReferencedAccessSubTreeHash =
338
                                         getReferencedAccessSubTreeListFromDB();
339 2161 tao
            }
340 2245 sgarg
341
            //Here is for  data object checking.
342
            if (action != null && action.equals("UPDATE"))
343
            {
344
              //info about inline data object which user doesn't have read
345
              //permission the info come from xml_access table
346
              previousUnreadableInlineDataObjectHash = PermissionController.
347 2292 sgarg
                            getUnReadableInlineDataIdList(docid, user,
348
                                                          groups, true);
349 2245 sgarg
350
              //info about data object which user doesn't have write permission
351
              // the info come from xml_accesss table
352
              previousUnwritableInlineDataObjectHash = PermissionController.
353 2292 sgarg
                            getUnWritableInlineDataIdList(docid, user,
354
                                                          groups, true);
355 2245 sgarg
356
            }
357
358
359
        }
360
        catch (Exception e)
361
        {
362 4661 daigle
            logMetacat.error("error in Eml200SAXHandler is " + e.getMessage());
363 2161 tao
            throw new SAXException(e.getMessage());
364
        }
365
    }
366
367 2245 sgarg
    /*
368
     * Get the top level access subtree info from xml_accesssubtree table.
369
     * If no top access subtree found, null will be return.
370
     */
371
     private AccessSection getTopAccessSubTreeFromDB()
372
                                                       throws SAXException
373
     {
374
       AccessSection topAccess = null;
375
       PreparedStatement pstmt = null;
376
       ResultSet rs = null;
377
       String sql = "SELECT subtreeid, startnodeid, endnodeid "
378
                + "FROM xml_accesssubtree WHERE docid like ? "
379
                + "AND controllevel like ?";
380 2161 tao
381
382 2245 sgarg
       try
383
       {
384
            pstmt = connection.prepareStatement(sql);
385
            // Increase DBConnection usage count
386
            connection.increaseUsageCount(1);
387
            // Bind the values to the query
388
            pstmt.setString(1, docid);
389
            pstmt.setString(2, TOPLEVEL);
390
            pstmt.execute();
391 2161 tao
392 2245 sgarg
            // 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 2262 sgarg
                topAccess = new AccessSection();
401
                topAccess.setControlLevel(TOPLEVEL);
402
                topAccess.setDocId(docid);
403
                topAccess.setSubTreeId(sectionId);
404
                topAccess.setStartNodeId(startNodeId);
405
                topAccess.setEndNodeId(endNodeId);
406 2245 sgarg
            }
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 2161 tao
430 2245 sgarg
     }
431 2161 tao
432
    /*
433
     * Get the subtree node info from xml_accesssubtree table
434
     */
435 2245 sgarg
    private Vector getAdditionalAccessSubTreeListFromDB() throws Exception
436 2161 tao
    {
437
        Vector result = new Vector();
438
        PreparedStatement pstmt = null;
439
        ResultSet rs = null;
440 2245 sgarg
        String sql = "SELECT subtreeid, startnodeid, endnodeid "
441 2161 tao
                + "FROM xml_accesssubtree WHERE docid like ? "
442 2245 sgarg
                + "AND controllevel like ? "
443 2161 tao
                + "ORDER BY startnodeid ASC";
444
445 2245 sgarg
        try
446
        {
447 2161 tao
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 2245 sgarg
            pstmt.setString(2, DATAACCESSLEVEL);
454 2161 tao
            pstmt.execute();
455
456
            // Get result set
457
            rs = pstmt.getResultSet();
458 2245 sgarg
            while (rs.next())
459
            {
460
                String sectionId = rs.getString(1);
461
                long startNodeId = rs.getLong(2);
462
                long endNodeId = rs.getLong(3);
463 2161 tao
                // create a new access section
464
                AccessSection accessObj = new AccessSection();
465 2245 sgarg
                accessObj.setControlLevel(DATAACCESSLEVEL);
466 2161 tao
                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 2245 sgarg
473 2161 tao
            }
474
            pstmt.close();
475
        }//try
476 2245 sgarg
        catch (SQLException e)
477
        {
478 2161 tao
            throw new SAXException(
479 2245 sgarg
                    "EMLSAXHandler.getAddtionalAccessSubTreeListFromDB(): "
480 2161 tao
                            + e.getMessage());
481
        }//catch
482 2245 sgarg
        finally
483
        {
484
            try
485
            {
486 2161 tao
                pstmt.close();
487 2245 sgarg
            }
488
            catch (SQLException ee)
489
            {
490 2161 tao
                throw new SAXException(
491
                        "EMLSAXHandler.getAccessSubTreeListFromDB(): "
492
                                + ee.getMessage());
493
            }
494
        }//finally
495
        return result;
496
    }
497
498 2245 sgarg
   /*
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 2161 tao
    /** 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 2663 sgarg
        logMetacat.info("Start ELEMENT(qName) " + qName);
577
        logMetacat.info("Start ELEMENT(localName) " + localName);
578
        logMetacat.info("Start ELEMENT(uri) " + uri);
579 2161 tao
580
        DBSAXNode parentNode = null;
581
        DBSAXNode currentNode = null;
582 2245 sgarg
        // none inline part
583
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
584
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
585
        if (!handleInlineData)
586
        {
587 2161 tao
            // Get a reference to the parent node for the id
588 2245 sgarg
            try
589
            {
590 2161 tao
                parentNode = (DBSAXNode) nodeStack.peek();
591 2245 sgarg
            }
592
            catch (EmptyStackException e)
593
            {
594 2161 tao
                parentNode = null;
595
            }
596
597
            //start handle inline data
598 2245 sgarg
            //=====================================================
599
            if (qName.equals(INLINE) && !inAddtionalMetaData)
600
            {
601 2161 tao
                handleInlineData = true;
602
                inLineDataIndex++;
603
                //intitialize namespace hash for in line data
604
                inlineDataNameSpace = new Hashtable();
605
                //initialize file writer
606 5025 daigle
                String docidWithoutRev = DocumentUtil.getDocIdFromString(docid);
607 4080 daigle
                String seperator = ".";
608
                try {
609 4212 daigle
					seperator = PropertyService.getProperty("document.accNumSeparator");
610 4080 daigle
				} catch (PropertyNotFoundException pnfe) {
611
					logMetacat.error("Could not get property 'accNumSeparator'.  "
612
							+ "Setting separator to '.': "+ pnfe.getMessage());
613
				}
614 2161 tao
                // 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 2245 sgarg
                // 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 2161 tao
            }
646 2245 sgarg
            //==============================================================
647 2161 tao
648 2245 sgarg
649 2161 tao
            // 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 2245 sgarg
            //==============================================================
653
            if (hitTextNode && parentNode != null)
654
            {
655 2161 tao
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 4698 daigle
                            null, null, MetacatUtil.normalize(textBuffer
662 2161 tao
                                    .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 2245 sgarg
            //==================================================================
678 2161 tao
679
            // Document representation that points to the root document node
680 2245 sgarg
            //==================================================================
681
            if (atFirstElement)
682
            {
683 2161 tao
                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 2663 sgarg
                    logMetacat.info("DOCNAME-a: " + docname);
696
                    logMetacat.info("DOCTYPE-a: " + doctype);
697 2161 tao
                } 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 2663 sgarg
                    logMetacat.info("DOCTYPE-b: " + doctype);
702 2161 tao
                }
703
                rootNode.writeNodename(docname);
704 2618 tao
                //System.out.println("here!!!!!!!!!!!!!!!!!!1");
705 2161 tao
                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 2623 tao
                    //String catalogid = null;
715 2161 tao
                    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 2618 tao
                        //System.out.println("here!!!!!!!!!!!!!!!!!!2");
735 2161 tao
                    }//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 2608 tao
                    if (!super.getIsRevisionDoc())
746
                    {
747
748
                       currentDocument = new DocumentImpl(connection, rootNode
749 2161 tao
                            .getNodeID(), docname, doctype, docid, revision,
750 2623 tao
                            action, user, this.pub, catalogid, this.serverCode,
751
                            createDate, updateDate);
752 2608 tao
                    }
753 2623 tao
754 2161 tao
755
                } catch (Exception ane) {
756
                    throw (new SAXException(
757
                            "Error in EMLSaxHandler.startElement " + action,
758
                            ane));
759
                }
760 2608 tao
761 2161 tao
            }
762 2245 sgarg
            //==================================================================
763 2161 tao
764 2245 sgarg
            // node
765
            //==================================================================
766 2161 tao
            // Create the current node representation
767
            currentNode = new DBSAXNode(connection, qName, localName,
768 2628 tao
                    parentNode, rootNode.getNodeID(), docid,
769
                    doctype);
770 2161 tao
            // Use a local variable to store the element node id
771
            // If this element is a start point of subtree(section), it will be
772
            // stored
773
            // otherwise, it will be discated
774
            long startNodeId = currentNode.getNodeID();
775
            // Add all of the namespaces
776
            String prefix = null;
777
            String nsuri = null;
778
            Enumeration prefixes = namespaces.keys();
779 2245 sgarg
            while (prefixes.hasMoreElements())
780
            {
781 2161 tao
                prefix = (String) prefixes.nextElement();
782
                nsuri = (String) namespaces.get(prefix);
783
                endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
784
            }
785
786 2245 sgarg
            //=================================================================
787
           // attributes
788
           // Add all of the attributes
789
          for (int i = 0; i < atts.getLength(); i++)
790
          {
791
              String attributeName = atts.getQName(i);
792
              String attributeValue = atts.getValue(i);
793
              endNodeId = currentNode.setAttribute(attributeName,
794
                      attributeValue, docid);
795 2161 tao
796 2245 sgarg
              // To handle name space and schema location if the attribute
797
              // name is
798
              // xsi:schemaLocation. If the name space is in not in catalog
799
              // table
800
              // it will be regeistered.
801
              if (attributeName != null
802
                      && attributeName
803
                              .indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
804
                  SchemaLocationResolver resolver = new SchemaLocationResolver(
805
                          attributeValue);
806
                  resolver.resolveNameSpace();
807 2161 tao
808 2245 sgarg
              }
809
              else if (attributeName != null && attributeName.equals(ID) &&
810
                       currentNode.getTagName().equals(DISTRIBUTION) &&
811
                       !inAddtionalMetaData)
812
              {
813
                 // this is a distribution element and the id is distributionID
814
                 distributionId = attributeValue;
815
                 distributionAllIdList.put(distributionId, distributionId);
816 2161 tao
817 2245 sgarg
              }
818 2161 tao
819 2245 sgarg
          }//for
820 2161 tao
821
822 2245 sgarg
           //=================================================================
823
824 2161 tao
            // handle access stuff
825 2245 sgarg
            //==================================================================
826
            if (localName.equals(ACCESS))
827
            {
828
                //make sure the access is top level
829
                // this mean current node's parent's parent should be "eml"
830
                DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out
831 2161 tao
                                                                    // parent
832
                                                                    // node
833 2245 sgarg
                //peek out grandParentNode
834
                DBSAXNode grandParentNode = (DBSAXNode) nodeStack.peek();
835
                // put parent node back
836
                nodeStack.push(tmpNode);
837
                String grandParentTag = grandParentNode.getTagName();
838
                if (grandParentTag.equals(EML) && !inAddtionalMetaData)
839
                {
840
                  processTopLeverAccess = true;
841 2161 tao
842
                }
843 2245 sgarg
                else if ( !inAddtionalMetaData )
844
                {
845
                  // process other access embedded into resource level
846
                  // module
847
                  processOtherAccess = true;
848
                }
849
                else
850
                {
851
                  // this for access in additional data which don't have
852
                  // described element. If it has a descirbed element,
853
                  // this code would hurt any thing
854
                  processAdditionalAccess = true;
855 2663 sgarg
                  logMetacat.warn("accessing process addtional access true when meet access");
856 2245 sgarg
                }
857
858
859 2161 tao
                // create access object
860
                accessObject = new AccessSection();
861
                // set permission order
862
                String permOrder = currentNode.getAttribute(ORDER);
863
                accessObject.setPermissionOrder(permOrder);
864
                // set access id
865
                String accessId = currentNode.getAttribute(ID);
866
                accessObject.setSubTreeId(accessId);
867 2245 sgarg
                // for additional access subtree, the  start of node id should
868
                // be describe element. We also stored the start access element
869
                // node id too.
870
                if (processAdditionalAccess)
871
                {
872 4471 daigle
                  accessObject.setStartedDescribesNodeId(firstDescribesNodeId);
873 2245 sgarg
                  accessObject.setControlLevel(DATAACCESSLEVEL);
874
                }
875
                else if (processTopLeverAccess)
876
                {
877
                  accessObject.setControlLevel(TOPLEVEL);
878
                }
879
                else if (processOtherAccess)
880
                {
881
                  accessObject.setControlLevel(REFERENCEDLEVEL);
882
                }
883
884 2161 tao
                accessObject.setStartNodeId(startNodeId);
885
                accessObject.setDocId(docid);
886
887
888 2245 sgarg
889 2161 tao
            }
890
            // Set up a access rule for allow
891
            else if (parentNode.getTagName() != null
892
                    && (parentNode.getTagName()).equals(ACCESS)
893 2245 sgarg
                    && localName.equals(ALLOW))
894
           {
895 2161 tao
896
                accessRule = new AccessRule();
897
898
                //set permission type "allow"
899
                accessRule.setPermissionType(ALLOW);
900
901
            }
902
            // set up an access rule for den
903
            else if (parentNode.getTagName() != null
904
                    && (parentNode.getTagName()).equals(ACCESS)
905 2245 sgarg
                    && localName.equals(DENY))
906
           {
907 2161 tao
                accessRule = new AccessRule();
908
                //set permission type "allow"
909
                accessRule.setPermissionType(DENY);
910
            }
911
912 2245 sgarg
            //=================================================================
913
            // some other independ stuff
914
915 2161 tao
            // Add the node to the stack, so that any text data can be
916
            // added as it is encountered
917
            nodeStack.push(currentNode);
918
            // Add the node to the vector used by thread for writing XML Index
919
            nodeIndex.addElement(currentNode);
920
921
            // store access module element and attributes into stored stack
922
            if (needCheckingAccessModule
923 2245 sgarg
                    && (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
924
            {
925 2161 tao
                // stored the pull out nodes into storedNode stack
926
                NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
927 4698 daigle
                        localName, prefix, MetacatUtil.normalize(null));
928 2161 tao
                storedAccessNodeStack.push(nodeElement);
929
                for (int i = 0; i < atts.getLength(); i++) {
930
                    String attributeName = atts.getQName(i);
931
                    String attributeValue = atts.getValue(i);
932
                    NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2,
933 4698 daigle
                            "ATTRIBUTE", attributeName, null, MetacatUtil
934 2161 tao
                                    .normalize(attributeValue));
935
                    storedAccessNodeStack.push(nodeAttribute);
936
                }
937
938
            }
939
940 2245 sgarg
            if (currentNode.getTagName().equals(ADDITIONALMETADATA))
941
            {
942
              inAddtionalMetaData = true;
943
            }
944
            else if (currentNode.getTagName().equals(DESCRIBES) &&
945
                     parentNode.getTagName().equals(ADDITIONALMETADATA) &&
946
                     firstDescribesInAdditionalMetadata)
947
            {
948
              // this is first decirbes element in additional metadata
949
              firstDescribesNodeId = startNodeId;
950
              // we started process additional access rules here
951
              // because access and describe couldn't be seperated
952 2278 sgarg
              NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT",
953 4698 daigle
                        localName, prefix, MetacatUtil.normalize(null));
954 2278 sgarg
              storedAccessNodeStack.push(nodeElement);
955 2245 sgarg
              processAdditionalAccess = true;
956 2663 sgarg
              logMetacat.warn("set processAdditonalAccess ture when meet describe");
957 2245 sgarg
            }
958
            else if (inAddtionalMetaData && processAdditionalAccess &&
959
                     parentNode.getTagName().equals(ADDITIONALMETADATA) &&
960
                     !currentNode.getTagName().equals(DESCRIBES) &&
961
                     !currentNode.getTagName().equals(ACCESS))
962
            {
963
               // we start processAddtionalAccess  module when first hit describes
964
               // in additionalMetadata. So this is possible, there are
965
               // "describes" but not "access". So here is try to terminate
966
               // processAddionalAccess. In this situation, there another element
967
               // rather than "describes" or "access" as a child of additionalMetadata
968
               // so this is impossible it will have access element now.
969
               // If additionalMetadata has access element, the flag will be
970
               // terminated in endElement
971
               processAdditionalAccess = false;
972 2663 sgarg
               logMetacat.warn("set processAddtionAccess false if the there is no access in additional");
973 2245 sgarg
            }
974
            else if (currentNode.getTagName().equals(DISTRIBUTION) &&
975
                     !inAddtionalMetaData)
976
            {
977
              proccessDistribution = true;
978
            }
979
980
981
             //==================================================================
982 2161 tao
            // reset name space
983
            namespaces = null;
984
            namespaces = new Hashtable();
985 2245 sgarg
986 2161 tao
        }//not inline data
987 2245 sgarg
        // inline data
988
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
989
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
990
        else
991
        {
992 2161 tao
            // we don't buffer the inline data in characters() method
993
            // so start character don't need to hand text node.
994
995
            // inline data may be the xml format.
996
            StringBuffer inlineElements = new StringBuffer();
997
            inlineElements.append("<").append(qName);
998
            // append attributes
999
            for (int i = 0; i < atts.getLength(); i++) {
1000
                String attributeName = atts.getQName(i);
1001
                String attributeValue = atts.getValue(i);
1002
                inlineElements.append(" ");
1003
                inlineElements.append(attributeName);
1004
                inlineElements.append("=\"");
1005
                inlineElements.append(attributeValue);
1006
                inlineElements.append("\"");
1007
            }
1008
            // append namespace
1009
            String prefix = null;
1010
            String nsuri = null;
1011
            Enumeration prefixes = inlineDataNameSpace.keys();
1012
            while (prefixes.hasMoreElements()) {
1013
                prefix = (String) prefixes.nextElement();
1014 2245 sgarg
                nsuri =  (String)  inlineDataNameSpace.get(prefix);
1015 2161 tao
                inlineElements.append(" ");
1016
                inlineElements.append("xmlns:");
1017
                inlineElements.append(prefix);
1018
                inlineElements.append("=\"");
1019
                inlineElements.append(nsuri);
1020
                inlineElements.append("\"");
1021
            }
1022
            inlineElements.append(">");
1023
            //reset inline data name space
1024
            inlineDataNameSpace = null;
1025
            inlineDataNameSpace = new Hashtable();
1026
            //write inline data into file
1027 2663 sgarg
            logMetacat.info("the inline element data is: "
1028
                    + inlineElements.toString());
1029 2161 tao
            writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
1030
        }//else
1031 2245 sgarg
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1032
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1033 2161 tao
1034
    }
1035
1036
1037
    /** SAX Handler that is called for each XML text node */
1038
    public void characters(char[] cbuf, int start, int len) throws SAXException
1039
    {
1040 2663 sgarg
        logMetacat.info("CHARACTERS");
1041 2161 tao
        if (!handleInlineData) {
1042
            // buffer all text nodes for same element. This is for text was
1043
            // splited
1044
            // into different nodes
1045
            textBuffer.append(new String(cbuf, start, len));
1046
            // set hittextnode true
1047
            hitTextNode = true;
1048
            // if text buffer .size is greater than max, write it to db.
1049
            // so we can save memory
1050 2245 sgarg
            if (textBuffer.length() >= MAXDATACHARS)
1051
            {
1052 2663 sgarg
                logMetacat.info("Write text into DB in charaters"
1053
                           + " when text buffer size is greater than maxmum number");
1054 2161 tao
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1055
                endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1056
                        currentNode);
1057 2245 sgarg
                if (needCheckingAccessModule
1058
                     && (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1059
                {
1060
                     // stored the pull out nodes into storedNode stack
1061
                     NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1062 4698 daigle
                       null, null, MetacatUtil.normalize(textBuffer
1063 2245 sgarg
                          .toString()));
1064
                     storedAccessNodeStack.push(nodeElement);
1065
1066
                }
1067 2161 tao
                textBuffer = null;
1068
                textBuffer = new StringBuffer();
1069
            }
1070 2245 sgarg
        }
1071
        else
1072
        {
1073 2161 tao
            // this is inline data and write file system directly
1074
            // we don't need to buffered it.
1075
            StringBuffer inlineText = new StringBuffer();
1076
            inlineText.append(new String(cbuf, start, len));
1077 2663 sgarg
            logMetacat.info(
1078 2161 tao
                    "The inline text data write into file system: "
1079 2663 sgarg
                            + inlineText.toString());
1080 2161 tao
            writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
1081
        }
1082
    }
1083
1084
    /** SAX Handler that is called at the end of each XML element */
1085
    public void endElement(String uri, String localName, String qName)
1086
            throws SAXException
1087
    {
1088 2663 sgarg
        logMetacat.info("End ELEMENT " + qName);
1089 2161 tao
1090 2245 sgarg
        // when close inline element
1091
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1092
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1093
        if (localName.equals(INLINE) && handleInlineData)
1094
        {
1095 2161 tao
            // Get the node from the stack
1096
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1097
            String currentTag = currentNode.getTagName();
1098 2663 sgarg
            logMetacat.info("End of inline data");
1099 2161 tao
            // close file writer
1100 2245 sgarg
            try
1101
            {
1102 2161 tao
                inlineDataFileWriter.close();
1103
                handleInlineData = false;
1104 2245 sgarg
            }
1105
            catch (IOException ioe)
1106
            {
1107 2161 tao
                throw new SAXException(ioe.getMessage());
1108
            }
1109
1110
            //check if user changed inine data or not if user doesn't have
1111 2245 sgarg
            // write permission for this inline block
1112
            // if some error happends, we would delete the inline data file here,
1113
            // we will call a method named deletedInlineFiles in DocumentImple
1114
            if (unWritableInlineDataObject)
1115
            {
1116
                if (unReadableInlineDataObject)
1117
                {
1118
                  // now user just got a empty string in linline part
1119
                  // so if the user send back a empty string is fine and we will
1120
                  // copy the old file to new file. If he send something else,
1121
                  // the document will be rejected
1122
                  if (inlineDataIsEmpty(inlineDataFileName))
1123
                  {
1124
                    copyInlineFile(distributionId, inlineDataFileName);
1125
                  }
1126
                  else
1127
                  {
1128 2663 sgarg
                    logMetacat.info(
1129 2245 sgarg
                               "inline data was changed by a user"
1130 2663 sgarg
                                       + " who doesn't have permission");
1131 2245 sgarg
                    throw new SAXException(PERMISSIONERROR);
1132
1133
                  }
1134
                }//if
1135
                else
1136
                {
1137
                  // user get the inline data
1138
                  if (modifiedInlineData(distributionId, inlineDataFileName))
1139
                  {
1140 2663 sgarg
                    logMetacat.info(
1141 2161 tao
                                "inline data was changed by a user"
1142 2663 sgarg
                                        + " who doesn't have permission");
1143 2161 tao
                    throw new SAXException(PERMISSIONERROR);
1144 2245 sgarg
                  }//if
1145
                }//else
1146
            }//if
1147
            else
1148
            {
1149
               //now user can update file.
1150
               if (unReadableInlineDataObject)
1151
               {
1152
                  // now user just got a empty string in linline part
1153
                  // so if the user send back a empty string is fine and we will
1154
                  // copy the old file to new file. If he send something else,
1155
                  // the new inline data will overwite the old one(here we need
1156
                  // do nothing because the new inline data already existed
1157
                  if (inlineDataIsEmpty(inlineDataFileName))
1158
                  {
1159
                    copyInlineFile(distributionId, inlineDataFileName);
1160
                  }
1161
                }//if
1162 2161 tao
1163 2245 sgarg
            }//else
1164
            // put inline data file name into text buffer (without path)
1165 2161 tao
            textBuffer = new StringBuffer(inlineDataFileName);
1166
            // write file name into db
1167
            endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1168
                    currentNode);
1169
            // reset textbuff
1170
            textBuffer = null;
1171
            textBuffer = new StringBuffer();
1172 2245 sgarg
            // resetinlinedata file name
1173
            inlineDataFileName = null;
1174
            unWritableInlineDataObject = false;
1175
            unReadableInlineDataObject = false;
1176 2161 tao
            return;
1177
        }
1178 2245 sgarg
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1179
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1180 2161 tao
1181 2245 sgarg
1182
1183
        // close element which is not in inline data
1184
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1185
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1186
        if (!handleInlineData)
1187
        {
1188 2161 tao
            // Get the node from the stack
1189
            DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
1190
            String currentTag = currentNode.getTagName();
1191
1192
            // If before the end element, the parser hit text nodes and store
1193
            // them
1194
            // into the buffer, write the buffer to data base. The reason we
1195
            // put
1196
            // write database here is for xerces some time split text node
1197 2245 sgarg
            if (hitTextNode)
1198
            {
1199 2161 tao
                // get access value
1200
                String data = null;
1201
                // add principal
1202 2245 sgarg
                if (currentTag.equals(PRINCIPAL) && accessRule != null)
1203
                {
1204 2161 tao
                    data = (textBuffer.toString()).trim();
1205
                    accessRule.addPrincipal(data);
1206
1207 2245 sgarg
                }
1208
                else if (currentTag.equals(PERMISSION) && accessRule != null)
1209
                {
1210 2161 tao
                    data = (textBuffer.toString()).trim();
1211
                    // we conbine different a permission into one value
1212
                    int permission = accessRule.getPermission();
1213
                    // add permision
1214 2245 sgarg
                    if (data.toUpperCase().equals(READSTRING))
1215
                    {
1216 2161 tao
                        permission = permission | READ;
1217 2245 sgarg
                    }
1218
                    else if (data.toUpperCase().equals(WRITESTRING))
1219
                    {
1220 2161 tao
                        permission = permission | WRITE;
1221 2245 sgarg
                    }
1222
                    else if (data.toUpperCase().equals(CHMODSTRING))
1223
                    {
1224 2161 tao
                        permission = permission | CHMOD;
1225 2245 sgarg
                    }
1226
                    else if (data.toUpperCase().equals(ALLSTRING))
1227
                    {
1228 2161 tao
                        permission = permission | ALL;
1229
                    }
1230
                    accessRule.setPermission(permission);
1231
                }
1232
                // put additionalmetadata/describes into vector
1233 2245 sgarg
                else if (currentTag.equals(DESCRIBES))
1234
                {
1235 2161 tao
                    data = (textBuffer.toString()).trim();
1236
                    describesId.add(data);
1237 2245 sgarg
                    //firstDescribesInAdditionalMetadata = false;
1238
                    //firstDescribesNodeId = 0;
1239
                }
1240
                else if (currentTag.equals(REFERENCES)
1241
                        && (processTopLeverAccess || processAdditionalAccess || processOtherAccess))
1242
                {
1243 2161 tao
                    // get reference
1244
                    data = (textBuffer.toString()).trim();
1245
                    // put reference id into accessSection
1246
                    accessObject.setReferences(data);
1247
1248 2245 sgarg
                }
1249
                else if (currentTag.equals(REFERENCES) && proccessDistribution)
1250
                {
1251
                  // get reference for distribution
1252
                  data = (textBuffer.toString()).trim();
1253
                  // we only stored the distribution reference which itself
1254
                  // has a id
1255
                  if (distributionId != null)
1256
                  {
1257
                    distributionReferenceList.put(distributionId, data);
1258
                  }
1259
1260
                }
1261
                else if (currentTag.equals(URL) && !inAddtionalMetaData)
1262
                {
1263 2161 tao
                    //handle online data, make sure its'parent is online
1264
                    DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1265
                    if (parentNode != null && parentNode.getTagName() != null
1266 2245 sgarg
                            && parentNode.getTagName().equals(ONLINE))
1267
                    {
1268 2161 tao
                        data = (textBuffer.toString()).trim();
1269 2245 sgarg
                        if (distributionId != null)
1270
                        {
1271
                          onlineURLDistributionIdList.put(distributionId, data);
1272
                        }
1273
                        else
1274
                        {
1275 4501 daigle
                          onlineURLDistributionListWithoutId.add(data);
1276 2245 sgarg
                        }
1277 2161 tao
                    }//if
1278
                }//else if
1279
                // write text to db if it is not inline data
1280 2245 sgarg
1281 2663 sgarg
                logMetacat.info(
1282
                            "Write text into DB in End Element");
1283 2245 sgarg
1284
                 // write text node into db
1285
                 endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer,
1286 2161 tao
                            currentNode);
1287 2245 sgarg
1288 2161 tao
                if (needCheckingAccessModule
1289
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1290
                    // stored the pull out nodes into storedNode stack
1291
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1292 4698 daigle
                            null, null, MetacatUtil.normalize(textBuffer
1293 2161 tao
                                    .toString()));
1294
                    storedAccessNodeStack.push(nodeElement);
1295
1296
                }
1297 2245 sgarg
            }//if handle text node
1298 2161 tao
1299
1300 2245 sgarg
1301 2161 tao
            //set hitText false
1302
            hitTextNode = false;
1303
            // reset textbuff
1304
            textBuffer = null;
1305
            textBuffer = new StringBuffer();
1306
1307
1308
            // access stuff
1309 2245 sgarg
            if (currentTag.equals(ALLOW) || currentTag.equals(DENY))
1310
            {
1311 2161 tao
                // finish parser a ccess rule and assign it to new one
1312
                AccessRule newRule = accessRule;
1313
                //add the new rule to access section object
1314
                accessObject.addAccessRule(newRule);
1315
                // reset access rule
1316
                accessRule = null;
1317 2245 sgarg
            }// ALLOW or DENY
1318
            else if (currentTag.equals(ACCESS))
1319
            {
1320
                // finish parse a access setction and stored them into different
1321
                // places
1322 2161 tao
1323
                accessObject.setEndNodeId(endNodeId);
1324
                AccessSection newAccessObject = accessObject;
1325 2245 sgarg
                newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1326
                if (newAccessObject != null)
1327
                {
1328 2161 tao
1329 2245 sgarg
                    if (processTopLeverAccess)
1330
                    {
1331
                       topAccessSection = newAccessObject;
1332 2161 tao
1333
                    }//if
1334 2245 sgarg
                    else if (processAdditionalAccess)
1335
                    {
1336 2161 tao
                        // for additional control
1337 2245 sgarg
                        // put discribesId into the accessobject and put this
1338
                        // access object into vector
1339
                        newAccessObject.setDescribedIdList(describesId);
1340
                        addtionalAccessVector.add(newAccessObject);
1341 2161 tao
1342
                    }//if
1343 2245 sgarg
                    else if (processOtherAccess)
1344
                    {
1345
                      // we only stored the access object which has a id
1346
                      // because only the access object which has a id can
1347
                      // be reference
1348
                      if (newAccessObject.getSubTreeId() != null &&
1349
                          !newAccessObject.getSubTreeId().trim().equals(""))
1350
                      {
1351
                         possibleReferencedAccessHash.
1352
                           put(newAccessObject.getSubTreeId(), newAccessObject);
1353
                      }
1354
                    }
1355 2161 tao
1356
                }//if
1357
                //reset access section object
1358
                accessObject = null;
1359
1360
                // reset tmp stored node stack
1361
                storedAccessNodeStack = null;
1362
                storedAccessNodeStack = new Stack();
1363
1364
                // reset flag
1365
                processAdditionalAccess = false;
1366
                processTopLeverAccess = false;
1367
                processOtherAccess = false;
1368
1369 2245 sgarg
            }//access element
1370
            else if (currentTag.equals(ADDITIONALMETADATA))
1371
            {
1372 2161 tao
                //reset describesId
1373
                describesId = null;
1374
                describesId = new Vector();
1375 2245 sgarg
                inAddtionalMetaData = false;
1376 2278 sgarg
                firstDescribesNodeId = -1;
1377
                // reset tmp stored node stack
1378
                storedAccessNodeStack = null;
1379
                storedAccessNodeStack = new Stack();
1380 2245 sgarg
1381 2278 sgarg
1382 2161 tao
            }
1383 2245 sgarg
            else if (currentTag.equals(DISTRIBUTION) && !inAddtionalMetaData)
1384
            {
1385
               //reset distribution id
1386
               distributionId = null;
1387
               proccessDistribution = false;
1388
            }
1389
            else if (currentTag.equals(OFFLINE) && !inAddtionalMetaData)
1390
            {
1391
               if (distributionId != null)
1392
               {
1393
                 offlineDistributionIdList.put(distributionId, distributionId);
1394
               }
1395
            }
1396
            else if ((currentTag.equals(CONNECTION) || currentTag.equals(CONNECTIONDEFINITION))
1397
                     && !inAddtionalMetaData)
1398
            {
1399
              //handle online data, make sure its'parent is online
1400
                 DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
1401
                 if (parentNode != null && parentNode.getTagName() != null
1402
                         && parentNode.getTagName().equals(ONLINE))
1403
                 {
1404
                     if (distributionId != null)
1405
                     {
1406
                        onlineOtherDistributionIdList.put(distributionId, distributionId);
1407
                     }
1408
                 }//if
1409
1410
            }//else if
1411
            else if (currentTag.equals(DESCRIBES))
1412
            {
1413
                firstDescribesInAdditionalMetadata = false;
1414 2278 sgarg
1415 2245 sgarg
            }
1416
1417
1418
1419
        }
1420
        // close elements which are in inline data (inline data can be xml doc)
1421
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1422
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1423
        else
1424
        {
1425 2161 tao
            // this is in inline part
1426
            StringBuffer endElement = new StringBuffer();
1427
            endElement.append("</");
1428
            endElement.append(qName);
1429
            endElement.append(">");
1430 2663 sgarg
            logMetacat.info("inline endElement: "
1431
                    + endElement.toString());
1432 2161 tao
            writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1433
        }
1434 2245 sgarg
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1435
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1436 2161 tao
    }
1437
1438 2245 sgarg
1439
    /*
1440
     * Method to check if the new line data is as same as the old one
1441
     */
1442
     private boolean modifiedInlineData(String inlineDistributionId,
1443 4080 daigle
			String newInlineInternalFileName) throws SAXException {
1444 2245 sgarg
       boolean modified = true;
1445
       if (inlineDistributionId == null || newInlineInternalFileName == null)
1446
       {
1447
         return modified;
1448
       }
1449
       String oldInlineInternalFileName =
1450
            (String)previousUnwritableInlineDataObjectHash.get(inlineDistributionId);
1451
       if (oldInlineInternalFileName == null ||
1452
           oldInlineInternalFileName.trim().equals(""))
1453
       {
1454
         return modified;
1455
       }
1456 2663 sgarg
       logMetacat.info("in handle inline data");
1457
       logMetacat.info("the inline data file name from xml_access is: "
1458
                                    + oldInlineInternalFileName);
1459 2245 sgarg
1460
       try
1461
       {
1462
         if (!compareInlineDataFiles(oldInlineInternalFileName,
1463
                                     newInlineInternalFileName))
1464
         {
1465
           modified = true;
1466
1467
         }
1468
         else
1469
         {
1470
           modified = false;
1471
         }
1472
       }
1473
       catch(Exception e)
1474
       {
1475
         modified = true;
1476
       }
1477
1478
       // delete the inline data file already in file system
1479
       if (modified)
1480
       {
1481
         deleteInlineDataFile(newInlineInternalFileName);
1482
1483
       }
1484
       return modified;
1485
     }
1486
1487
     /*
1488
      * A method to check if a line file is empty
1489
      */
1490
     private boolean inlineDataIsEmpty(String fileName) throws SAXException
1491
     {
1492
        boolean isEmpty = true;
1493
        if ( fileName == null)
1494
        {
1495
          throw new SAXException("The inline file name is null");
1496
        }
1497 4080 daigle
1498
        try {
1499
			String path = PropertyService.getProperty("application.inlinedatafilepath");
1500
			// the new file name will look like path/docid.rev.2
1501
			File inlineDataDirectory = new File(path);
1502
			File inlineDataFile = new File(inlineDataDirectory, fileName);
1503 2245 sgarg
1504 4080 daigle
			FileReader inlineFileReader = new FileReader(inlineDataFile);
1505
			BufferedReader inlineStringReader = new BufferedReader(inlineFileReader);
1506
			String string = inlineStringReader.readLine();
1507
			// at the end oldstring will be null
1508
			while (string != null) {
1509
				string = inlineStringReader.readLine();
1510
				if (string != null && !string.trim().equals("")) {
1511
					isEmpty = false;
1512
					break;
1513
				}
1514
			}
1515 2245 sgarg
1516 4080 daigle
		} catch (Exception e) {
1517
			throw new SAXException(e.getMessage());
1518
		}
1519
		return isEmpty;
1520
1521 2245 sgarg
     }
1522
1523
1524 2161 tao
    /**
1525 4080 daigle
	 * SAX Handler that receives notification of comments in the DTD
1526
	 */
1527 2161 tao
    public void comment(char[] ch, int start, int length) throws SAXException
1528
    {
1529 2663 sgarg
        logMetacat.info("COMMENT");
1530 2161 tao
        if (!handleInlineData) {
1531
            if (!processingDTD) {
1532
                DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1533
                String str = new String(ch, start, length);
1534
1535
                //compare comment if need
1536 2245 sgarg
                /*if (startCriticalSubTree) {
1537 2161 tao
                    compareCommentNode(currentUnChangedableSubtreeNodeStack,
1538
                            str, PERMISSIONERROR);
1539 2245 sgarg
                }//if*/
1540 2161 tao
                //compare top level access module
1541
                if (processTopLeverAccess && needCheckingAccessModule) {
1542 2245 sgarg
                    /*compareCommentNode(currentUnchangableAccessModuleNodeStack,
1543
                            str, UPDATEACCESSERROR);*/
1544 2161 tao
                }
1545
                endNodeId = currentNode.writeChildNodeToDB("COMMENT", null,
1546
                        str, docid);
1547
                if (needCheckingAccessModule
1548
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1549
                    // stored the pull out nodes into storedNode stack
1550
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2,
1551 4698 daigle
                            "COMMENT", null, null, MetacatUtil.normalize(str));
1552 2161 tao
                    storedAccessNodeStack.push(nodeElement);
1553
1554
                }
1555
            }
1556
        } else {
1557
            // inline data comment
1558
            StringBuffer inlineComment = new StringBuffer();
1559
            inlineComment.append("<!--");
1560
            inlineComment.append(new String(ch, start, length));
1561
            inlineComment.append("-->");
1562 2663 sgarg
            logMetacat.info("inline data comment: "
1563
                    + inlineComment.toString());
1564 2161 tao
            writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1565
        }
1566
    }
1567
1568
1569 2245 sgarg
1570 2161 tao
    /**
1571
     * SAX Handler called once for each processing instruction found: node that
1572
     * PI may occur before or after the root element.
1573
     */
1574
    public void processingInstruction(String target, String data)
1575
            throws SAXException
1576
    {
1577 2663 sgarg
        logMetacat.info("PI");
1578 2161 tao
        if (!handleInlineData) {
1579
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1580
            endNodeId = currentNode.writeChildNodeToDB("PI", target, data,
1581
                    docid);
1582
        } else {
1583
            StringBuffer inlinePI = new StringBuffer();
1584
            inlinePI.append("<?");
1585
            inlinePI.append(target);
1586
            inlinePI.append(" ");
1587
            inlinePI.append(data);
1588
            inlinePI.append("?>");
1589 2663 sgarg
            logMetacat.info("inline data pi is: "
1590
                    + inlinePI.toString());
1591 2161 tao
            writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1592
        }
1593
    }
1594
1595
    /** SAX Handler that is called at the start of Namespace */
1596
    public void startPrefixMapping(String prefix, String uri)
1597
            throws SAXException
1598
    {
1599 2663 sgarg
        logMetacat.info("NAMESPACE");
1600
        logMetacat.info("NAMESPACE prefix "+prefix);
1601
        logMetacat.info("NAMESPACE uri "+uri);
1602 2161 tao
        if (!handleInlineData) {
1603
            namespaces.put(prefix, uri);
1604
        } else {
1605
            inlineDataNameSpace.put(prefix, uri);
1606
        }
1607
    }
1608
1609
    /**
1610
     * SAX Handler that is called for each XML text node that is Ignorable
1611
     * white space
1612
     */
1613
    public void ignorableWhitespace(char[] cbuf, int start, int len)
1614
            throws SAXException
1615
    {
1616
        // When validation is turned "on", white spaces are reported here
1617
        // When validation is turned "off" white spaces are not reported here,
1618
        // but through characters() callback
1619 2663 sgarg
        logMetacat.info("IGNORABLEWHITESPACE");
1620 2161 tao
        if (!handleInlineData) {
1621
            DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1622
            String data = null;
1623
            int leftover = len;
1624
            int offset = start;
1625
            boolean moredata = true;
1626
1627
            // This loop deals with the case where there are more characters
1628
            // than can fit in a single database text field (limit is
1629
            // MAXDATACHARS). If the text to be inserted exceeds MAXDATACHARS,
1630
            // write a series of nodes that are MAXDATACHARS long, and then the
1631
            // final node contains the remainder
1632
            while (moredata) {
1633
                if (leftover > MAXDATACHARS) {
1634
                    data = new String(cbuf, offset, MAXDATACHARS);
1635
                    leftover -= MAXDATACHARS;
1636
                    offset += MAXDATACHARS;
1637
                } else {
1638
                    data = new String(cbuf, offset, leftover);
1639
                    moredata = false;
1640
                }
1641
1642
                //compare whitespace if need
1643 2245 sgarg
                /*if (startCriticalSubTree) {
1644 2161 tao
                    compareWhiteSpace(currentUnChangedableSubtreeNodeStack,
1645
                            data, PERMISSIONERROR);
1646 2245 sgarg
                }//if*/
1647 2161 tao
1648
                //compare whitespace in access top module
1649
                if (processTopLeverAccess && needCheckingAccessModule) {
1650 2245 sgarg
                    /*compareWhiteSpace(currentUnchangableAccessModuleNodeStack,
1651
                            data, UPDATEACCESSERROR);*/
1652 2161 tao
                }
1653
                // Write the content of the node to the database
1654
                if (needCheckingAccessModule
1655
                        && (processAdditionalAccess || processOtherAccess || processTopLeverAccess)) {
1656
                    // stored the pull out nodes into storedNode stack
1657
                    NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT",
1658 4698 daigle
                            null, null, MetacatUtil.normalize(data));
1659 2161 tao
                    storedAccessNodeStack.push(nodeElement);
1660
1661
                }
1662
                endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data,
1663
                        docid);
1664
            }
1665
        } else {
1666
            //This is inline data write to file directly
1667
            StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf,
1668
                    start, len));
1669
            writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1670
        }
1671
1672
    }
1673
1674
1675
    /** SAX Handler that receives notification of end of the document */
1676
    public void endDocument() throws SAXException
1677
    {
1678 2663 sgarg
        logMetacat.info("end Document");
1679 2245 sgarg
        if (needCheckingAccessModule)
1680
        {
1681
          compareAllAccessModules();
1682 2161 tao
        }
1683
1684 2245 sgarg
        // user deleted some inline block which it counldn't delete
1685
        if (numberOfHitUnWritableInlineData !=
1686
            previousUnwritableInlineDataObjectHash.size())
1687
        {
1688
          throw new SAXException("user deleted some inline block it couldn't");
1689
        }
1690
1691 2608 tao
        if (!super.getIsRevisionDoc())
1692
        {
1693
          // write access rule to xml_access table which include both top level
1694
          // and additional level(data access level). It also write access subtree
1695
          // info into xml_accesssubtree about the top access, additional access
1696
          // and some third place access modules which are referenced by top
1697
          // level or additional level
1698
          writeAccessRuleToDB();
1699 2161 tao
1700 2608 tao
          //delete relation table
1701
          deleteRelations();
1702
          //write relations
1703
           for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1704 2165 tao
            String id = (String) onlineDataFileIdInRelationVector.elementAt(i);
1705 2161 tao
            writeOnlineDataFileIdIntoRelationTable(id);
1706 2608 tao
           }
1707 2161 tao
        }
1708
1709 2245 sgarg
        // clean the subtree record
1710
        accessSubTreeAlreadyWriteDBList = new Hashtable();
1711 2161 tao
    }
1712
1713
1714 2245 sgarg
1715
    /* The method will compare all access modules in eml document -
1716
     * topLevel, additionalLevel(data access) and referenced access module*/
1717
    private void compareAllAccessModules() throws SAXException
1718 2161 tao
    {
1719 2245 sgarg
      //compare top level
1720
      compareAccessSubtree(unChangebleTopAccessSubTree, topAccessSection);
1721 2161 tao
1722 2245 sgarg
      //compare additional level
1723
      int oldSize = unChangebleAdditionalAccessSubTreeVector.size();
1724
      int newSize = addtionalAccessVector.size();
1725
      // if size is different, use deleted or added rules, so throw a exception
1726
      if (oldSize != newSize)
1727
      {
1728
        throw new SAXException(UPDATEACCESSERROR);
1729
      }
1730
      //because access modules are both ordered in ASC in vectors, so we can
1731
      // compare one bye one
1732
      for ( int i = 0; i < newSize; i++)
1733
      {
1734
        AccessSection fromDB = (AccessSection)
1735
                          unChangebleAdditionalAccessSubTreeVector.elementAt(i);
1736
        AccessSection fromParser = (AccessSection)
1737
                                addtionalAccessVector.elementAt(i);
1738
        compareAccessSubtree(fromDB, fromParser);
1739
      }
1740 2161 tao
1741 2245 sgarg
      //compare referenced level
1742
      Enumeration em = unChangebleReferencedAccessSubTreeHash.keys();
1743
      while (em.hasMoreElements())
1744
      {
1745
        String id = (String)em.nextElement();
1746
        AccessSection fromDB = (AccessSection)
1747
                               unChangebleReferencedAccessSubTreeHash.get(id);
1748
        AccessSection fromParser = (AccessSection)
1749
                               possibleReferencedAccessHash.get(id);
1750
        compareAccessSubtree(fromDB, fromParser);
1751
      }
1752
    }
1753 2161 tao
1754 2245 sgarg
    /* The method will compare two access subtree. Currently they compare to
1755
     * nodes one by one. It also can be changed to parse the node first, then
1756
     * compare the parsed result
1757
     */
1758
    private void compareAccessSubtree(AccessSection fromDBTable,
1759
                                       AccessSection fromParser)
1760
                                      throws SAXException
1761
    {
1762
       if (fromDBTable == null || fromParser == null)
1763
       {
1764
         throw new SAXException(UPDATEACCESSERROR);
1765
       }
1766
       Stack nodeStackFromDBTable = fromDBTable.getSubTreeNodeStack();
1767
       Stack nodeStackFromParser  = fromParser.getStoredTmpNodeStack();
1768 2262 sgarg
1769
       Stack tempStack = new Stack();
1770
       while(!nodeStackFromDBTable.isEmpty()){
1771
           tempStack.push(nodeStackFromDBTable.pop());
1772
       }
1773
       comparingNodeStacks(tempStack, nodeStackFromParser);
1774 2245 sgarg
    }
1775 2161 tao
1776 2245 sgarg
    /* Compare two node stacks to see if they are same */
1777
  private void comparingNodeStacks(Stack stack1, Stack stack2)
1778
          throws SAXException
1779
  {
1780
      // make sure stack1 and stack2 are not empty
1781
      if (stack1.isEmpty() || stack2.isEmpty()) {
1782 2663 sgarg
          logMetacat.info("Because stack is empty!");
1783 2245 sgarg
          throw new SAXException(UPDATEACCESSERROR);
1784
      }
1785
      // go throw two stacks and compare every element
1786
      while (!stack1.isEmpty()) {
1787
          // Pop an element from stack1
1788
          NodeRecord record1 = (NodeRecord) stack1.pop();
1789 2278 sgarg
1790 2245 sgarg
          // Pop an element from stack2(stack 2 maybe empty)
1791
          NodeRecord record2 = null;
1792
          try {
1793
              record2 = (NodeRecord) stack2.pop();
1794
          } catch (EmptyStackException ee) {
1795 2278 sgarg
1796 2663 sgarg
              logMetacat.error(
1797
                      "Node stack2 is empty but stack1 isn't!");
1798 2245 sgarg
              throw new SAXException(UPDATEACCESSERROR);
1799
          }
1800
          // if two records are not same throw a exception
1801
          if (!record1.contentEquals(record2)) {
1802 2663 sgarg
              logMetacat.info("Two records from new and old stack are not "
1803
                                      + "same!" + record1 + "--" +record2);
1804 2245 sgarg
              throw new SAXException(UPDATEACCESSERROR);
1805
          }//if
1806
      }//while
1807 2165 tao
1808 2245 sgarg
      // now stack1 is empty and we should make sure stack2 is empty too
1809
      if (!stack2.isEmpty()) {
1810 2278 sgarg
1811 2663 sgarg
          logMetacat.info(
1812 2278 sgarg
                  "stack2 still have some elements while stack1 "
1813 2663 sgarg
                          + "is empty! ");
1814 2245 sgarg
          throw new SAXException(UPDATEACCESSERROR);
1815
      }//if
1816
  }//comparingNodeStacks
1817 2161 tao
1818
1819 2245 sgarg
    /* The method to write all access rule into db */
1820
    private void writeAccessRuleToDB() throws SAXException
1821
    {
1822
        // delete xml_accesssubtree table record for this docid
1823
        deleteAccessSubTreeRecord(docid);
1824
        //write additional access rule, and old records in xml_access will be
1825
        //deleted too
1826 2618 tao
        //System.out.println("before write additional access rules");
1827 2245 sgarg
        writeAddtionalAccessRuleToDB();
1828 2618 tao
        //System.out.println("after write additional access rules");
1829 2245 sgarg
        //write top leve access rule, and old records in xml_access will be
1830
        //deleted too
1831 2248 sgarg
1832
        if (topAccessSection != null){
1833
          writeTopLevelAccessRuleToDB();
1834
        }
1835 2618 tao
        //System.out.println("after write top access rules");
1836 2245 sgarg
    }//writeAccessRuleToDB
1837 2161 tao
1838
1839 2245 sgarg
    /* The method will figure out access reference for given access section -
1840
     * return a new AccessSection which contain access rules that be referenced.
1841
     * And will write the access subtree into xml_access table.
1842
     * this is a recursive method
1843
     */
1844
   private AccessSection resolveAccessRuleReference(AccessSection access)
1845
                                                    throws SAXException
1846
   {
1847
     if (access == null)
1848
     {
1849 2663 sgarg
       logMetacat.info("access module is null in " +
1850
                                "resolveAccessRulesReference");
1851 2245 sgarg
       throw new SAXException("An access modules is null");
1852
     }
1853
     String subTreeId = access.getSubTreeId();
1854
     if (subTreeId == null ||
1855
         (subTreeId != null && !accessSubTreeAlreadyWriteDBList.contains(subTreeId)))
1856
     {
1857
        // we should record this access subtree into accesssubtree table.
1858
        // subtreeId is null means it can't be referenced. So this tree couldn't
1859
        // be stored twise in the table. Subtree is not null, but it is in
1860
        // hash yet, so it is new one.
1861
        writeAccessSubTreeIntoDB(access);
1862
        if (subTreeId != null)
1863
        {
1864
          accessSubTreeAlreadyWriteDBList.put(subTreeId, subTreeId);
1865 2161 tao
        }
1866 2245 sgarg
     }
1867 2161 tao
1868 2245 sgarg
     String reference = access.getReferences();
1869
     if (reference != null)
1870
     {
1871
       // find the reference in top level
1872
       String topSubtreeId = topAccessSection.getSubTreeId();
1873
       if (topSubtreeId != null && topSubtreeId.equals(reference))
1874
       {
1875
          return resolveAccessRuleReference(topAccessSection);
1876
       }
1877
       else
1878
       {
1879
           // search it the additional access
1880
           for ( int i = 0; i <addtionalAccessVector.size(); i++)
1881
           {
1882
             AccessSection additionalAccess = (AccessSection)
1883
                           addtionalAccessVector.elementAt(i);
1884
             String additionId = additionalAccess.getSubTreeId();
1885
             if (additionId != null && additionId.equals(reference))
1886
             {
1887
               return resolveAccessRuleReference(additionalAccess);
1888
             }// if
1889
           }// for
1890 2161 tao
1891 2245 sgarg
           // search possible referenced access hashtable
1892
           if (possibleReferencedAccessHash.containsKey(reference))
1893
           {
1894
             AccessSection referenceAccess = (AccessSection)
1895
                         possibleReferencedAccessHash.get(reference);
1896
             return resolveAccessRuleReference(referenceAccess);
1897
           }
1898 2161 tao
1899 2245 sgarg
           // if hit here, this means you don't find any id match the reference
1900
           // throw a exception
1901
           throw new SAXException("No access module's id match the reference id");
1902
       }
1903
     }
1904
     else
1905
     {
1906
       // base line reference == null
1907
       AccessSection newAccessSection = new AccessSection();
1908
       access.copyPermOrderAndAccessRules(newAccessSection);
1909
       return newAccessSection;
1910
     }
1911
   }//resolveAccessRuleReference
1912 2161 tao
1913 2245 sgarg
   /* This method will return a id which points a real distribution block if
1914
    *  given a distribution id which is a reference. If the given id is a real
1915
    *  distribution the id itself will be returned.
1916
    *  Here is segment of eml
1917
    *   <distribution id ="100"><online><url>abc</url></online></distribution>
1918
    *   <distribution id ="200"><reference>100</reference></distribution>
1919
    * if the given value is 200, 100 will be returned.
1920
    * if the given value is 100, 100 will be returned.
1921
    */
1922
   private String resolveDistributionReference(String givenId)
1923
   {
1924
      if (givenId == null )
1925
      {
1926
        return null;
1927
      }
1928
      if (!distributionReferenceList.containsKey(givenId))
1929
      {
1930
        //this is not reference distribution block, return given id
1931
        return givenId;
1932
      }
1933
      else
1934
      {
1935
         String referencedId = (String) distributionReferenceList.get(givenId);
1936
         // search util the referenced id is not in dsitribtionReferenceList
1937
         while (distributionReferenceList.containsKey(referencedId))
1938
         {
1939
           referencedId = (String) distributionReferenceList.get(referencedId);
1940
         }
1941
         return referencedId;
1942
      }
1943
   }
1944 2161 tao
1945
1946 2245 sgarg
  /* The method to write top level access rule into db. The old rules will be
1947
   * deleted
1948
   * If no describedId in the access object, this access rules will be ingorned
1949
   */
1950
  private void writeAddtionalAccessRuleToDB() throws SAXException
1951
  {
1952 2618 tao
     //System.out.println("in write addtional");
1953 2245 sgarg
     // we should delete all inline access rules in xml_access if
1954
     // user has all permission
1955
     if (!needCheckingAccessModule)
1956
     {
1957
       deleteAllInlineDataAccessRules();
1958
     }
1959
     for (int i=0; i < addtionalAccessVector.size(); i++)
1960
     {
1961 2618 tao
       //System.out.println("in for loop of write addtional");
1962 2245 sgarg
       AccessSection access = (AccessSection)addtionalAccessVector.elementAt(i);
1963
       Vector describeIdList = access.getDescribedIdList();
1964
       // if this access is a reference, a new access object will be created
1965
       // which contains the real access rules referenced. Also, each access tree
1966
       // will be write into xml_accesssubtee table
1967
       AccessSection newAccess = resolveAccessRuleReference(access);
1968
       String permOrder = newAccess.getPermissionOrder();
1969
       Vector accessRule = newAccess.getAccessRules();
1970 2161 tao
1971 2245 sgarg
       if (describeIdList == null || describeIdList.isEmpty())
1972
       {
1973
         continue;
1974
       }
1975 2161 tao
1976 2245 sgarg
       for (int j = 0; j < describeIdList.size(); j++)
1977
       {
1978
         String subreeid = (String)describeIdList.elementAt(j);
1979 2663 sgarg
         logMetacat.info("describe id in additional access " +
1980
                                  subreeid);
1981 2245 sgarg
         // we need to figure out the real id if this subreeid is points to
1982
         // a distribution reference.
1983
         subreeid = resolveDistributionReference(subreeid);
1984
         if (subreeid != null && !subreeid.trim().equals(""))
1985
         {
1986 2663 sgarg
           logMetacat.info("subtree id is "+ subreeid +
1987
                                    " after resolve reference id" );
1988 2245 sgarg
           // if this id is for line data, we need to delete the records first
1989
           // then add new records. The key for deleting is subtee id
1990
           if (inlineDistributionIdList.containsKey(subreeid))
1991
           {
1992
             String inlineFileName = (String)
1993
                                        inlineDistributionIdList.get(subreeid);
1994
             deleteSubtreeAccessRule(subreeid);
1995 2663 sgarg
             logMetacat.info("Write inline data access into " +
1996
                                   "xml_access table for"+ inlineFileName);
1997 2245 sgarg
             writeGivenAccessRuleIntoDB(permOrder, accessRule,
1998
                                        inlineFileName, subreeid);
1999
           }
2000
           else if (onlineURLDistributionIdList.containsKey(subreeid))
2001
           {
2002
             String url = (String)onlineURLDistributionIdList.get(subreeid);
2003
             //this method will extrace data file id from url. It also will
2004
             // check if user can change the access rules for the data file id.
2005
             // if couldn't, it will throw a exception. Morover, the docid will
2006
             // be to relation id vector too.
2007
             // for online data, the subtree id we set is null.
2008
             // So in xml_access, only the inline data subteeid is not null
2009
             String dataFileName = handleOnlineUrlDataFile(url);
2010 2663 sgarg
             logMetacat.info("The data fileName in online url " +
2011
                                      dataFileName);
2012 2245 sgarg
             if (dataFileName != null)
2013
             {
2014
               deletePermissionsInAccessTableForDoc(dataFileName);
2015
               writeGivenAccessRuleIntoDB(permOrder, accessRule,
2016
                                          dataFileName, null);
2017 2663 sgarg
               logMetacat.info("Write online data access into " +
2018
                                   "xml_access table for " + dataFileName);
2019 2245 sgarg
               // put the id into a hashtalbe. So when we run wirtetop level
2020
               // access, those id will be ignored because they already has
2021
               // additional access rules
2022
               onlineURLIdHasAddtionalAccess.put(subreeid, subreeid);
2023
             }
2024
           }//elseif
2025
         }//if
2026
       }//for
2027
     }//for
2028 2161 tao
2029 2245 sgarg
   }//writeAdditonalLevelAccessRuletoDB
2030 2161 tao
2031
2032 2245 sgarg
    /* The method to write addtional access rule into db. */
2033
    private void writeTopLevelAccessRuleToDB() throws SAXException
2034 2161 tao
    {
2035 2245 sgarg
       // if top access is reference, we need figure out the real access rules
2036
       // it points to
2037 2618 tao
       //System.out.println("permorder in top level" + topAccessSection.getPermissionOrder());
2038 2245 sgarg
       AccessSection newAccess = resolveAccessRuleReference(topAccessSection);
2039 2618 tao
       //System.out.println("permorder in new level" + newAccess.getPermissionOrder());
2040 2245 sgarg
       String permOrder = newAccess.getPermissionOrder();
2041
       Vector accessRule = newAccess.getAccessRules();
2042
       String subtree     = null;
2043
       // document itself
2044
       deletePermissionsInAccessTableForDoc(docid);
2045
       writeGivenAccessRuleIntoDB(permOrder, accessRule, docid, subtree);
2046
       // for online data, it includes with id and without id.
2047
       // 1. for the data with subtree id, we should ignore the ones already in
2048
       // the hash - onlineURLIdHasAddionalAccess.
2049
       // 2. for those without subreeid, it couldn't have additional access and we
2050
       // couldn't ignore it.
2051
       // 3. for inline data, we need do nothing because if it doesn't have
2052
       // additional access, it default value is the top one.
2053 2161 tao
2054 2245 sgarg
       // here is the online url with id
2055
       Enumeration em = onlineURLDistributionIdList.keys();
2056
       while (em.hasMoreElements())
2057
       {
2058
         String onlineSubtreeId = (String)em.nextElement();
2059
         if (!onlineURLIdHasAddtionalAccess.containsKey(onlineSubtreeId))
2060
         {
2061
            String url =
2062
                       (String)onlineURLDistributionIdList.get(onlineSubtreeId);
2063
            String onlineDataId = handleOnlineUrlDataFile(url);
2064
            if (onlineDataId != null)
2065
            {
2066
              deletePermissionsInAccessTableForDoc(onlineDataId);
2067
              writeGivenAccessRuleIntoDB(permOrder, accessRule,
2068
                                         onlineDataId, subtree);
2069 2161 tao
            }
2070
2071 2245 sgarg
         }
2072
       }//while
2073 2161 tao
2074 2245 sgarg
       // here is the onlineURL without id
2075 4501 daigle
       for (int i= 0; i < onlineURLDistributionListWithoutId.size(); i++)
2076 2245 sgarg
       {
2077 4501 daigle
         String url = (String)onlineURLDistributionListWithoutId.elementAt(i);
2078 2245 sgarg
         String onlineDataId = handleOnlineUrlDataFile(url);
2079
         if (onlineDataId != null)
2080
         {
2081
           deletePermissionsInAccessTableForDoc(onlineDataId);
2082
           writeGivenAccessRuleIntoDB(permOrder, accessRule,
2083
                                         onlineDataId, subtree);
2084
         }
2085
       }//for
2086
    }//writeTopAccessRuletoDB
2087 2161 tao
2088
    /* Write a gaven access rule into db */
2089 2245 sgarg
    private void writeGivenAccessRuleIntoDB(String permOrder, Vector accessRules,
2090
                     String dataId, String subTreeId) throws SAXException
2091 2161 tao
    {
2092 2245 sgarg
      if (permOrder == null || permOrder.trim().equals("") || dataId == null ||
2093
          dataId.trim().equals("") || accessRules == null ||
2094
          accessRules.isEmpty())
2095
      {
2096 2663 sgarg
        logMetacat.info("The access object is null and tried to " +
2097
                                  " write to xml_access table");
2098 2245 sgarg
        throw new SAXException("The access object is null");
2099
      }
2100
       // get rid of rev from dataId
2101 4698 daigle
       //dataId = MetacatUtil.getDocIdFromString(dataId);
2102 2245 sgarg
       //String permOrder = accessSection.getPermissionOrder();
2103
       String sql = null;
2104
       PreparedStatement pstmt = null;
2105
       sql = "INSERT INTO xml_access (docid, principal_name, permission, "
2106
               + "perm_type, perm_order, accessfileid, subtreeid) VALUES "
2107
               + " (?, ?, ?, ?, ?, ?, ?)";
2108 2161 tao
2109 2245 sgarg
       try
2110
       {
2111 2161 tao
2112 2245 sgarg
           pstmt = connection.prepareStatement(sql);
2113
           // Increase DBConnection usage count
2114
           connection.increaseUsageCount(1);
2115
           // Bind the values to the query
2116
           pstmt.setString(1, dataId);
2117 2663 sgarg
           logMetacat.info("Docid in accesstable: " + docid);
2118 2245 sgarg
           pstmt.setString(6, docid);
2119 2663 sgarg
           logMetacat.info("Accessfileid in accesstable: " + docid);
2120 2245 sgarg
           pstmt.setString(5, permOrder);
2121 2663 sgarg
           logMetacat.info("PermOder in accesstable: " + permOrder);
2122 2245 sgarg
           pstmt.setString(7, subTreeId);
2123 2663 sgarg
           logMetacat.info("subtree id in accesstable: " + subTreeId);
2124 2245 sgarg
           // if it is not top level, set s id
2125 2161 tao
2126 2245 sgarg
           //Vector accessRules = accessSection.getAccessRules();
2127
           // go through every rule
2128
           for (int i = 0; i < accessRules.size(); i++)
2129
           {
2130
               AccessRule rule = (AccessRule) accessRules.elementAt(i);
2131
               String permType = rule.getPermissionType();
2132
               int permission = rule.getPermission();
2133
               pstmt.setInt(3, permission);
2134 2663 sgarg
               logMetacat.info("permission in accesstable: "
2135
                       + permission);
2136 2245 sgarg
               pstmt.setString(4, permType);
2137 2663 sgarg
               logMetacat.info(
2138
                       "Permtype in accesstable: " + permType);
2139 2245 sgarg
               // go through every principle in rule
2140
               Vector nameVector = rule.getPrincipal();
2141
               for (int j = 0; j < nameVector.size(); j++)
2142
               {
2143
                   String prName = (String) nameVector.elementAt(j);
2144
                   pstmt.setString(2, prName);
2145 2663 sgarg
                   logMetacat.info("Principal in accesstable: "
2146
                           + prName);
2147 4140 daigle
                   logMetacat.debug("running sql: " + pstmt.toString());
2148 2245 sgarg
                   pstmt.execute();
2149
               }//for
2150
           }//for
2151
           pstmt.close();
2152
       }//try
2153
       catch (SQLException e)
2154
       {
2155
           throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
2156
                   + e.getMessage());
2157
       }//catch
2158
       finally
2159
       {
2160
           try
2161
           {
2162
               pstmt.close();
2163
           }
2164
           catch (SQLException ee)
2165
           {
2166
               throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
2167
                       + ee.getMessage());
2168
           }
2169
       }//finally
2170 2161 tao
2171 2245 sgarg
    }//writeGivenAccessRuleIntoDB
2172 2161 tao
2173 2245 sgarg
2174
    /* Delete from db all permission for resources related to @docid if any. */
2175
    private void deletePermissionsInAccessTableForDoc(String docid)
2176 2161 tao
            throws SAXException
2177
    {
2178
        Statement stmt = null;
2179
        try {
2180
            // delete all acl records for resources related to @aclid if any
2181
            stmt = connection.createStatement();
2182
            // Increase DBConnection usage count
2183
            connection.increaseUsageCount(1);
2184 2245 sgarg
            stmt.execute("DELETE FROM xml_access WHERE docid = '"
2185
                    + docid + "'");
2186 2161 tao
2187
        } catch (SQLException e) {
2188
            throw new SAXException(e.getMessage());
2189
        } finally {
2190
            try {
2191
                stmt.close();
2192
            } catch (SQLException ee) {
2193
                throw new SAXException(ee.getMessage());
2194
            }
2195
        }
2196
    }//deletePermissionsInAccessTable
2197
2198 2245 sgarg
    /* Delete access rules from xml_access for a subtee id */
2199
    private void deleteSubtreeAccessRule(String subtreeid) throws SAXException
2200
    {
2201
      Statement stmt = null;
2202
       try
2203
       {
2204
           stmt = connection.createStatement();
2205
           // Increase DBConnection usage count
2206
           connection.increaseUsageCount(1);
2207
           stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
2208
                   + docid + "' AND subtreeid ='" + subtreeid +"'");
2209
       }
2210
       catch (SQLException e)
2211
       {
2212
           throw new SAXException(e.getMessage());
2213
       }
2214
       finally
2215
       {
2216
           try
2217
           {
2218
               stmt.close();
2219
           }
2220
           catch (SQLException ee)
2221
           {
2222
               throw new SAXException(ee.getMessage());
2223
           }
2224
       }
2225
2226
    }
2227
2228
    private void deleteAllInlineDataAccessRules() throws SAXException
2229
    {
2230
      Statement stmt = null;
2231
       try
2232
       {
2233
           stmt = connection.createStatement();
2234
           // Increase DBConnection usage count
2235
           connection.increaseUsageCount(1);
2236
           stmt.execute("DELETE FROM xml_access WHERE accessfileid = '"
2237
                   + docid + "' AND subtreeid IS NOT NULL");
2238
       }
2239
       catch (SQLException e)
2240
       {
2241
           throw new SAXException(e.getMessage());
2242
       }
2243
       finally
2244
       {
2245
           try
2246
           {
2247
               stmt.close();
2248
           }
2249
           catch (SQLException ee)
2250
           {
2251
               throw new SAXException(ee.getMessage());
2252
           }
2253
       }
2254
2255
    }
2256
2257 2161 tao
    /*
2258
     * In order to make sure only usr has "all" permission can update access
2259
     * subtree in eml document we need to keep access subtree info in
2260
     * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
2261
     */
2262 2245 sgarg
    private void writeAccessSubTreeIntoDB(AccessSection accessSection)
2263
                                          throws SAXException
2264 2161 tao
    {
2265 2245 sgarg
        if (accessSection == null)
2266
        {
2267 2161 tao
2268 2663 sgarg
          logMetacat.info("Access object is null and tried to write "+
2269
                                   "into access subtree table");
2270 2245 sgarg
          throw new SAXException("The access object is null to write access " +
2271
                                 "sbutree");
2272
        }
2273
2274 2161 tao
        String sql = null;
2275
        PreparedStatement pstmt = null;
2276
        sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
2277
                + "subtreeid, startnodeid, endnodeid) VALUES "
2278
                + " (?, ?, ?, ?, ?, ?)";
2279 2245 sgarg
        try
2280
        {
2281 2161 tao
2282
            pstmt = connection.prepareStatement(sql);
2283
            // Increase DBConnection usage count
2284
            connection.increaseUsageCount(1);
2285 2245 sgarg
            String level = accessSection.getControlLevel();
2286
            long startNodeId = -1;
2287
            if (level != null && level.equals(DATAACCESSLEVEL))
2288
            {
2289
              // for addtional access module the start node id should be
2290
              // descirbes element id
2291
              startNodeId = accessSection.getStartedDescribesNodeId();
2292
              // if in additional access, there is not describes element,
2293
              // in this senario, describesNodeId will be -1. Then we should
2294
              // the start access element id
2295
              if (startNodeId == -1)
2296
              {
2297
                startNodeId = accessSection.getStartNodeId();
2298
              }
2299
            }
2300
            else
2301
            {
2302
                startNodeId = accessSection.getStartNodeId();
2303
            }
2304
2305 2161 tao
            long endNodeId = accessSection.getEndNodeId();
2306
            String sectionId = accessSection.getSubTreeId();
2307 2245 sgarg
2308
            if (startNodeId ==-1 || endNodeId == -1)
2309
            {
2310
              throw new SAXException("Don't find start node or end node id " +
2311
                                      "for the access subtee");
2312
2313
            }
2314
2315 2161 tao
            // Bind the values to the query
2316
            pstmt.setString(1, docid);
2317 2663 sgarg
            logMetacat.info("Docid in access-subtreetable: " + docid);
2318 2608 tao
            pstmt.setInt(2, (new Integer(revision)).intValue());
2319 2663 sgarg
            logMetacat.info("rev in accesssubtreetable: " + revision);
2320 2161 tao
            pstmt.setString(3, level);
2321 2663 sgarg
            logMetacat.info("contorl level in access-subtree table: "
2322
                    + level);
2323 2161 tao
            pstmt.setString(4, sectionId);
2324 2663 sgarg
            logMetacat.info("Subtree id in access-subtree table: "
2325
                    + sectionId);
2326 2161 tao
            pstmt.setLong(5, startNodeId);
2327 2663 sgarg
            logMetacat.info("Start node id is: " + startNodeId);
2328 2161 tao
            pstmt.setLong(6, endNodeId);
2329 2663 sgarg
            logMetacat.info("End node id is: " + endNodeId);
2330 4140 daigle
            logMetacat.debug("running sql: " + pstmt.toString());
2331 2161 tao
            pstmt.execute();
2332
            pstmt.close();
2333
        }//try
2334 2245 sgarg
        catch (SQLException e)
2335
        {
2336 2161 tao
            throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
2337
                    + e.getMessage());
2338
        }//catch
2339 2245 sgarg
        finally
2340
        {
2341
            try
2342
            {
2343 2161 tao
                pstmt.close();
2344 2245 sgarg
            }
2345
            catch (SQLException ee)
2346
            {
2347 2161 tao
                throw new SAXException(
2348
                        "EMLSAXHandler.writeAccessSubTreeIntoDB(): "
2349
                                + ee.getMessage());
2350
            }
2351
        }//finally
2352
2353
    }//writeAccessSubtreeIntoDB
2354
2355
    /* Delete every access subtree record from xml_accesssubtree. */
2356
    private void deleteAccessSubTreeRecord(String docId) throws SAXException
2357
    {
2358
        Statement stmt = null;
2359
        try {
2360
            // delete all acl records for resources related to @aclid if any
2361
            stmt = connection.createStatement();
2362
            // Increase DBConnection usage count
2363 4140 daigle
            connection.increaseUsageCount(1);
2364
            logMetacat.debug("running sql: DELETE FROM xml_accesssubtree WHERE docid = '"
2365
                    + docId + "'");
2366 2161 tao
            stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '"
2367
                    + docId + "'");
2368
2369
        } catch (SQLException e) {
2370
            throw new SAXException(e.getMessage());
2371
        } finally {
2372
            try {
2373
                stmt.close();
2374
            } catch (SQLException ee) {
2375
                throw new SAXException(ee.getMessage());
2376
            }
2377
        }
2378
    }//deleteAccessSubTreeRecord
2379
2380
    // open a file writer for writing inline data to file
2381
    private FileWriter createInlineDataFileWriter(String fileName)
2382
            throws SAXException
2383
    {
2384
        FileWriter writer = null;
2385 4080 daigle
        String path;
2386
        try {
2387
        	 path = PropertyService.getProperty("application.inlinedatafilepath");
2388
        } catch (PropertyNotFoundException pnfe) {
2389
            throw new SAXException(pnfe.getMessage());
2390
        }
2391 2161 tao
        /*
2392
         * File inlineDataDirectory = new File(path);
2393
         */
2394
        String newFile = path + "/" + fileName;
2395 2663 sgarg
        logMetacat.info("inline file name: " + newFile);
2396 2161 tao
        try {
2397
            // true means append
2398
            writer = new FileWriter(newFile, true);
2399
        } catch (IOException ioe) {
2400
            throw new SAXException(ioe.getMessage());
2401
        }
2402
        return writer;
2403
    }
2404
2405
    // write inline data into file system and return file name(without path)
2406
    private void writeInlineDataIntoFile(FileWriter writer, StringBuffer data)
2407
            throws SAXException
2408
    {
2409
        try {
2410
            writer.write(data.toString());
2411
            writer.flush();
2412
        } catch (Exception e) {
2413
            throw new SAXException(e.getMessage());
2414
        }
2415
    }
2416
2417 2245 sgarg
2418
2419 2161 tao
    /*
2420
     * In eml2, the inline data wouldn't store in db, it store in file system
2421
     * The db stores file name(without path). We got the old file name from db
2422
     * and compare to the new in line data file
2423
     */
2424
    public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2425
            throws McdbException
2426
    {
2427
        // this method need to be testing
2428
        boolean same = true;
2429
        String data = null;
2430
        try {
2431 4080 daigle
        	String path = PropertyService.getProperty("application.inlinedatafilepath");
2432
			// the new file name will look like path/docid.rev.2
2433
			File inlineDataDirectory = new File(path);
2434
			File oldDataFile = new File(inlineDataDirectory, oldFileName);
2435
			File newDataFile = new File(inlineDataDirectory, newFileName);
2436
2437 2161 tao
            FileReader oldFileReader = new FileReader(oldDataFile);
2438
            BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2439
            FileReader newFileReader = new FileReader(newDataFile);
2440
            BufferedReader newStringReader = new BufferedReader(newFileReader);
2441
            // read first line of data
2442
            String oldString = oldStringReader.readLine();
2443
            String newString = newStringReader.readLine();
2444
2445
            // at the end oldstring will be null
2446
            while (oldString != null) {
2447
                oldString = oldStringReader.readLine();
2448
                newString = newStringReader.readLine();
2449
                if (!oldString.equals(newString)) {
2450
                    same = false;
2451
                    break;
2452
                }
2453
            }
2454
2455
            // if oldString is null but newString is not null, they are same
2456
            if (same) {
2457
                if (newString != null) {
2458
                    same = false;
2459
                }
2460
            }
2461
2462
        } catch (Exception e) {
2463
            throw new McdbException(e.getMessage());
2464
        }
2465 2663 sgarg
        logMetacat.info("the inline data retrieve from file: " + data);
2466 2161 tao
        return same;
2467
    }
2468
2469 2245 sgarg
   /*
2470 4080 daigle
	 * Copy a old line file to a new inline file
2471
	 */
2472
	public void copyInlineFile(String inlineDistributionId, String newFileName)
2473
			throws SAXException {
2474
		if (inlineDistributionId == null || newFileName == null) {
2475
			throw new SAXException("Could not copy inline file from old one to new "
2476
					+ "one!");
2477
		}
2478
		// get old file id from previousUnreadable data object
2479
		String oldInlineInternalFileName = (String) previousUnreadableInlineDataObjectHash
2480
				.get(inlineDistributionId);
2481 2278 sgarg
2482 4080 daigle
		if (oldInlineInternalFileName == null
2483
				|| oldInlineInternalFileName.trim().equals("")) {
2484
			throw new SAXException("Could not copy inline file from old one to new "
2485
					+ "one because can't find old file name");
2486
		}
2487
		logMetacat.info("in handle inline data");
2488
		logMetacat.info("the inline data file name from xml_access is: "
2489
				+ oldInlineInternalFileName);
2490 2245 sgarg
2491 4080 daigle
		FileReader oldFileReader = null;
2492
		FileWriter newFileWriter = null;
2493
		try {
2494
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2495
			// the new file name will look like path/docid.rev.2
2496
			File inlineDataDirectory = new File(path);
2497
			File oldDataFile = new File(inlineDataDirectory, oldInlineInternalFileName);
2498
			File newDataFile = new File(inlineDataDirectory, newFileName);
2499 2245 sgarg
2500 4080 daigle
			oldFileReader = new FileReader(oldDataFile);
2501
			newFileWriter = new FileWriter(newDataFile);
2502
			char[] buf = new char[4 * 1024]; // 4K buffer
2503
			int b = oldFileReader.read(buf);
2504
			while (b != -1) {
2505
				newFileWriter.write(buf, 0, b);
2506
				b = oldFileReader.read(buf);
2507
			}
2508
		} catch (Exception e) {
2509
			throw new SAXException(e.getMessage());
2510
		} finally {
2511
			if (oldFileReader != null) {
2512
				try {
2513
					oldFileReader.close();
2514
				} catch (Exception ee) {
2515
					throw new SAXException(ee.getMessage());
2516
				}
2517 2245 sgarg
2518 4080 daigle
			}
2519
			if (newFileWriter != null) {
2520
				try {
2521
					newFileWriter.close();
2522
				} catch (Exception ee) {
2523
					throw new SAXException(ee.getMessage());
2524
				}
2525 2245 sgarg
2526 4080 daigle
			}
2527
		}
2528
	}
2529 2245 sgarg
2530
2531 2161 tao
    // if xml file failed to upload, we need to call this method to delete
2532
    // the inline data already in file system
2533 4080 daigle
    public void deleteInlineFiles() throws SAXException
2534 2161 tao
    {
2535
        if (!inlineFileIDList.isEmpty()) {
2536
            for (int i = 0; i < inlineFileIDList.size(); i++) {
2537
                String fileName = (String) inlineFileIDList.elementAt(i);
2538
                deleteInlineDataFile(fileName);
2539
            }
2540
        }
2541
    }
2542
2543
    /* delete the inline data file */
2544 4080 daigle
    private void deleteInlineDataFile(String fileName) throws SAXException
2545 2161 tao
    {
2546 4080 daigle
    	String path;
2547
    	try {
2548
    		path = PropertyService.getProperty("application.inlinedatafilepath");
2549
    	} catch (PropertyNotFoundException pnfe) {
2550
    		throw new SAXException ("Could not find inline data file path: "
2551
    				+ pnfe.getMessage());
2552
    	}
2553 2161 tao
        File inlineDataDirectory = new File(path);
2554
        File newFile = new File(inlineDataDirectory, fileName);
2555
        newFile.delete();
2556
2557
    }
2558
2559
    /*
2560 4080 daigle
	 * In eml2, the inline data wouldn't store in db, it store in file system
2561
	 * The db stores file name(without path).
2562
	 */
2563
	public static Reader readInlineDataFromFileSystem(String fileName)
2564
			throws McdbException {
2565
		// BufferedReader stringReader = null;
2566
		FileReader fileReader = null;
2567
		try {
2568
			String path = PropertyService.getProperty("application.inlinedatafilepath");
2569
			// the new file name will look like path/docid.rev.2
2570
			File inlineDataDirectory = new File(path);
2571
			File dataFile = new File(inlineDataDirectory, fileName);
2572 2161 tao
2573 4080 daigle
			fileReader = new FileReader(dataFile);
2574
			// stringReader = new BufferedReader(fileReader);
2575
		} catch (Exception e) {
2576
			throw new McdbException(e.getMessage());
2577
		}
2578
		// return stringReader;
2579
		return fileReader;
2580
	}
2581
2582 2161 tao
    /* Delete relations */
2583
    private void deleteRelations() throws SAXException
2584
    {
2585
        PreparedStatement pStmt = null;
2586
        String sql = "DELETE FROM xml_relation where docid =?";
2587
        try {
2588
            pStmt = connection.prepareStatement(sql);
2589
            //bind variable
2590
            pStmt.setString(1, docid);
2591
            //execute query
2592
            pStmt.execute();
2593
            pStmt.close();
2594
        }//try
2595
        catch (SQLException e) {
2596
            throw new SAXException("EMLSAXHandler.deleteRelations(): "
2597
                    + e.getMessage());
2598
        }//catch
2599
        finally {
2600
            try {
2601
                pStmt.close();
2602
            }//try
2603
            catch (SQLException ee) {
2604
                throw new SAXException("EMLSAXHandler.deleteRelations: "
2605
                        + ee.getMessage());
2606
            }//catch
2607
        }//finally
2608
    }
2609
2610 2165 tao
    /* Write an online data file id into xml_relation table. The dataId shouldnot
2611
     * have the revision
2612
     */
2613 2161 tao
    private void writeOnlineDataFileIdIntoRelationTable(String dataId)
2614
            throws SAXException
2615
    {
2616
        PreparedStatement pStmt = null;
2617
        String sql = "INSERT into xml_relation (docid, packagetype, subject, "
2618
                + "relationship, object) values (?, ?, ?, ?, ?)";
2619
        try {
2620
            pStmt = connection.prepareStatement(sql);
2621
            //bind variable
2622
            pStmt.setString(1, docid);
2623 2397 tao
            pStmt.setString(2, doctype);
2624 2161 tao
            pStmt.setString(3, docid);
2625
            pStmt.setString(4, RELATION);
2626
            pStmt.setString(5, dataId);
2627
            //execute query
2628
            pStmt.execute();
2629
            pStmt.close();
2630
        }//try
2631
        catch (SQLException e) {
2632
            throw new SAXException(
2633
                    "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2634
                            + e.getMessage());
2635
        }//catch
2636
        finally {
2637
            try {
2638
                pStmt.close();
2639
            }//try
2640
            catch (SQLException ee) {
2641
                throw new SAXException(
2642
                        "EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
2643
                                + ee.getMessage());
2644
            }//catch
2645
        }//finally
2646
2647
    }//writeOnlineDataFileIdIntoRelationTable
2648
2649 2165 tao
    /*
2650
     * This method will handle data file in online url. If the data file is in
2651 2245 sgarg
     * ecogrid protocol, then the datafile identifier(without rev) be returned.
2652
     * otherwise, null will be returned.
2653 2165 tao
     * If the data file doesn't exsit in xml_documents or
2654
     * xml_revision table, or the user has all permission to the data file if
2655 2245 sgarg
     * the docid already existed, the data file id (without rev)will be returned
2656 2165 tao
     * NEED to do:
2657
     * We should also need to implement http and ftp. Those
2658
     * external files should be download and assign a data file id to it.
2659
     */
2660 2245 sgarg
    private String handleOnlineUrlDataFile(String url) throws SAXException
2661 2165 tao
    {
2662 2663 sgarg
      logMetacat.warn("The url is "+ url);
2663 2245 sgarg
      String docid = null;
2664 2165 tao
      // if the url is not a ecogrid protocol, null will be getten
2665
      String accessionNumber =
2666 5025 daigle
    	  DocumentUtil.getAccessionNumberFromEcogridIdentifier(url);
2667 2165 tao
      if (accessionNumber != null)
2668
      {
2669
        // handle ecogrid protocol
2670
        // get rid of revision number to get the docid.
2671 5025 daigle
        docid = DocumentUtil.getDocIdFromAccessionNumber(accessionNumber);
2672 2165 tao
        onlineDataFileIdInRelationVector.add(docid);
2673
        try
2674
        {
2675
2676
          if (!AccessionNumber.accNumberUsed(docid))
2677
          {
2678 2245 sgarg
            return docid;
2679 2165 tao
          }
2680
          PermissionController controller = new
2681
              PermissionController(accessionNumber);
2682
          if (controller.hasPermission(
2683
              user, groups, AccessControlInterface.ALLSTRING))
2684
          {
2685 2245 sgarg
            return docid;
2686 2165 tao
          }
2687 2245 sgarg
          else
2688
          {
2689 4856 daigle
            throw new SAXException("User: " + user + " does not have permission to update " +
2690
                  "access rules for data file "+ docid);
2691 2245 sgarg
          }
2692 2165 tao
        }//try
2693
        catch(Exception e)
2694
        {
2695 2663 sgarg
          logMetacat.error("Error in " +
2696 2165 tao
                                "Eml200SAXHanlder.handleOnlineUrlDataFile is " +
2697 2663 sgarg
                                 e.getMessage());
2698 2165 tao
          throw new SAXException(e.getMessage());
2699
        }
2700
      }
2701 2245 sgarg
      return docid;
2702 2165 tao
    }
2703
2704 2245 sgarg
    private void compareElementNameSpaceAttributes(Stack unchangableNodeStack,
2705
            Hashtable nameSpaces, Attributes attributes, String localName,
2706
            String error) throws SAXException
2707
    {
2708
        //Get element subtree node stack (element node)
2709
        NodeRecord elementNode = null;
2710
        try {
2711
            elementNode = (NodeRecord) unchangableNodeStack.pop();
2712
        } catch (EmptyStackException ee) {
2713 2663 sgarg
            logMetacat.error("Node stack is empty for element data");
2714 2245 sgarg
            throw new SAXException(error);
2715
        }
2716 2663 sgarg
        logMetacat.info("current node type from xml is ELEMENT");
2717
        logMetacat.info("node type from stack: "
2718
                + elementNode.getNodeType());
2719
        logMetacat.info("node name from xml document: " + localName);
2720
        logMetacat.info("node name from stack: "
2721
                + elementNode.getNodeName());
2722
        logMetacat.info("node data from stack: "
2723
                + elementNode.getNodeData());
2724
        logMetacat.info("node id is: " + elementNode.getNodeId());
2725 2245 sgarg
        // if this node is not element or local name not equal or name space
2726
        // not
2727
        // equals, throw an exception
2728
        if (!elementNode.getNodeType().equals("ELEMENT")
2729
                || !localName.equals(elementNode.getNodeName()))
2730
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
2731
        {
2732 2663 sgarg
            logMetacat.info("Inconsistence happend: ");
2733
            logMetacat.info("current node type from xml is ELEMENT");
2734
            logMetacat.info("node type from stack: "
2735
                    + elementNode.getNodeType());
2736
            logMetacat.info("node name from xml document: "
2737
                    + localName);
2738
            logMetacat.info("node name from stack: "
2739
                    + elementNode.getNodeName());
2740
            logMetacat.info("node data from stack: "
2741
                    + elementNode.getNodeData());
2742
            logMetacat.info("node id is: " + elementNode.getNodeId());
2743 2245 sgarg
            throw new SAXException(error);
2744
        }
2745
2746
        //compare namespace
2747
        Enumeration nameEn = nameSpaces.keys();
2748
        while (nameEn.hasMoreElements()) {
2749
            //Get namespacke node stack (element node)
2750
            NodeRecord nameNode = null;
2751
            try {
2752
                nameNode = (NodeRecord) unchangableNodeStack.pop();
2753
            } catch (EmptyStackException ee) {
2754 2663 sgarg
                logMetacat.error(
2755
                        "Node stack is empty for namespace data");
2756 2245 sgarg
                throw new SAXException(error);
2757
            }
2758
2759
            String prefixName = (String) nameEn.nextElement();
2760
            String nameSpaceUri = (String) nameSpaces.get(prefixName);
2761
            if (!nameNode.getNodeType().equals("NAMESPACE")
2762
                    || !prefixName.equals(nameNode.getNodeName())
2763
                    || !nameSpaceUri.equals(nameNode.getNodeData())) {
2764 2663 sgarg
                logMetacat.info("Inconsistence happend: ");
2765
                logMetacat.info(
2766
                        "current node type from xml is NAMESPACE");
2767
                logMetacat.info("node type from stack: "
2768
                        + nameNode.getNodeType());
2769
                logMetacat.info("current node name from xml is: "
2770
                        + prefixName);
2771
                logMetacat.info("node name from stack: "
2772
                        + nameNode.getNodeName());
2773
                logMetacat.info("current node data from xml is: "
2774
                        + nameSpaceUri);
2775
                logMetacat.info("node data from stack: "
2776
                        + nameNode.getNodeData());
2777
                logMetacat.info("node id is: " + nameNode.getNodeId());
2778 2245 sgarg
                throw new SAXException(error);
2779
            }
2780
2781
        }//while
2782
2783
        //compare attributes
2784
        for (int i = 0; i < attributes.getLength(); i++) {
2785
            NodeRecord attriNode = null;
2786
            try {
2787
                attriNode = (NodeRecord) unchangableNodeStack.pop();
2788
2789
            } catch (EmptyStackException ee) {
2790 2663 sgarg
                logMetacat.error(
2791
                        "Node stack is empty for attribute data");
2792 2245 sgarg
                throw new SAXException(error);
2793
            }
2794
            String attributeName = attributes.getQName(i);
2795
            String attributeValue = attributes.getValue(i);
2796 2663 sgarg
            logMetacat.info(
2797
                    "current node type from xml is ATTRIBUTE ");
2798
            logMetacat.info("node type from stack: "
2799
                    + attriNode.getNodeType());
2800
            logMetacat.info("current node name from xml is: "
2801
                    + attributeName);
2802
            logMetacat.info("node name from stack: "
2803
                    + attriNode.getNodeName());
2804
            logMetacat.info("current node data from xml is: "
2805
                    + attributeValue);
2806
            logMetacat.info("node data from stack: "
2807
                    + attriNode.getNodeData());
2808
            logMetacat.info("node id  is: " + attriNode.getNodeId());
2809 2245 sgarg
2810
            if (!attriNode.getNodeType().equals("ATTRIBUTE")
2811
                    || !attributeName.equals(attriNode.getNodeName())
2812
                    || !attributeValue.equals(attriNode.getNodeData())) {
2813 2663 sgarg
                logMetacat.info("Inconsistence happend: ");
2814
                logMetacat.info(
2815
                        "current node type from xml is ATTRIBUTE ");
2816
                logMetacat.info("node type from stack: "
2817
                        + attriNode.getNodeType());
2818
                logMetacat.info("current node name from xml is: "
2819
                        + attributeName);
2820
                logMetacat.info("node name from stack: "
2821
                        + attriNode.getNodeName());
2822
                logMetacat.info("current node data from xml is: "
2823
                        + attributeValue);
2824
                logMetacat.info("node data from stack: "
2825
                        + attriNode.getNodeData());
2826
                logMetacat.info("node is: " + attriNode.getNodeId());
2827 2245 sgarg
                throw new SAXException(error);
2828
            }
2829
        }//for
2830
2831
    }
2832
2833
    /* mehtod to compare current text node and node in db */
2834
    private void compareTextNode(Stack nodeStack, StringBuffer text,
2835
            String error) throws SAXException
2836
    {
2837
        NodeRecord node = null;
2838
        //get node from current stack
2839
        try {
2840
            node = (NodeRecord) nodeStack.pop();
2841
        } catch (EmptyStackException ee) {
2842 2663 sgarg
            logMetacat.error(
2843
                    "Node stack is empty for text data in startElement");
2844 2245 sgarg
            throw new SAXException(error);
2845
        }
2846 2663 sgarg
        logMetacat.info(
2847
                "current node type from xml is TEXT in start element");
2848
        logMetacat.info("node type from stack: " + node.getNodeType());
2849
        logMetacat.info("current node data from xml is: "
2850
                + text.toString());
2851
        logMetacat.info("node data from stack: " + node.getNodeData());
2852
        logMetacat.info("node name from stack: " + node.getNodeName());
2853
        logMetacat.info("node is: " + node.getNodeId());
2854 2245 sgarg
        if (!node.getNodeType().equals("TEXT")
2855
                || !(text.toString()).equals(node.getNodeData())) {
2856 2663 sgarg
            logMetacat.info("Inconsistence happend: ");
2857
            logMetacat.info(
2858
                    "current node type from xml is TEXT in start element");
2859
            logMetacat.info("node type from stack: "
2860
                    + node.getNodeType());
2861
            logMetacat.info("current node data from xml is: "
2862
                    + text.toString());
2863
            logMetacat.info("node data from stack: "
2864
                    + node.getNodeData());
2865
            logMetacat.info("node name from stack: "
2866
                    + node.getNodeName());
2867
            logMetacat.info("node is: " + node.getNodeId());
2868 2245 sgarg
            throw new SAXException(error);
2869
        }//if
2870
    }
2871
2872
    /* Comparet comment from xml and db */
2873
    private void compareCommentNode(Stack nodeStack, String string, String error)
2874
            throws SAXException
2875
    {
2876
        NodeRecord node = null;
2877
        try {
2878
            node = (NodeRecord) nodeStack.pop();
2879
        } catch (EmptyStackException ee) {
2880 2663 sgarg
            logMetacat.error("the stack is empty for comment data");
2881 2245 sgarg
            throw new SAXException(error);
2882
        }
2883 2663 sgarg
        logMetacat.info("current node type from xml is COMMENT");
2884
        logMetacat.info("node type from stack: " + node.getNodeType());
2885
        logMetacat.info("current node data from xml is: " + string);
2886
        logMetacat.info("node data from stack: " + node.getNodeData());
2887
        logMetacat.info("node is from stack: " + node.getNodeId());
2888 2245 sgarg
        // if not consistent terminate program and throw a exception
2889
        if (!node.getNodeType().equals("COMMENT")
2890
                || !string.equals(node.getNodeData())) {
2891 2663 sgarg
            logMetacat.info("Inconsistence happend: ");
2892
            logMetacat.info("current node type from xml is COMMENT");
2893
            logMetacat.info("node type from stack: "
2894
                    + node.getNodeType());
2895
            logMetacat.info(
2896
                    "current node data from xml is: " + string);
2897
            logMetacat.info("node data from stack: "
2898
                    + node.getNodeData());
2899
            logMetacat.info("node is from stack: " + node.getNodeId());
2900 2245 sgarg
            throw new SAXException(error);
2901
        }//if
2902
    }
2903
2904
    /* Compare whitespace from xml and db */
2905
   private void compareWhiteSpace(Stack nodeStack, String string, String error)
2906
           throws SAXException
2907
   {
2908
       NodeRecord node = null;
2909
       try {
2910
           node = (NodeRecord) nodeStack.pop();
2911
       } catch (EmptyStackException ee) {
2912 2663 sgarg
           logMetacat.error("the stack is empty for whitespace data");
2913 2245 sgarg
           throw new SAXException(error);
2914
       }
2915
       if (!node.getNodeType().equals("TEXT")
2916
               || !string.equals(node.getNodeData())) {
2917 2663 sgarg
           logMetacat.info("Inconsistence happend: ");
2918
           logMetacat.info(
2919
                   "current node type from xml is WHITESPACE TEXT");
2920
           logMetacat.info("node type from stack: "
2921
                   + node.getNodeType());
2922
           logMetacat.info(
2923
                   "current node data from xml is: " + string);
2924
           logMetacat.info("node data from stack: "
2925
                   + node.getNodeData());
2926
           logMetacat.info("node is from stack: " + node.getNodeId());
2927 2245 sgarg
           throw new SAXException(error);
2928
       }//if
2929
   }
2930
2931
2932
2933 2161 tao
}