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