Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author: jones $'
11
 *     '$Date: 2004-03-30 13:35:19 -0800 (Tue, 30 Mar 2004) $'
12
 * '$Revision: 2076 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31
import java.io.BufferedReader;
32
import java.io.File;
33
import java.io.FileReader;
34
import java.io.FileWriter;
35
import java.io.IOException;
36
import java.io.Reader;
37
import java.sql.PreparedStatement;
38
import java.sql.ResultSet;
39
import java.sql.SQLException;
40
import java.sql.Statement;
41
import java.util.EmptyStackException;
42
import java.util.Enumeration;
43
import java.util.Hashtable;
44
import java.util.Stack;
45
import java.util.Vector;
46

    
47
import org.xml.sax.Attributes;
48
import org.xml.sax.SAXException;
49

    
50
/**
51
 * A database aware Class implementing callback bethods for the SAX parser to
52
 * call when processing the XML stream and generating events
53
 */
54
public class EmlSAXHandler extends DBSAXHandler implements 
55
                                                      AccessControlInterface
56
{
57
   private Vector allowRules = new Vector();
58
   private Vector denyRules = new Vector();
59
   private String documentId = null;
60
   private Vector subDocumentIdList = new Vector();
61
   private boolean processTopLeverAccess = false;
62
   private boolean processAdditionalAccess = false;
63
   private boolean processOtherAccess = false;
64
   private AccessSection accessObject= null;
65
   private AccessRule accessRule = null;
66
   private Vector accessObjectList = new Vector(); // store every access rule
67
   private Hashtable topLevelAccessControlMap = new Hashtable();
68
   private Hashtable additionalAccessControlMap = new Hashtable();// store 
69
                                                 //subtree access for single
70
                                                 // additionalmetacat
71
   private Vector additionalAccessMapList = new Vector();// store maps for 
72
                                                       // every addionalmetadata
73
   private Vector describesId = new Vector(); // store the ids in
74
                                      //additionalmetadata/describes
75
   private Stack subTreeInfoStack = new Stack();
76
   private Vector subTreeList = new Vector();// store the final subtree
77
   private Hashtable unChangableSubTreeHash = new Hashtable();
78
   private Stack currentUnChangedableSubtreeNodeStack =new Stack();
79
   private boolean startCriticalSubTree = false;
80
   private boolean firstElementForCriticalSubTree = false;
81
   private String firstElementNameForCriticalSubTree;
82
   private boolean needCheckingAccessModule = false;
83
   private Vector unChangableAccessSubTreeVector = new Vector();
84
   private Stack currentUnchangableAccessModuleNodeStack = new Stack();
85
   private AccessSection topAccessSection;
86
   
87
   // we need an another stack to store the access node which we pull out just
88
   // from xml. If a reference happend, we can use the stack the compare nodes
89
   private Stack storedAccessNodeStack = new Stack();
90
   // vector stored the data file id which will be write into relation table
91
   private Vector onlineDataFileIdVector = new Vector();
92
   // Indicator of inline data
93
   private boolean handleInlineData = false;
94
   private Stack   inlineDataNodeStack = null;
95
   private Hashtable inlineDataNameSpace = null;
96
   private FileWriter inlineDataFileWriter = null;
97
   private String inlineDataFileName = null;
98
   private int inLineDataIndex = 0;
99
   private Vector inlineFileIDList = new Vector();
100
 
101
   // Constant
102
   private static final String EML ="eml";
103
   private static final String DESCRIBES = "describes";
104
   private static final String ADDITIONALMETADATA = "additionalMetadata";
105
   private static final String ORDER = "order";
106
   private static final String ID ="id";
107
   private static final String REFERENCES = "references";
108
   public  static final String INLINE = "inline";
109
   private static final String ONLINE = "online";
110
   private static final String URL    = "url";
111
   private static final String PERMISSIONERROR ="User try to update a subtree"+
112
                               " which it doesn't have write permission!";
113
   private static final String UPDATEACCESSERROR = "User try to update a " + 
114
                      "access module which it doesn't have \"ALL\" permission!";
115
   private static final String TOPLEVEL = "top";
116
   private static final String SUBTREELEVEL ="subtree";
117
   private static final String RELATION = "Provides info for";
118
  
119
    /** Construct an instance of the handler class
120
    * In this constructor, user can specify the version need to upadate
121
    *
122
    * @param conn the JDBC connection to which information is written
123
    * @param action - "INSERT" or "UPDATE"
124
    * @param docid to be inserted or updated into JDBC connection
125
    * @param revision, the user specified the revision need to be update
126
    * @param user the user connected to MetaCat servlet and owns the document
127
    * @param groups the groups to which user belongs
128
    * @param pub flag for public "read" access on document
129
    * @param serverCode the serverid from xml_replication on which this document
130
    *        resides.
131
    *
132
    */
133
   public EmlSAXHandler(DBConnection conn, String action, String docid,
134
     String revision, String user, String[] groups, String pub, int serverCode)
135
                              throws SAXException
136
   {
137
     super(conn, action, docid, revision, user, groups, pub, serverCode);
138
     // Get the unchangable subtrees (user doesn't have write permission)
139
     try
140
     {
141
       PermissionController control = new PermissionController(docid+
142
                             MetaCatUtil.getOption("accNumSeparator")+revision);
143
       //unChangableSubTreeHash = getUnchangableSubTree(control, user, groups);
144
       
145
       
146
       //If the action is update and user doesn't have "ALL" permission
147
       // we need to check if user update access subtree
148
       if (action.equals("UPDATE") && 
149
         !control.hasPermission(user, groups, AccessControlInterface.ALLSTRING))
150
       {
151
         needCheckingAccessModule = true;
152
         unChangableAccessSubTreeVector = getAccessSubTreeListFromDB();
153
       }
154
     }
155
     catch (Exception e)
156
     {
157
       throw new SAXException(e.getMessage());
158
     }
159
   }
160
   
161
   /* Pass a permission control and get the list of unchangable subtree*/
162
   private Hashtable getUnchangableSubTree(PermissionController controller,
163
                                           String user, String[]groups)
164
                                           throws Exception
165
   {
166
     Hashtable list = null;
167
     Hashtable result = new Hashtable();
168
     // get unwritable sutree from controller
169
     list = controller.hasUnaccessableSubTree(user, groups, 
170
                                          AccessControlInterface.WRITESTRING);
171
      if (list != null)
172
      {
173
       
174
         Enumeration en = list.elements();
175
         while (en.hasMoreElements())
176
         {
177
           // Get  a subtree without node record list
178
           SubTree treeWithoutStack = (SubTree)en.nextElement();
179
           String subTreeId   = treeWithoutStack.getSubTreeId();
180
           MetaCatUtil.debugMessage("unchangable subtree id: " + subTreeId, 40);
181
           long   startNodeId = treeWithoutStack.getStartNodeId();
182
           MetaCatUtil.debugMessage("unchangable subtree startnodeid: " +
183
                                    startNodeId, 40);
184
           long   endNodeId   = treeWithoutStack.getEndNodeId();
185
           MetaCatUtil.debugMessage("unchangable subtree endnodeid: " +
186
                                     endNodeId, 40);
187
           // Get a subtree has the nodelist
188
           SubTree tree = new SubTree(docid, subTreeId, startNodeId, endNodeId);
189
           // add this tree to the result
190
           result.put(subTreeId, tree);
191
         
192
          }//while
193
      
194
      }//if
195
      
196
      return result;
197
   }
198
   
199
   
200
   /*
201
    * Get the subtree node info from xml_accesssubtree table
202
    */
203
   private Vector getAccessSubTreeListFromDB() throws Exception
204
   {
205
      Vector result = new Vector();
206
      PreparedStatement pstmt = null;
207
      ResultSet rs = null;
208
      String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid " + 
209
                   "FROM xml_accesssubtree WHERE docid like ? " +
210
                   "ORDER BY startnodeid ASC";
211
              
212
      try 
213
      {
214
     
215
        pstmt = connection.prepareStatement(sql);
216
        // Increase DBConnection usage count
217
        connection.increaseUsageCount(1);
218
        // Bind the values to the query
219
        pstmt.setString(1, docid);
220
        pstmt.execute();
221
        
222
        // Get result set
223
        rs = pstmt.getResultSet();
224
        while (rs.next())
225
        {
226
          String level = rs.getString(1);
227
          String sectionId = rs.getString(2);
228
          long startNodeId = rs.getLong(3);
229
          long endNodeId = rs.getLong(4);
230
          // create a new access section
231
          AccessSection accessObj = new AccessSection();
232
          accessObj.setControlLevel(level);
233
          accessObj.setDocId(docid);
234
          accessObj.setSubTreeId(sectionId);
235
          accessObj.setStartNodeId(startNodeId);
236
          accessObj.setEndNodeId(endNodeId); 
237
          Stack nodeStack = accessObj.getSubTreeNodeList();
238
          accessObj.setSubTreeNodeStack(nodeStack);
239
          // add this access obj into vector
240
          result.add(accessObj);
241
          // Get the top level access subtree control
242
          if ( level != null && level.equals(TOPLEVEL))
243
          {
244
            topAccessSection = accessObj;
245
          }
246
        }
247
        pstmt.close();
248
      }//try 
249
      catch (SQLException e) 
250
      {
251
        throw new 
252
        SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): " + 
253
                      e.getMessage());
254
      }//catch
255
      finally
256
      {
257
        try
258
        {
259
          pstmt.close();
260
        }
261
        catch(SQLException ee)
262
        {
263
          throw new 
264
          SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): " + 
265
          ee.getMessage());
266
        }
267
      }//finally
268
      return result;
269
   }
270
   /** SAX Handler that is called at the start of each XML element */
271
   public void startElement(String uri, String localName,
272
                            String qName, Attributes atts)
273
               throws SAXException 
274
  {
275
    // for element <eml:eml...> qname is "eml:eml", local name is "eml"            
276
    // for element <acl....> both qname and local name is "eml"
277
    // uri is namesapce
278
    MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
279
    MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
280
    MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
281
     
282
     
283
    DBSAXNode parentNode = null;
284
    DBSAXNode currentNode = null;
285
   
286
   if (!handleInlineData)
287
   {
288
     // Get a reference to the parent node for the id
289
     try 
290
     {
291
       parentNode = (DBSAXNode)nodeStack.peek();
292
     } 
293
     catch (EmptyStackException e) 
294
     {
295
       parentNode = null;
296
     }
297
     
298
     //start handle inline data
299
     if (localName.equals(INLINE))
300
     {
301
       handleInlineData = true;
302
       inLineDataIndex ++;
303
       //intitialize namespace hash for in line data
304
       inlineDataNameSpace = new Hashtable();
305
       //initialize file writer
306
       String docidWithoutRev = MetaCatUtil.getDocIdFromString(docid);
307
       String seperator = MetaCatUtil.getOption("accNumSeparator");
308
       // the new file name will look like docid.rev.2
309
       inlineDataFileName = docidWithoutRev + seperator+revision+seperator +
310
                         inLineDataIndex;
311
       inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName);
312
       // put the inline file id into a vector. If upload failed, metacat will
313
       // delete the inline data file
314
       inlineFileIDList.add(inlineDataFileName);
315
       
316
     }
317
     
318
     
319
     // If hit a text node, we need write this text for current's parent node
320
     // This will happend if the element is mixted
321
     if (hitTextNode && parentNode != null)
322
     {
323
       //compare text node data for unchangesubtree
324
       if (startCriticalSubTree)
325
       {
326
         compareTextNode(currentUnChangedableSubtreeNodeStack, textBuffer, 
327
                         PERMISSIONERROR);
328
       }//if
329
      
330
       //compare top level access module
331
       if (processTopLeverAccess && needCheckingAccessModule)
332
       {
333
          compareTextNode(currentUnchangableAccessModuleNodeStack, 
334
                          textBuffer, UPDATEACCESSERROR);
335
       }
336
       
337
       if (needCheckingAccessModule && 
338
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
339
       {
340
        // stored the pull out nodes into storedNode stack
341
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
342
                      null, null, MetaCatUtil.normalize(textBuffer.toString()));
343
        storedAccessNodeStack.push(nodeElement);
344
                                         
345
      }
346
        
347
       // write the textbuffer into db for parent node.
348
        endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
349
        // rest hitTextNode
350
        hitTextNode =false;
351
        // reset textbuffer
352
        textBuffer = null;
353
        textBuffer = new StringBuffer();
354
       
355
     }
356
     
357
  
358
     // Document representation that points to the root document node
359
     if (atFirstElement) 
360
     {
361
       atFirstElement = false;
362
       // If no DOCTYPE declaration: docname = root element
363
       // doctype = root element name or name space
364
       if (docname == null) 
365
       {
366
         docname = localName;
367
         // if uri isn't null doctype = uri(namespace)
368
         // othewise root element
369
         if (uri != null && !(uri.trim()).equals(""))
370
         {
371
           doctype = uri;
372
         }
373
         else
374
         {
375
           doctype = docname;
376
         }
377
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
378
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
379
       } 
380
       else if (doctype == null) 
381
       {
382
         // because docname is not null and it is declared in dtd
383
         // so could not be in schema, no namespace
384
         doctype = docname;
385
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
386
       }
387
       rootNode.writeNodename(docname);
388
       try 
389
       {
390
         // for validated XML Documents store a reference to XML DB Catalog
391
         // Because this is select statement and it needn't to roll back if
392
         // insert document action fialed.
393
         // In order to decrease DBConnection usage count, we get a new
394
         // dbconnection from pool
395
         String catalogid = null;
396
         DBConnection dbConn = null;
397
         int serialNumber = -1;
398

    
399
        
400
         try
401
         {
402
            // Get dbconnection
403
            dbConn=DBConnectionPool.getDBConnection
404
                                          ("DBSAXHandler.startElement");
405
            serialNumber=dbConn.getCheckOutSerialNumber();
406

    
407
            Statement stmt = dbConn.createStatement();
408
            ResultSet rs = stmt.executeQuery(
409
                          "SELECT catalog_id FROM xml_catalog " +
410
                          "WHERE entry_type = 'Schema' " +
411
                          "AND public_id = '" + doctype + "'");
412
            boolean hasRow = rs.next();
413
            if ( hasRow ) 
414
            {
415
              catalogid = rs.getString(1);
416
            }
417
            stmt.close();
418
         }//try
419
         finally
420
         {
421
             // Return dbconnection
422
             DBConnectionPool.returnDBConnection(dbConn, serialNumber);
423
         }//finally
424
       
425

    
426
         //create documentImpl object by the constructor which can specify
427
         //the revision
428
         currentDocument = new DocumentImpl(connection, rootNode.getNodeID(),
429
                               docname, doctype, docid, revision, action, user,
430
                               this.pub, catalogid, this.serverCode);
431

    
432

    
433
       } 
434
       catch (Exception ane) 
435
       {
436
         throw (new SAXException("Error in EMLSaxHandler.startElement " +
437
                                 action, ane));
438
       }
439
     }
440

    
441
     // Create the current node representation
442
     currentNode = new DBSAXNode(connection, qName, localName, parentNode,
443
                                 currentDocument.getRootNodeID(),docid,
444
                                 currentDocument.getDoctype());
445
     // Use a local variable to store the element node id
446
     // If this element is a start point of subtree(section), it will be stored
447
     // otherwise, it will be discated
448
     long startNodeId = currentNode.getNodeID();
449
     // Add all of the namespaces
450
     String prefix =null;
451
     String nsuri = null;
452
     Enumeration prefixes = namespaces.keys();
453
     while ( prefixes.hasMoreElements() ) 
454
     {
455
       prefix = (String)prefixes.nextElement();
456
       nsuri = (String)namespaces.get(prefix);
457
       endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
458
     }
459
   
460

    
461
     // Add all of the attributes
462
     for (int i=0; i<atts.getLength(); i++) 
463
     {
464
       String attributeName = atts.getQName(i);
465
       String attributeValue = atts.getValue(i);
466
       endNodeId = 
467
                currentNode.setAttribute(attributeName, attributeValue, docid);
468
       
469
       // To handle name space and schema location if the attribute name is
470
       // xsi:schemaLocation. If the name space is in not in catalog table
471
       // it will be regeistered.
472
       if (attributeName != null && 
473
           attributeName.indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1)
474
       {
475
         SchemaLocationResolver resolver = 
476
                                  new SchemaLocationResolver(attributeValue);
477
         resolver.resolveNameSpace();
478
         
479
       }
480
       else if (attributeName !=null && attributeName.equals(ID))
481
       {
482
        
483
        
484
         //check unchangedable subtree hash if contains this subtree id
485
         if (unChangableSubTreeHash.containsKey(attributeValue))
486
         {
487
           // this subtree couldn't be changed by the user and move it from hash
488
           SubTree currentUnChangedableSubtree = (SubTree)
489
                                  unChangableSubTreeHash.remove(attributeValue);
490
           currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree.
491
                                                         getSubTreeNodeStack();
492
           startCriticalSubTree = true;
493
           firstElementForCriticalSubTree = true;
494
         }
495
         
496
         // handle subtree info
497
         SubTree subTress = new SubTree();
498
         // set sub tree id
499
         subTress.setSubTreeId(attributeValue);
500
         // set sub tree sstart lement name
501
         subTress.setStartElementName(currentNode.getTagName());
502
         // set start node number
503
         subTress.setStartNodeId(startNodeId);
504
         // add to stack, but it didn't get end node id yet
505
         subTreeInfoStack.push(subTress);
506
         
507
       }
508
     }//for
509
   
510
     // handle access stuff
511
     if (localName.equals(ACCESS))
512
     {
513
       // if it is in addtionalmetacat
514
       if (parentNode.getTagName() == ADDITIONALMETADATA)
515
       {
516
         processAdditionalAccess = true;
517
        
518
       }
519
       else
520
       {
521
         //make sure the access is top level
522
         // this mean current node's parent's parent should be "eml"
523
         DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out parent node
524
         //peek out grandParentNode
525
         DBSAXNode grandParentNode = (DBSAXNode)nodeStack.peek();
526
         // put parent node back
527
         nodeStack.push(tmpNode);
528
         String grandParentTag = grandParentNode.getTagName();
529
         if (grandParentTag.equals(EML))
530
         {
531
           processTopLeverAccess = true;
532
         }
533
         else
534
         {
535
           // process other access embedded into resource level module
536
           processOtherAccess = true;
537
         }
538
        
539
       }
540
       // create access object 
541
       accessObject = new AccessSection();
542
         // set permission order
543
       String permOrder = currentNode.getAttribute(ORDER);
544
       accessObject.setPermissionOrder(permOrder);
545
       // set access id
546
       String accessId = currentNode.getAttribute(ID);
547
       accessObject.setSubTreeId(accessId);
548
       accessObject.setStartNodeId(startNodeId);
549
       accessObject.setDocId(docid);
550
       
551
       // load top level node stack to currentUnchangableAccessModuleNodeStack
552
       if (processTopLeverAccess && needCheckingAccessModule)
553
       {
554
         // get the node stack for
555
         currentUnchangableAccessModuleNodeStack = 
556
                                        topAccessSection.getSubTreeNodeStack();
557
       }
558
                 
559
       
560
     }
561
     // Set up a access rule for allow
562
     else if (parentNode.getTagName() != null && 
563
       (parentNode.getTagName()).equals(ACCESS) && localName.equals(ALLOW))
564
     {
565
      
566
       accessRule = new AccessRule(); 
567
      
568
       //set permission type "allow"
569
       accessRule.setPermissionType(ALLOW);
570
      
571
     }
572
     // set up an access rule for den
573
     else if (parentNode.getTagName() != null 
574
       && (parentNode.getTagName()).equals(ACCESS) && localName.equals(DENY))
575
     {
576
       accessRule = new AccessRule();
577
       //set permission type "allow"
578
       accessRule.setPermissionType(DENY);
579
     }
580
      
581
     // Add the node to the stack, so that any text data can be
582
     // added as it is encountered
583
     nodeStack.push(currentNode);
584
     // Add the node to the vector used by thread for writing XML Index
585
     nodeIndex.addElement(currentNode);
586
    
587
    // handle critical subtree
588
    if (startCriticalSubTree && firstElementForCriticalSubTree)
589
    {
590
      //store the element name
591
      firstElementNameForCriticalSubTree = qName;
592
      firstElementForCriticalSubTree = false;
593
    }//for first element
594
    
595
    // handle critical subtree
596
    if (startCriticalSubTree)
597
    {
598
      compareElementNameSpaceAttributes(currentUnChangedableSubtreeNodeStack,
599
                                        namespaces, atts, localName, 
600
                                        PERMISSIONERROR);
601
      
602
    }
603
    //compare top access level module
604
    if (processTopLeverAccess && needCheckingAccessModule)
605
    {
606
      compareElementNameSpaceAttributes(currentUnchangableAccessModuleNodeStack, 
607
                                        namespaces, atts, localName, 
608
                                        UPDATEACCESSERROR);
609
       
610
    }
611
    
612
    // store access module element and attributes into stored stack
613
    if (needCheckingAccessModule && 
614
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
615
    {
616
       // stored the pull out nodes into storedNode stack
617
       NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT", 
618
                                localName, prefix, MetaCatUtil.normalize(null));
619
       storedAccessNodeStack.push(nodeElement);
620
       for (int i=0; i<atts.getLength(); i++) 
621
       {
622
         String attributeName = atts.getQName(i);
623
         String attributeValue = atts.getValue(i);
624
         NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2, "ATTRIBUTE",
625
                    attributeName, null, MetaCatUtil.normalize(attributeValue));
626
         storedAccessNodeStack.push(nodeAttribute);
627
       }
628
                                   
629
    }
630
   
631
    // reset name space
632
    namespaces = null;
633
    namespaces = new Hashtable();
634
   }//not inline data
635
   else
636
   {
637
       // we don't buffer the inline data in characters() method
638
       // so start character don't need to hand text node.
639
       
640
       // inline data may be the xml format.
641
       StringBuffer inlineElements = new StringBuffer();
642
       inlineElements.append("<").append(qName);
643
       // append attributes
644
       for (int i=0; i<atts.getLength(); i++) 
645
       {
646
         String attributeName = atts.getQName(i);
647
         String attributeValue = atts.getValue(i);
648
         inlineElements.append(" ");
649
         inlineElements.append(attributeName);
650
         inlineElements.append("=\"");
651
         inlineElements.append(attributeValue);
652
         inlineElements.append("\"");
653
       }
654
       // append namespace
655
       String prefix =null;
656
       String nsuri = null;
657
       Enumeration prefixes = inlineDataNameSpace.keys();
658
       while ( prefixes.hasMoreElements() ) 
659
       {
660
         prefix = (String)prefixes.nextElement();
661
         nsuri = (String)namespaces.get(prefix);
662
         inlineElements.append(" ");
663
         inlineElements.append("xmlns:");
664
         inlineElements.append(prefix);
665
         inlineElements.append("=\"");
666
         inlineElements.append(nsuri);
667
         inlineElements.append("\"");
668
       }
669
       inlineElements.append(">");
670
       //reset inline data name space
671
       inlineDataNameSpace = null;
672
       inlineDataNameSpace = new Hashtable();
673
       //write inline data into file
674
       MetaCatUtil.debugMessage("the inline element data is: "+ 
675
                                 inlineElements.toString(), 50);
676
       writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
677
   }//else
678
   
679
  }
680
  
681
  private void compareElementNameSpaceAttributes(Stack unchangableNodeStack, 
682
                                            Hashtable nameSpaces,
683
                                            Attributes attributes,
684
                                            String localName, String error) 
685
                                            throws SAXException
686
  {
687
     //Get element subtree node stack (element node)
688
      NodeRecord elementNode = null;
689
      try
690
      {
691
        elementNode= (NodeRecord) unchangableNodeStack.pop();
692
      }
693
      catch (EmptyStackException ee)
694
      {
695
        MetaCatUtil.debugMessage("Node stack is empty for element data", 35);
696
        throw new SAXException(error);
697
      }
698
      MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
699
      MetaCatUtil.debugMessage("node type from stack: " + 
700
                                  elementNode.getNodeType(), 40);
701
      MetaCatUtil.debugMessage("node name from xml document: " + 
702
                                  localName, 40);
703
      MetaCatUtil.debugMessage("node name from stack: " +
704
                                  elementNode.getNodeName(), 40);
705
      MetaCatUtil.debugMessage("node data from stack: " +
706
                                  elementNode.getNodeData(), 40);
707
      MetaCatUtil.debugMessage("node id is: "+ elementNode.getNodeId(), 40);
708
      // if this node is not element or local name not equal or name space not
709
      // equals, throw an exception
710
      if (!elementNode.getNodeType().equals("ELEMENT") || 
711
          !localName.equals(elementNode.getNodeName()))
712
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
713
      {
714
        MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
715
        MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
716
        MetaCatUtil.debugMessage("node type from stack: " + 
717
                                  elementNode.getNodeType(), 40);
718
        MetaCatUtil.debugMessage("node name from xml document: " + 
719
                                  localName, 40);
720
        MetaCatUtil.debugMessage("node name from stack: " +
721
                                  elementNode.getNodeName(), 40);
722
        MetaCatUtil.debugMessage("node data from stack: " +
723
                                  elementNode.getNodeData(), 40);
724
        MetaCatUtil.debugMessage("node id is: "+ elementNode.getNodeId(), 40);
725
        throw new SAXException(error);
726
      }
727
      
728
      //compare namespace
729
     Enumeration nameEn = nameSpaces.keys();
730
     while ( nameEn.hasMoreElements() ) 
731
     {
732
       //Get namespacke node stack (element node)
733
       NodeRecord nameNode = null;
734
       try
735
       { 
736
         nameNode = (NodeRecord) unchangableNodeStack.pop();
737
       }
738
       catch (EmptyStackException ee)
739
       {
740
         MetaCatUtil.debugMessage("Node stack is empty for namespace data", 35);
741
         throw new SAXException(error);
742
       }
743
       
744
       String prefixName = (String)nameEn.nextElement(); 
745
       String nameSpaceUri = (String)nameSpaces.get(prefixName);
746
       if (!nameNode.getNodeType().equals("NAMESPACE") || 
747
           !prefixName.equals(nameNode.getNodeName()) || 
748
           !nameSpaceUri.equals(nameNode.getNodeData()))
749
       { 
750
         MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
751
         MetaCatUtil.debugMessage("current node type from xml is NAMESPACE", 40);
752
         MetaCatUtil.debugMessage("node type from stack: " + 
753
                                  nameNode.getNodeType(), 40);
754
         MetaCatUtil.debugMessage("current node name from xml is: " + 
755
                                   prefixName, 40);
756
         MetaCatUtil.debugMessage("node name from stack: " +
757
                                  nameNode.getNodeName(), 40);
758
         MetaCatUtil.debugMessage("current node data from xml is: " + 
759
                                   nameSpaceUri, 40);
760
         MetaCatUtil.debugMessage("node data from stack: " +
761
                                  nameNode.getNodeData(), 40);
762
         MetaCatUtil.debugMessage("node id is: "+ nameNode.getNodeId(), 40);
763
         throw new SAXException(error);
764
       }
765
      
766
     }//while
767
      
768
      //compare attributes
769
      for (int i=0; i<attributes.getLength(); i++)
770
      {
771
        NodeRecord attriNode = null;
772
        try
773
        {
774
          attriNode = (NodeRecord)unchangableNodeStack.pop();
775
          
776
        }
777
        catch (EmptyStackException ee)
778
        {
779
          MetaCatUtil.debugMessage("Node stack is empty for attribute data", 35);
780
          throw new SAXException(error);
781
        }
782
        String attributeName = attributes.getQName(i);
783
        String attributeValue = attributes.getValue(i);
784
        MetaCatUtil.debugMessage("current node type from xml is ATTRIBUTE ", 40);
785
        MetaCatUtil.debugMessage("node type from stack: " + 
786
                                   attriNode.getNodeType(), 40);
787
        MetaCatUtil.debugMessage("current node name from xml is: " + 
788
                                    attributeName, 40);
789
        MetaCatUtil.debugMessage("node name from stack: " +
790
                                    attriNode.getNodeName(), 40);
791
        MetaCatUtil.debugMessage("current node data from xml is: " + 
792
                                    attributeValue, 40);
793
        MetaCatUtil.debugMessage("node data from stack: " +
794
                                    attriNode.getNodeData(), 40);
795
        MetaCatUtil.debugMessage("node id  is: "+ attriNode.getNodeId(), 40);
796
        
797
        if (!attriNode.getNodeType().equals("ATTRIBUTE") || 
798
            !attributeName.equals(attriNode.getNodeName()) ||
799
            !attributeValue.equals(attriNode.getNodeData()))
800
        {
801
          MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
802
          MetaCatUtil.debugMessage("current node type from xml is ATTRIBUTE ", 40);
803
          MetaCatUtil.debugMessage("node type from stack: " + 
804
                                   attriNode.getNodeType(), 40);
805
          MetaCatUtil.debugMessage("current node name from xml is: " + 
806
                                    attributeName, 40);
807
          MetaCatUtil.debugMessage("node name from stack: " +
808
                                    attriNode.getNodeName(), 40);
809
          MetaCatUtil.debugMessage("current node data from xml is: " + 
810
                                    attributeValue, 40);
811
          MetaCatUtil.debugMessage("node data from stack: " +
812
                                    attriNode.getNodeData(), 40);
813
          MetaCatUtil.debugMessage("node is: "+ attriNode.getNodeId(), 40);
814
          throw new SAXException(error);
815
        }
816
      }//for
817
    
818
  }
819
  
820
  /* mehtod to compare current text node and node in db*/                                         
821
  private void compareTextNode(Stack nodeStack, StringBuffer text, String error) 
822
                               throws SAXException
823
  {
824
    NodeRecord node = null;
825
    //get node from current stack
826
    try
827
    { 
828
      node = (NodeRecord)nodeStack.pop();
829
    }
830
    catch (EmptyStackException ee)
831
    {
832
      MetaCatUtil.
833
          debugMessage("Node stack is empty for text data in startElement", 35);
834
      throw new SAXException(error);
835
    }
836
    MetaCatUtil.debugMessage("current node type from xml is TEXT in start element", 40);
837
    MetaCatUtil.debugMessage("node type from stack: " + 
838
                                        node.getNodeType(), 40);
839
    MetaCatUtil.debugMessage("current node data from xml is: " + 
840
                                        text.toString(), 40);
841
    MetaCatUtil.debugMessage("node data from stack: " +
842
                                        node.getNodeData(), 40);
843
    MetaCatUtil.debugMessage("node name from stack: " +
844
                                        node.getNodeName(), 40);
845
    MetaCatUtil.debugMessage("node is: "+ node.getNodeId(), 40);              
846
    if (!node.getNodeType().equals("TEXT") || 
847
        !(text.toString()).equals(node.getNodeData())) 
848
    { 
849
      MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
850
      MetaCatUtil.debugMessage("current node type from xml is TEXT in start element", 40);
851
      MetaCatUtil.debugMessage("node type from stack: " + 
852
                                        node.getNodeType(), 40);
853
      MetaCatUtil.debugMessage("current node data from xml is: " + 
854
                                        text.toString(), 40);
855
      MetaCatUtil.debugMessage("node data from stack: " +
856
                                        node.getNodeData(), 40);
857
      MetaCatUtil.debugMessage("node name from stack: " +
858
                                        node.getNodeName(), 40);
859
      MetaCatUtil.debugMessage("node is: "+ node.getNodeId(), 40);
860
      throw new SAXException(error);
861
    }//if
862
  } 
863
  
864
  /** SAX Handler that is called for each XML text node */
865
  public void characters(char[] cbuf, int start, int len) throws SAXException 
866
  {
867
     MetaCatUtil.debugMessage("CHARACTERS", 50);
868
     if (!handleInlineData)
869
     {
870
        // buffer all text nodes for same element. This is for text was splited
871
        // into different nodes
872
        textBuffer.append(new String(cbuf, start,len));
873
        // set hittextnode true
874
        hitTextNode = true;
875
        // if text buffer .size is greater than max, write it to db. 
876
        // so we can save memory
877
        if (textBuffer.length() > MAXDATACHARS)
878
        {
879
          MetaCatUtil.debugMessage("Write text into DB in charaters" + 
880
                   " when text buffer size is greater than maxmum number", 50);
881
          DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
882
          endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
883
          textBuffer = null;
884
          textBuffer = new StringBuffer();
885
        }
886
     }
887
     else
888
     {
889
       // this is inline data and write file system directly
890
       // we don't need to buffered it.
891
       StringBuffer inlineText = new StringBuffer();
892
       inlineText.append(new String(cbuf, start,len));
893
       MetaCatUtil.debugMessage("The inline text data write into file system: "
894
                                 + inlineText.toString(), 50);
895
       writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
896
     }
897
  }
898
  
899
  
900
  /** SAX Handler that is called at the end of each XML element */
901
   public void endElement(String uri, String localName,
902
                          String qName) throws SAXException 
903
  {
904
    MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
905
    
906
     if (localName.equals(INLINE) && handleInlineData)
907
     {
908
          // Get the node from the stack
909
          DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
910
          String currentTag = currentNode.getTagName();
911
          MetaCatUtil.debugMessage("End of inline data", 35);
912
          // close file writer
913
          try
914
          {
915
           inlineDataFileWriter.close();
916
           handleInlineData = false;
917
          }
918
          catch (IOException ioe)
919
          {
920
            throw new SAXException(ioe.getMessage());
921
          }
922
          
923
          //check if user changed inine data or not if user doesn't have
924
          // write permission
925
          if (startCriticalSubTree)
926
          {
927
            NodeRecord node = null;
928
            String inlineData;
929
            try
930
            {
931
              node = (NodeRecord)currentUnChangedableSubtreeNodeStack.pop();
932
              // get file name from db
933
              String fileName = node.getNodeData();
934
              MetaCatUtil.debugMessage("in handle inline data", 35);
935
              MetaCatUtil.debugMessage("the inline data file name from node is: "+
936
                                      fileName, 40);
937
              if (!compareInlineDataFiles(fileName, inlineDataFileName))
938
              {
939
                MetaCatUtil.debugMessage("inline data was changed by a user" +
940
                                       " who doesn't have permission", 30);
941
                throw new SAXException(PERMISSIONERROR);
942
              }
943
            }
944
            catch (EmptyStackException ee)
945
            {
946
              MetaCatUtil.debugMessage("the stack is empty for text data", 32);
947
              throw new SAXException(PERMISSIONERROR);
948
            }
949
            catch (McdbException eee)
950
            {
951
              throw new SAXException(eee.getMessage());
952
            }
953
            finally
954
            {
955
              // delete the inline data file already in file system
956
              deleteInlineDataFile(inlineDataFileName);
957
            }
958
          
959
          }//if
960
          // write put inline data file name into text buffer (without path)
961
          textBuffer = new StringBuffer(inlineDataFileName);
962
          // write file name into db
963
          endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
964
          // reset textbuff
965
          textBuffer = null;
966
          textBuffer = new StringBuffer(); 
967
          return;
968
    }
969
    
970
    if (!handleInlineData)
971
    {
972
     // Get the node from the stack
973
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
974
     String currentTag = currentNode.getTagName();
975
    
976
     // If before the end element, the parser hit text nodes and store them
977
     // into the buffer, write the buffer to data base. The reason we put
978
     // write database here is for xerces some time split text node
979
     if (hitTextNode)
980
     {
981
        // get access value
982
        String data = null;
983
        // add principal
984
       if (currentTag.equals(PRINCIPAL) && accessRule != null) 
985
       {
986
          data = (textBuffer.toString()).trim();
987
          accessRule.addPrincipal(data);
988

    
989
       } 
990
       else if (currentTag.equals(PERMISSION) && accessRule != null) 
991
       {
992
         data = (textBuffer.toString()).trim();
993
         // we conbine different a permission into one value
994
         int permission = accessRule.getPermission();
995
         // add permision
996
         if ( data.toUpperCase().equals(READSTRING) ) 
997
         {
998
           permission = permission | READ;
999
         } 
1000
         else if ( data.toUpperCase().equals(WRITESTRING) ) 
1001
         {
1002
           permission = permission | WRITE;
1003
         } 
1004
         else if ( data.toUpperCase().equals(CHMODSTRING)) 
1005
         {
1006
           permission = permission | CHMOD;
1007
         } 
1008
         else if ( data.toUpperCase().equals(ALLSTRING) ) 
1009
         {
1010
          permission = permission | ALL;
1011
         }
1012
         accessRule.setPermission(permission);
1013
       }
1014
       // put additionalmetadata/describes into vector
1015
       else if (currentTag.equals(DESCRIBES))
1016
       {
1017
          data = (textBuffer.toString()).trim();
1018
          describesId.add(data);
1019
       }
1020
       else if (currentTag.equals(REFERENCES) && 
1021
               (processTopLeverAccess ||
1022
                processAdditionalAccess || processOtherAccess))
1023
       {
1024
         // get reference 
1025
         data = (textBuffer.toString()).trim();
1026
         // put reference id into accessSection
1027
         accessObject.setReferences(data);
1028
         
1029
       }
1030
       else if (currentTag.equals(URL))
1031
       {
1032
         //handle online data, make sure its'parent is online
1033
         DBSAXNode parentNode = (DBSAXNode)nodeStack.peek();
1034
         if (parentNode != null && parentNode.getTagName()!= null &&
1035
             parentNode.getTagName().equals(ONLINE))
1036
         {
1037
            // if online data is in local metacat, add it to the vector
1038
            data = (textBuffer.toString()).trim();
1039
            if (data != null && 
1040
                (data.indexOf(MetaCatUtil.getOption("httpserver")) != -1 || 
1041
                data.indexOf(MetaCatUtil.getOption("server")) != -1))
1042
            {
1043
              // Get docid from url
1044
              String dataId =MetaCatUtil.getDocIdWithRevFromOnlineURL(data);
1045
              // add to vector
1046
              onlineDataFileIdVector.add(dataId);             
1047
            }//if
1048
          }//if
1049
       }//else if
1050
       // write text to db if it is not inline data
1051
       //if (!localName.equals(INLINE))
1052
       {
1053
          MetaCatUtil.debugMessage("Write text into DB in End Element", 50);
1054
          //compare text node if need
1055
          if (startCriticalSubTree)
1056
          {
1057
            compareTextNode(currentUnChangedableSubtreeNodeStack, textBuffer, 
1058
                            PERMISSIONERROR);
1059
          }//if
1060
          //compare top level access module
1061
          if (processTopLeverAccess && needCheckingAccessModule)
1062
          {
1063
             compareTextNode(currentUnchangableAccessModuleNodeStack, 
1064
                            textBuffer, UPDATEACCESSERROR);
1065
          }
1066
          // write text node into db
1067
          endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
1068
       }
1069
       if (needCheckingAccessModule && 
1070
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1071
       {
1072
        // stored the pull out nodes into storedNode stack
1073
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
1074
                      null, null, MetaCatUtil.normalize(textBuffer.toString()));
1075
        storedAccessNodeStack.push(nodeElement);
1076
                                         
1077
      }
1078
     }//if
1079
     
1080
     //end crtical subtree(user doesn't have permission to write)
1081
     //When reach the first element and stack is empty
1082
     if (localName.equals(firstElementNameForCriticalSubTree) && 
1083
         currentUnChangedableSubtreeNodeStack.isEmpty()) 
1084
     {
1085
       startCriticalSubTree = false;
1086
     }
1087
     
1088
     
1089
     //set hitText false
1090
     hitTextNode = false;
1091
     // reset textbuff
1092
     textBuffer = null;
1093
     textBuffer = new StringBuffer();
1094
     
1095
     // hand sub stree stuff
1096
     if (!subTreeInfoStack.empty())
1097
     {
1098
       SubTree tree = (SubTree)subTreeInfoStack.peek();// get last subtree
1099
       if (tree != null && tree.getStartElementName() != null && 
1100
         (tree.getStartElementName()).equals(currentTag))
1101
       {
1102
         // find the end of sub tree and set the end node id
1103
         tree.setEndNodeId(endNodeId);
1104
         // add the subtree into the final store palace
1105
         subTreeList.add(tree);
1106
         // get rid of it from stack
1107
         subTreeInfoStack.pop();
1108
       }//if
1109
     }//if
1110

    
1111
     // access stuff
1112
     if (currentTag.equals(ALLOW) || currentTag.equals(DENY))
1113
     {
1114
       // finish parser a ccess rule and  assign it to new one
1115
       AccessRule newRule = accessRule;
1116
       //add the new rule to access section object
1117
       accessObject.addAccessRule(newRule);
1118
       // reset access rule
1119
       accessRule = null;
1120
     }
1121
     else if (currentTag.equals(ACCESS))
1122
     {
1123
       // finish parse a access setction and assign it to new one
1124
      
1125
       accessObject.setEndNodeId(endNodeId);
1126
       AccessSection newAccessObject = accessObject;
1127
    
1128
       if (newAccessObject != null)
1129
       {
1130
       
1131
        // add the accessSection into a vector to store it
1132
        // if it is not a reference, need to store it
1133
        if ( newAccessObject.getReferences() == null)
1134
        {
1135
          
1136
          newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
1137
          accessObjectList.add(newAccessObject);
1138
        }
1139
        if (processTopLeverAccess)
1140
        {
1141
          
1142
          // top level access control will handle whole document -docid
1143
          topLevelAccessControlMap.put(docid, newAccessObject);
1144
          // reset processtopleveraccess tag
1145
          
1146
        }//if
1147
        else if (processAdditionalAccess)
1148
        {
1149
          // for additional control
1150
          // put everything in describes value and access object into hash
1151
          for ( int i=0; i<describesId.size(); i++)
1152
          {
1153
           
1154
            String subId = (String)describesId.elementAt(i);
1155
            if (subId != null)
1156
            {
1157
              additionalAccessControlMap.put(subId, newAccessObject);
1158
            }//if
1159
          }//for
1160
          // add this hashtable in to vector
1161
         
1162
          additionalAccessMapList.add(additionalAccessControlMap);
1163
          // reset this hashtable in order to store another additional 
1164
          //accesscontrol
1165
          additionalAccessControlMap = null;
1166
          additionalAccessControlMap = new Hashtable();
1167
        }//if
1168
       
1169
       }//if
1170
       //check if  access node stack is empty after parsing top access
1171
       //module
1172
      
1173
       if (needCheckingAccessModule && processTopLeverAccess && 
1174
           !currentUnchangableAccessModuleNodeStack.isEmpty())
1175
       {
1176
         
1177
         MetaCatUtil.debugMessage("Access node stack is not empty after " + 
1178
                                   "parsing access subtree", 40);
1179
         throw new SAXException(UPDATEACCESSERROR);
1180
                                  
1181
       }
1182
       //reset access section object
1183
      
1184
       accessObject = null;
1185
     
1186
       // reset tmp stored node stack
1187
       storedAccessNodeStack = null;
1188
       storedAccessNodeStack = new Stack();
1189
    
1190
       // reset flag
1191
       processAdditionalAccess =false;
1192
       processTopLeverAccess =false;
1193
       processOtherAccess = false;
1194
      
1195
     }
1196
     else if (currentTag.equals(ADDITIONALMETADATA))
1197
     {
1198
        //reset describesId
1199
        describesId = null;
1200
        describesId = new Vector();
1201
     }
1202
    }
1203
    else
1204
    {
1205
      // this is in inline part
1206
      StringBuffer endElement = new StringBuffer();
1207
      endElement.append("</");
1208
      endElement.append(qName);
1209
      endElement.append(">");
1210
      MetaCatUtil.debugMessage("inline endElement: " +
1211
                                endElement.toString(), 50);
1212
      writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1213
    }
1214
  }
1215
   
1216
   /**
1217
    * SAX Handler that receives notification of comments in the DTD
1218
    */
1219
   public void comment(char[] ch, int start, int length) throws SAXException 
1220
   {
1221
     MetaCatUtil.debugMessage("COMMENT", 50);
1222
     if ( !handleInlineData)
1223
     {
1224
       if ( !processingDTD ) 
1225
       {
1226
         DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
1227
         String str = new String(ch, start, length);
1228
       
1229
         //compare comment if need
1230
         if (startCriticalSubTree)
1231
         {
1232
           compareCommentNode(currentUnChangedableSubtreeNodeStack, str, 
1233
                            PERMISSIONERROR);
1234
         }//if
1235
         //compare top level access module
1236
         if (processTopLeverAccess && needCheckingAccessModule)
1237
         {
1238
           compareCommentNode(currentUnchangableAccessModuleNodeStack, str,
1239
                            UPDATEACCESSERROR);
1240
         }
1241
         endNodeId = currentNode.writeChildNodeToDB("COMMENT", null, str, docid);
1242
         if (needCheckingAccessModule && 
1243
         (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1244
         {
1245
          // stored the pull out nodes into storedNode stack
1246
          NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "COMMENT", 
1247
                                        null, null, MetaCatUtil.normalize(str));
1248
          storedAccessNodeStack.push(nodeElement);
1249
                                         
1250
        }
1251
       }
1252
     }
1253
     else
1254
     {
1255
       // inline data comment
1256
       StringBuffer inlineComment = new StringBuffer();
1257
       inlineComment.append("<!--");
1258
       inlineComment.append(new String(ch, start, length));
1259
       inlineComment.append("-->");
1260
       MetaCatUtil.debugMessage("inline data comment: "+ 
1261
                                 inlineComment.toString(), 50);
1262
       writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1263
     }
1264
   }
1265
   
1266
   
1267
   /* Comparet comment from xml and db */
1268
   private void compareCommentNode(Stack nodeStack, String string, String error)
1269
                                   throws SAXException
1270
   {
1271
     NodeRecord node = null;
1272
     try
1273
     {
1274
       node = (NodeRecord)nodeStack.pop();
1275
     }
1276
     catch (EmptyStackException ee)
1277
     {
1278
       MetaCatUtil.debugMessage("the stack is empty for comment data", 32);
1279
       throw new SAXException(error);
1280
     }
1281
     MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
1282
     MetaCatUtil.debugMessage("node type from stack: " + 
1283
                                    node.getNodeType(), 40);
1284
     MetaCatUtil.debugMessage("current node data from xml is: " + 
1285
                                    string, 40);
1286
     MetaCatUtil.debugMessage("node data from stack: " +
1287
                                    node.getNodeData(), 40);
1288
     MetaCatUtil.debugMessage("node is from stack: " + 
1289
                                    node.getNodeId(), 40);
1290
     // if not consistent terminate program and throw a exception
1291
     if (!node.getNodeType().equals("COMMENT") || 
1292
         !string.equals(node.getNodeData())) 
1293
     { 
1294
       MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1295
       MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
1296
       MetaCatUtil.debugMessage("node type from stack: " + 
1297
                                    node.getNodeType(), 40);
1298
       MetaCatUtil.debugMessage("current node data from xml is: " + 
1299
                                    string, 40);
1300
       MetaCatUtil.debugMessage("node data from stack: " +
1301
                                    node.getNodeData(), 40);
1302
       MetaCatUtil.debugMessage("node is from stack: " + 
1303
                                        node.getNodeId(), 40);
1304
       throw new SAXException(error);
1305
     }//if
1306
   }
1307
   
1308
   /**
1309
    * SAX Handler called once for each processing instruction found:
1310
    * node that PI may occur before or after the root element.
1311
    */
1312
   public void processingInstruction(String target, String data)
1313
          throws SAXException 
1314
  {
1315
     MetaCatUtil.debugMessage("PI", 50);
1316
     if (!handleInlineData)
1317
     {
1318
       DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
1319
       endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
1320
     }
1321
     else
1322
     {
1323
       StringBuffer inlinePI = new StringBuffer();
1324
       inlinePI.append("<?");
1325
       inlinePI.append(target);
1326
       inlinePI.append(" ");
1327
       inlinePI.append(data);
1328
       inlinePI.append("?>");
1329
       MetaCatUtil.debugMessage("inline data pi is: " + 
1330
                                 inlinePI.toString(), 50);
1331
       writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1332
     }
1333
   }
1334

    
1335
  /** SAX Handler that is called at the start of Namespace */
1336
   public void startPrefixMapping(String prefix, String uri)
1337
                                          throws SAXException
1338
   {
1339
    MetaCatUtil.debugMessage("NAMESPACE", 50);
1340
    if (!handleInlineData)
1341
    {
1342
      namespaces.put(prefix, uri);
1343
    }
1344
    else
1345
    {
1346
      inlineDataNameSpace.put(prefix, uri);
1347
    }
1348
   }
1349
      /**
1350
    * SAX Handler that is called for each XML text node that is
1351
    * Ignorable white space
1352
    */
1353
   public void ignorableWhitespace(char[] cbuf, int start, int len)
1354
               throws SAXException 
1355
  {
1356
     // When validation is turned "on", white spaces are reported here
1357
     // When validation is turned "off" white spaces are not reported here,
1358
     // but through characters() callback
1359
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
1360
     if (!handleInlineData)
1361
     {
1362
       DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
1363
       String data = null;
1364
       int leftover = len;
1365
       int offset = start;
1366
       boolean moredata = true;
1367

    
1368
       // This loop deals with the case where there are more characters
1369
       // than can fit in a single database text field (limit is
1370
       // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
1371
       // write a series of nodes that are MAXDATACHARS long, and then the
1372
       // final node contains the remainder
1373
       while (moredata) 
1374
       {
1375
         if (leftover > MAXDATACHARS) 
1376
         {
1377
           data = new String(cbuf, offset, MAXDATACHARS);
1378
           leftover -= MAXDATACHARS;
1379
           offset += MAXDATACHARS;
1380
         } 
1381
         else 
1382
         {
1383
           data = new String(cbuf, offset, leftover);
1384
           moredata = false;
1385
         }
1386

    
1387
         //compare whitespace if need
1388
         if (startCriticalSubTree)
1389
         {
1390
           compareWhiteSpace(currentUnChangedableSubtreeNodeStack, data, 
1391
                           PERMISSIONERROR);
1392
         }//if
1393
       
1394
         //compare whitespace in access top module
1395
         if (processTopLeverAccess && needCheckingAccessModule)
1396
         {
1397
           compareWhiteSpace(currentUnchangableAccessModuleNodeStack, data, 
1398
                           UPDATEACCESSERROR);
1399
         }
1400
         // Write the content of the node to the database
1401
         if (needCheckingAccessModule && 
1402
         (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1403
         {
1404
          // stored the pull out nodes into storedNode stack
1405
          NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
1406
                                     null, null, MetaCatUtil.normalize(data));
1407
          storedAccessNodeStack.push(nodeElement);
1408
                                         
1409
         }
1410
         endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data, docid);
1411
       }
1412
     }
1413
     else
1414
     {
1415
       //This is inline data write to file directly
1416
       StringBuffer inlineWhiteSpace = new 
1417
                                     StringBuffer(new String(cbuf, start, len));
1418
       writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1419
     }
1420
       
1421
   }
1422
   
1423
   /* Compare whitespace from xml and db */
1424
   private void compareWhiteSpace(Stack nodeStack, String string, String error)
1425
                                  throws SAXException
1426
   {
1427
      NodeRecord node = null;
1428
      try
1429
      {
1430
        node = (NodeRecord)nodeStack.pop();
1431
      }
1432
      catch (EmptyStackException ee)
1433
      {
1434
        MetaCatUtil.debugMessage("the stack is empty for whitespace data", 32);
1435
        throw new SAXException(error);
1436
      }
1437
      if (!node.getNodeType().equals("TEXT") || 
1438
          !string.equals(node.getNodeData())) 
1439
      { 
1440
        MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1441
        MetaCatUtil.debugMessage("current node type from xml is WHITESPACE TEXT", 40);
1442
        MetaCatUtil.debugMessage("node type from stack: " + 
1443
                                  node.getNodeType(), 40);
1444
        MetaCatUtil.debugMessage("current node data from xml is: " + 
1445
                                  string, 40);
1446
        MetaCatUtil.debugMessage("node data from stack: " +
1447
                                  node.getNodeData(), 40);
1448
        MetaCatUtil.debugMessage("node is from stack: " + 
1449
                                  node.getNodeId(), 40);
1450
        throw new SAXException(error);
1451
     }//if
1452
   }
1453
   
1454
   /** SAX Handler that receives notification of end of the document */
1455
   public void endDocument() throws SAXException 
1456
   {
1457
     MetaCatUtil.debugMessage("end Document", 50);
1458
     // There are some unchangable subtree didn't be compare
1459
     // This maybe cause user change the subtree id
1460
     if (!unChangableSubTreeHash.isEmpty())
1461
     {
1462
       MetaCatUtil.debugMessage("The unChangealbe subtree is not empty", 40);
1463
       throw new SAXException(PERMISSIONERROR);
1464
     }
1465
     
1466
     // write access rule to db
1467
     writeAccessRuleToDB();
1468
     
1469
     //delete relation table
1470
     deleteRelations();
1471
     //write relations
1472
     for (int i= 0; i<onlineDataFileIdVector.size(); i++)
1473
     {
1474
       String id = (String)onlineDataFileIdVector.elementAt(i);
1475
       writeOnlineDataFileIdIntoRelationTable(id);
1476
     }
1477
   
1478
     // Starting new thread for writing XML Index.
1479
     // It calls the run method of the thread.
1480
     boolean useXMLIndex = 
1481
         (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
1482
     if (useXMLIndex) {
1483
            try {
1484
                xmlIndex.start();
1485
            } catch (NullPointerException e) {
1486
                xmlIndex = null;
1487
                throw new SAXException(
1488
                        "Problem with starting thread for writing XML Index. "
1489
                                + e.getMessage());
1490
            }
1491
     }
1492
   }
1493
   
1494
  /* The method to write all access rule into db */
1495
  private void writeAccessRuleToDB() throws SAXException
1496
  {
1497
    //Delete old permssion
1498
    deletePermissionsInAccessTable(docid);
1499
    //write top leve access rule
1500
    writeTopLevelAccessRuleToDB();
1501
    //write additional access rule
1502
    //writeAddtionalAccessRuleToDB();
1503
  }//writeAccessRuleToDB
1504
   
1505
  /* The method to write top level access rule into db. */
1506
  private void writeTopLevelAccessRuleToDB() throws SAXException
1507
  {
1508
    
1509
    // for top document level
1510
    Object accessSection = topLevelAccessControlMap.get(docid);
1511
    boolean top = true;
1512
    String subSectionId = null;
1513
    if ( accessSection != null )
1514
    {
1515
       AccessSection accessSectionObj = (AccessSection)accessSection;
1516
           
1517
       // if accessSection is not null and is not reference
1518
       if ( accessSectionObj.getReferences() == null)
1519
       {
1520
          // write the top level access module into xml_accesssubtree to store info
1521
          // and then when update to check if the user can update it or not
1522
          deleteAccessSubTreeRecord(docid);
1523
          writeAccessSubTreeIntoDB(accessSectionObj,TOPLEVEL);
1524
         
1525
          //write access section into xml_access table
1526
          writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1527
          // write relative online data file into xml_access too.
1528
          /*for (int i= 0; i<onlineDataFileIdVector.size(); i++)
1529
          {
1530
            String id = (String)onlineDataFileIdVector.elementAt(i);
1531
            writeAccessRuleForRalatedDataFileIntoDB(accessSectionObj, id);
1532
          }*/
1533
          
1534
       }
1535
       else
1536
       {
1537
   
1538
        // this is a reference and go trough the vector which contains all
1539
        // access object
1540
        String referenceId = accessSectionObj.getReferences();
1541
        boolean findAccessObject = false;
1542
        MetaCatUtil.debugMessage("referered id for top access: "+ 
1543
                               referenceId, 35);
1544
        for (int i=0; i<accessObjectList.size(); i++)
1545
        {
1546
          AccessSection accessObj = (AccessSection)accessObjectList.elementAt(i);
1547
          String accessObjId = accessObj.getSubTreeId();
1548
          if (referenceId != null && accessObj != null &&
1549
              referenceId.equals(accessObjId))
1550
          {
1551
            // make sure the user didn't change any thing in this access moduel
1552
            // too if user doesn't have all permission
1553
            if (needCheckingAccessModule)
1554
            {
1555
              
1556
              Stack newStack = accessObj.getStoredTmpNodeStack();
1557
              //revise order
1558
              newStack = MetaCatUtil.reviseStack(newStack);
1559
               // go throught the vector of unChangableAccessSubtreevector
1560
              // and find the one whose id is as same as referenceid
1561
              AccessSection oldAccessObj = 
1562
                       getAccessSectionFromUnchangableAccessVector(referenceId);
1563
              //if oldAccessObj is null something is wrong
1564
              if (oldAccessObj == null)
1565
              {
1566
                throw new SAXException(UPDATEACCESSERROR);
1567
              }//if
1568
              else
1569
              {
1570
                // Get the node stack from old access obj
1571
                Stack oldStack = oldAccessObj.getSubTreeNodeStack();
1572
                comparingNodeStacks(newStack, oldStack);
1573
              }//else
1574
            }//if
1575
            // write accessobject into db
1576
            writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1577
            // add access rule for related on line data id too.
1578
            /*for (int j= 0; j<onlineDataFileIdVector.size(); j++)
1579
            {
1580
              String id = (String)onlineDataFileIdVector.elementAt(j);
1581
              writeAccessRuleForRalatedDataFileIntoDB(accessObj, id);
1582
            }*/
1583
            
1584
            
1585
            //write the reference access into xml_accesssubtree too
1586
             // write the top level access module into xml_accesssubtree to store info
1587
             // and then when update to check if the user can update it or not
1588
            deleteAccessSubTreeRecord(docid);
1589
            writeAccessSubTreeIntoDB(accessSectionObj,TOPLEVEL);
1590
            writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1591
            findAccessObject = true;
1592
            break;
1593
          }
1594
        }//for
1595
        // if we couldn't find an access subtree id for this reference id
1596
        if (!findAccessObject)
1597
        {
1598
          throw new SAXException("The referenceid: " + referenceId +
1599
                               " is not access subtree");
1600
        }//if
1601
      }//else
1602
      
1603
     
1604
    }//if
1605
    else
1606
    {
1607
      // couldn't find a access section object 
1608
      MetaCatUtil.debugMessage("couldn't find access control for document: "+
1609
                                docid, 35);
1610
    }
1611
    
1612
  }//writeTopLevelAccessRuletoDB
1613
  
1614
  /* Given a subtree id and find the responding access section*/
1615
  private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1616
  {
1617
    AccessSection result = null;
1618
    // Makse sure the id
1619
    if (id == null || id.equals(""))
1620
    {
1621
      return result;
1622
    }
1623
    // go throught vector and find the list
1624
    for (int i=0; i<unChangableAccessSubTreeVector.size();i++)
1625
    {
1626
      AccessSection accessObj = (AccessSection)
1627
                                 unChangableAccessSubTreeVector.elementAt(i);
1628
      if (accessObj.getSubTreeId() != null && 
1629
         (accessObj.getSubTreeId()).equals(id))
1630
      {
1631
        result = accessObj;
1632
      }//if
1633
    }//for
1634
    return result;
1635
  }//getAccessSectionFromUnchangableAccessVector
1636
      
1637
  /* Compare two node stacks to see if they are same */
1638
  private void comparingNodeStacks(Stack stack1, Stack stack2) 
1639
                                 throws SAXException
1640
  {
1641
    // make sure stack1 and stack2 are not empty
1642
    if (stack1.isEmpty() || stack2.isEmpty())
1643
    {
1644
      MetaCatUtil.debugMessage("Because stack is empty!", 35);
1645
      throw new SAXException(UPDATEACCESSERROR);
1646
    }
1647
    // go throw two stacks and compare every element
1648
    while (!stack1.isEmpty())
1649
    {
1650
      // Pop an element from stack1
1651
      NodeRecord record1 = (NodeRecord) stack1.pop();
1652
      // Pop an element from stack2(stack 2 maybe empty)
1653
      NodeRecord record2 = null;
1654
      try
1655
      {
1656
        record2 = (NodeRecord) stack2.pop();
1657
      }
1658
      catch (EmptyStackException ee)
1659
      {
1660
        MetaCatUtil.debugMessage("Node stack2 is empty but stack1 isn't!", 35);
1661
        throw new SAXException(UPDATEACCESSERROR);
1662
      }
1663
      // if two records are not same throw a exception
1664
      if (!record1.contentEquals(record2))
1665
      {
1666
        MetaCatUtil.debugMessage("Two records from new and old stack are not "+
1667
                                 "same!", 30);
1668
        throw new SAXException(UPDATEACCESSERROR);
1669
      }//if
1670
    }//while
1671
    
1672
    // now stack1 is empty and we should make sure stack2 is empty too
1673
    if(!stack2.isEmpty())
1674
    {
1675
      MetaCatUtil.debugMessage("stack2 still have some elements while stack "+
1676
                               "is empty! ", 30);
1677
      throw new SAXException(UPDATEACCESSERROR);
1678
    }//if
1679
 }//comparingNodeStacks
1680
  
1681
   /* The method to write addtional access rule into db. */
1682
  private void writeAddtionalAccessRuleToDB() throws SAXException
1683
  {
1684
    
1685
     PreparedStatement pstmt = null;
1686
     boolean topLevel =false;
1687
    // go through the vector which contains the additional access control 
1688
    //hashtable. Each hashtable has info for one additonalmetadata container 
1689
   for (int j= 0; j < additionalAccessMapList.size(); j++)
1690
   {
1691
     
1692
     Hashtable accessControlMap = 
1693
                                (Hashtable)additionalAccessMapList.elementAt(j);
1694
     // additional access rule
1695
     Enumeration en = accessControlMap.keys();
1696
     
1697
     while(en.hasMoreElements())
1698
     {
1699
       try
1700
       {
1701
         // Get subsection id
1702
          String subSectionId = (String)en.nextElement();
1703
          MetaCatUtil.debugMessage("sub section id in additional access mapping"
1704
                                   +"(go through): "+ subSectionId, 35);
1705
          
1706
          if (subSectionId == null)
1707
          {
1708
            // if id is null, terminate the program
1709
            throw new SAXException("subtree id is null");
1710
          }
1711
          // Get AccessSection Object
1712
          Object accessSectionObj = accessControlMap.get(subSectionId);
1713
          if (accessSectionObj == null)
1714
          {
1715
            // if accesssection is null, terminate the program
1716
            throw new SAXException("access subtree is null");
1717
          }
1718
          else
1719
          {
1720
            AccessSection accessControlObj = (AccessSection)accessSectionObj;
1721
            // if the access section is not references, write it to db
1722
            if (accessControlObj.getReferences() == null)
1723
            {
1724
              writeGivenAccessRuleIntoDB(accessControlObj, topLevel, 
1725
                                         subSectionId);
1726
            }
1727
            else
1728
            {
1729
              // this is a reference and go trough the vector which contains all
1730
              // access object
1731
              String referenceId = accessControlObj.getReferences();
1732
            
1733
              boolean findAccessObject = false;
1734
              MetaCatUtil.debugMessage("referered id for additional access "+
1735
                                     "mapping(go through): "+ referenceId, 35);
1736
              for (int i=0; i<accessObjectList.size(); i++)
1737
              {
1738
                AccessSection accessObj = 
1739
                                (AccessSection)accessObjectList.elementAt(i);
1740
                String accessObjId = accessObj.getSubTreeId();
1741
                MetaCatUtil.debugMessage("access obj id in the list(go through): "
1742
                                        + accessObjId, 35);
1743
                if (referenceId != null && accessObj != null &&
1744
                    referenceId.equals(accessObjId))
1745
                {
1746
                  writeGivenAccessRuleIntoDB(accessObj, topLevel, subSectionId);
1747
                  findAccessObject = true;
1748
                }//if
1749
              }//for
1750
              // if we couldn't find an access subtree id for this reference id
1751
              if (!findAccessObject)
1752
              {
1753
                throw new SAXException("The referenceid: " + referenceId +
1754
                               " is not access subtree");
1755
              }//if
1756
            }//else
1757
          }//else
1758
       }//try
1759
       catch (Exception e)
1760
       {
1761
         
1762
         MetaCatUtil.debugMessage("error in EmlSAXHandler.writeAddtionalAccess"
1763
                                   + ": "+e.getMessage(), 30);
1764
         throw new SAXException(e.getMessage());
1765
       }
1766
     }//while
1767
    }//for
1768
  }//writeAccessRuletoDB
1769
  
1770
  /* Write a gaven access rule into db*/
1771
  private void writeGivenAccessRuleIntoDB(AccessSection accessSection, 
1772
                                         boolean topLevel, String subSectionId) 
1773
                                         throws SAXException
1774
  {
1775
     if (accessSection == null)
1776
     {
1777
       throw new SAXException("The access object is null");
1778
     }
1779
     
1780
      String permOrder = accessSection.getPermissionOrder();
1781
      String sql = null;
1782
      PreparedStatement pstmt = null;
1783
      if (topLevel)
1784
      {
1785
        sql = "INSERT INTO xml_access (docid, principal_name, permission, "+
1786
                 "perm_type, perm_order, accessfileid) VALUES " +
1787
                 " (?, ?, ?, ?, ?, ?)";
1788
      }
1789
      else
1790
      {
1791
        sql ="INSERT INTO xml_access (docid,principal_name, "+ 
1792
             "permission, perm_type, perm_order, accessfileid, subtreeid, "+
1793
             " startnodeid, endnodeid) VALUES" +
1794
             " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1795
      }
1796
      try 
1797
      {
1798
     
1799
        pstmt = connection.prepareStatement(sql);
1800
        // Increase DBConnection usage count
1801
        connection.increaseUsageCount(1);
1802
        // Bind the values to the query
1803
        pstmt.setString(1, docid);
1804
        MetaCatUtil.debugMessage("Docid in accesstable: "+ docid, 35);
1805
        pstmt.setString(6, docid);
1806
        MetaCatUtil.debugMessage("Accessfileid in accesstable: "+ docid, 35);
1807
        pstmt.setString(5, permOrder);
1808
        MetaCatUtil.debugMessage("PermOder in accesstable: "+ permOrder, 35);
1809
        // if it is not top level, set subsection id
1810
        if (!topLevel)
1811
        {
1812
          long startNodeId = 0;
1813
          long endNodeId = 0;
1814
          // for subtree should specify the
1815
          if (subSectionId == null)
1816
          {
1817
            throw new SAXException("The subsection is null");
1818
          }
1819
          // go through the substree list vector and found the start node id
1820
          // and stop node id for this subtree id
1821
          for (int i=0; i<subTreeList.size(); i++)
1822
          {
1823
            SubTree tree = (SubTree)subTreeList.elementAt(i);
1824
            String subTreeId = tree.getSubTreeId();
1825
            if (subSectionId.equals(subTreeId))
1826
            {
1827
              startNodeId = tree.getStartNodeId();
1828
              endNodeId = tree.getEndNodeId(); 
1829
            }//if
1830
          }//for
1831
          if (startNodeId == 0 || endNodeId == 0)
1832
          {
1833
            throw new SAXException("Could find the subtree"
1834
                                   + "for this id: "+subSectionId);
1835
          }
1836
          pstmt.setString(7, subSectionId);
1837
          MetaCatUtil.debugMessage("SubSectionId in accesstable: "+ 
1838
                                    subSectionId, 35);
1839
          pstmt.setLong(8, startNodeId);
1840
          MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
1841
          pstmt.setLong(9, endNodeId);
1842
          MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1843
          
1844
        }
1845
      
1846
        Vector accessRules = accessSection.getAccessRules();
1847
        // go through every rule
1848
        for (int i=0; i<accessRules.size(); i++)
1849
        {
1850
          AccessRule rule = (AccessRule)accessRules.elementAt(i);
1851
          String permType = rule.getPermissionType();
1852
          int permission = rule.getPermission();
1853
          pstmt.setInt(3, permission);
1854
          MetaCatUtil.debugMessage("permission in accesstable: "+ permission, 35);
1855
          pstmt.setString(4, permType);
1856
          MetaCatUtil.debugMessage("Permtype in accesstable: "+ permType, 35);
1857
          // go through every principle in rule
1858
          Vector nameVector = rule.getPrincipal();
1859
          for ( int j = 0; j < nameVector.size(); j++ ) 
1860
          {
1861
            String prName = (String)nameVector.elementAt(j);
1862
            pstmt.setString(2, prName);
1863
            MetaCatUtil.debugMessage("Principal in accesstable: "+prName, 35);
1864
            pstmt.execute();
1865
          }//for
1866
        }//for
1867
        pstmt.close();
1868
      }//try 
1869
      catch (SQLException e) 
1870
      {
1871
        throw new 
1872
        SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + e.getMessage());
1873
      }//catch
1874
      finally
1875
      {
1876
        try
1877
        {
1878
          pstmt.close();
1879
        }
1880
        catch(SQLException ee)
1881
        {
1882
          throw new 
1883
          SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + 
1884
          ee.getMessage());
1885
        }
1886
      }//finally
1887
     
1888
  }//writeGivenAccessRuleIntoDB
1889
  
1890
  
1891
  
1892
    /* Write a gaven access rule into db*/
1893
  private void writeAccessRuleForRalatedDataFileIntoDB
1894
                  (AccessSection accessSection, String dataId) 
1895
                                         throws SAXException
1896
  {
1897
      if (accessSection == null)
1898
      {
1899
        throw new SAXException("The access object is null");
1900
      }
1901
      // get rid of rev from dataId
1902
      dataId = MetaCatUtil.getDocIdFromString(dataId);
1903
      String permOrder = accessSection.getPermissionOrder();
1904
      String sql = null;
1905
      PreparedStatement pstmt = null;
1906
      sql = "INSERT INTO xml_access (docid, principal_name, permission, "+
1907
                 "perm_type, perm_order, accessfileid) VALUES " +
1908
                 " (?, ?, ?, ?, ?, ?)";
1909
   
1910
      try 
1911
      {
1912
     
1913
        pstmt = connection.prepareStatement(sql);
1914
        // Increase DBConnection usage count
1915
        connection.increaseUsageCount(1);
1916
        // Bind the values to the query
1917
        pstmt.setString(1, dataId);
1918
        MetaCatUtil.debugMessage("Docid in accesstable: "+ docid, 35);
1919
        pstmt.setString(6, docid);
1920
        MetaCatUtil.debugMessage("Accessfileid in accesstable: "+ docid, 35);
1921
        pstmt.setString(5, permOrder);
1922
        MetaCatUtil.debugMessage("PermOder in accesstable: "+ permOrder, 35);
1923
        // if it is not top level, set subsection id
1924
            
1925
        Vector accessRules = accessSection.getAccessRules();
1926
        // go through every rule
1927
        for (int i=0; i<accessRules.size(); i++)
1928
        {
1929
          AccessRule rule = (AccessRule)accessRules.elementAt(i);
1930
          String permType = rule.getPermissionType();
1931
          int permission = rule.getPermission();
1932
          pstmt.setInt(3, permission);
1933
          MetaCatUtil.debugMessage("permission in accesstable: "+ permission, 35);
1934
          pstmt.setString(4, permType);
1935
          MetaCatUtil.debugMessage("Permtype in accesstable: "+ permType, 35);
1936
          // go through every principle in rule
1937
          Vector nameVector = rule.getPrincipal();
1938
          for ( int j = 0; j < nameVector.size(); j++ ) 
1939
          {
1940
            String prName = (String)nameVector.elementAt(j);
1941
            pstmt.setString(2, prName);
1942
            MetaCatUtil.debugMessage("Principal in accesstable: "+prName, 35);
1943
            pstmt.execute();
1944
          }//for
1945
        }//for
1946
        pstmt.close();
1947
      }//try 
1948
      catch (SQLException e) 
1949
      {
1950
        throw new 
1951
        SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + e.getMessage());
1952
      }//catch
1953
      finally
1954
      {
1955
        try
1956
        {
1957
          pstmt.close();
1958
        }
1959
        catch(SQLException ee)
1960
        {
1961
          throw new 
1962
          SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + 
1963
          ee.getMessage());
1964
        }
1965
      }//finally
1966
     
1967
  }//writeAccessRuleForRalatedDataFileIntoDB
1968
  
1969
  
1970
  
1971
  
1972
  
1973
  /* Delete from db all permission for resources related to @aclid if any.*/
1974
  private void deletePermissionsInAccessTable(String aclid) 
1975
          throws SAXException 
1976
  {
1977
    Statement stmt = null;
1978
    try
1979
    {
1980
      // delete all acl records for resources related to @aclid if any
1981
      stmt = connection.createStatement();
1982
      // Increase DBConnection usage count
1983
      connection.increaseUsageCount(1);
1984
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid +
1985
                   "'"); 
1986
    
1987
    }
1988
    catch (SQLException e)
1989
    {
1990
      throw new SAXException(e.getMessage());
1991
    }
1992
    finally
1993
    {
1994
      try
1995
      {
1996
        stmt.close();
1997
      }
1998
      catch (SQLException ee)
1999
      {
2000
        throw new SAXException(ee.getMessage());
2001
      }
2002
    }
2003
  }//deletePermissionsInAccessTable
2004
  
2005
  
2006
  /* In order to make sure only usr has "all" permission can update access
2007
   * subtree in eml document we need to keep access subtree info in 
2008
   * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
2009
   */
2010
  private void writeAccessSubTreeIntoDB(AccessSection accessSection, 
2011
                                         String level) 
2012
                                         throws SAXException
2013
  {
2014
     if (accessSection == null)
2015
     {
2016
       throw new SAXException("The access object is null");
2017
     }
2018
     
2019
      String sql = null;
2020
      PreparedStatement pstmt = null;
2021
      sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "+
2022
                 "subtreeid, startnodeid, endnodeid) VALUES " +
2023
                 " (?, ?, ?, ?, ?, ?)";
2024
      try 
2025
      {
2026
     
2027
        pstmt = connection.prepareStatement(sql);
2028
        // Increase DBConnection usage count
2029
        connection.increaseUsageCount(1);
2030
        long startNodeId = accessSection.getStartNodeId();
2031
        long endNodeId = accessSection.getEndNodeId();
2032
        String sectionId = accessSection.getSubTreeId();
2033
        // Bind the values to the query
2034
        pstmt.setString(1, docid);
2035
        MetaCatUtil.debugMessage("Docid in access-subtreetable: "+ docid, 35);
2036
        pstmt.setString(2, revision );
2037
        MetaCatUtil.debugMessage("rev in accesssubtreetable: "+ revision, 35);
2038
        pstmt.setString(3, level);
2039
        MetaCatUtil.debugMessage("contorl level in access-subtree table: "+
2040
                                  level, 35);
2041
        pstmt.setString(4, sectionId);
2042
        MetaCatUtil.debugMessage("Subtree id in access-subtree table: "+ 
2043
                                  sectionId, 35);
2044
        pstmt.setLong(5, startNodeId);
2045
        MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
2046
        pstmt.setLong(6, endNodeId);
2047
        MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
2048
        pstmt.execute();
2049
        pstmt.close();
2050
      }//try 
2051
      catch (SQLException e) 
2052
      {
2053
        throw new 
2054
        SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): " + 
2055
                      e.getMessage());
2056
      }//catch
2057
      finally
2058
      {
2059
        try
2060
        {
2061
          pstmt.close();
2062
        }
2063
        catch(SQLException ee)
2064
        {
2065
          throw new 
2066
          SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): " + 
2067
          ee.getMessage());
2068
        }
2069
      }//finally
2070
     
2071
  }//writeAccessSubtreeIntoDB
2072
  
2073
   /* Delete every access subtree record from xml_accesssubtree.*/
2074
  private void deleteAccessSubTreeRecord(String docId) throws SAXException 
2075
  {
2076
    Statement stmt = null;
2077
    try
2078
    {
2079
      // delete all acl records for resources related to @aclid if any
2080
      stmt = connection.createStatement();
2081
      // Increase DBConnection usage count
2082
      connection.increaseUsageCount(1);
2083
      stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '" + docId + "'"); 
2084
   
2085
    }
2086
    catch (SQLException e)
2087
    {
2088
      throw new SAXException(e.getMessage());
2089
    }
2090
    finally
2091
    {
2092
      try
2093
      {
2094
        stmt.close();
2095
      }
2096
      catch (SQLException ee)
2097
      {
2098
        throw new SAXException(ee.getMessage());
2099
      }
2100
    }
2101
  }//deleteAccessSubTreeRecord
2102
  
2103
  // open a file writer for writing inline data to file
2104
  private FileWriter createInlineDataFileWriter(String fileName) 
2105
                                               throws SAXException
2106
  {
2107
    FileWriter writer = null;
2108
    String path = MetaCatUtil.getOption("inlinedatafilepath");
2109
    /*File inlineDataDirectory = new File(path);
2110
    File newFile = new File(inlineDataDirectory, fileName);*/
2111
    String newFile = path + "/" + fileName;
2112
    MetaCatUtil.debugMessage("inline file name: "+newFile, 30);
2113
    try
2114
    {
2115
      // true means append
2116
      writer = new FileWriter(newFile, true);
2117
    }
2118
    catch (IOException ioe)
2119
    {
2120
      throw new SAXException(ioe.getMessage());
2121
    }
2122
    return writer;
2123
  }
2124
  // write inline data into file system and return file name(without path)
2125
  private void writeInlineDataIntoFile(FileWriter writer, 
2126
                                               StringBuffer data) 
2127
                                               throws SAXException
2128
  {
2129
    try
2130
    {
2131
      writer.write(data.toString());
2132
      writer.flush();
2133
    }
2134
    catch (Exception e)
2135
    {
2136
      throw new SAXException(e.getMessage());
2137
    }
2138
  }
2139
  
2140
  /* In eml2, the inline data wouldn't store in db, it store in file system
2141
   * The db stores file name(without path). We got the old file name from db
2142
   * and compare to the new in line data file
2143
   */
2144
  public boolean compareInlineDataFiles(String oldFileName, String newFileName)
2145
                                                throws McdbException
2146
  {
2147
    // this method need to be testing
2148
    boolean same = true;
2149
    String data = null;
2150
    String path = MetaCatUtil.getOption("inlinedatafilepath");
2151
    // the new file name will look like path/docid.rev.2
2152
    File inlineDataDirectory = new File(path);
2153
    File oldDataFile = new File(inlineDataDirectory, oldFileName);
2154
    File newDataFile = new File(inlineDataDirectory, newFileName);
2155
    try
2156
    {
2157
      FileReader oldFileReader = new FileReader(oldDataFile);
2158
      BufferedReader oldStringReader = new BufferedReader(oldFileReader);
2159
      FileReader newFileReader = new FileReader(newDataFile);
2160
      BufferedReader newStringReader = new BufferedReader(newFileReader);
2161
      // read first line of data
2162
      String oldString = oldStringReader.readLine();
2163
      String newString = newStringReader.readLine();
2164
     
2165
      // at the end oldstring will be null
2166
      while (oldString != null)
2167
      {
2168
        oldString = oldStringReader.readLine();
2169
        newString = newStringReader.readLine();
2170
        if (!oldString.equals(newString))
2171
        {
2172
          same = false;
2173
          break;
2174
        }
2175
      }
2176
      
2177
      // if oldString is null but newString is not null, they are same
2178
      if (same)
2179
      {
2180
         if (newString != null)
2181
         {
2182
           same = false;
2183
         }
2184
      }
2185
      
2186
    }
2187
    catch (Exception e)
2188
    {
2189
      throw new McdbException(e.getMessage());
2190
    }
2191
    MetaCatUtil.debugMessage("the inline data retrieve from file: "+data, 50);
2192
    return same;
2193
  }
2194
  
2195
  // if xml file failed to upload, we need to call this method to delete
2196
  // the inline data already in file system
2197
  public void deleteInlineFiles()
2198
  {
2199
     if (!inlineFileIDList.isEmpty())
2200
     {
2201
       for ( int i=0; i<inlineFileIDList.size(); i++)
2202
       {
2203
         String fileName = (String) inlineFileIDList.elementAt(i);
2204
         deleteInlineDataFile(fileName);
2205
       }
2206
     }
2207
  }
2208
  
2209
  /* delete the inline data file */
2210
  private void deleteInlineDataFile(String fileName)
2211
  {
2212
    
2213
     String path = MetaCatUtil.getOption("inlinedatafilepath");
2214
     File inlineDataDirectory = new File(path);
2215
     File newFile = new File(inlineDataDirectory, fileName);
2216
     newFile.delete();
2217
  
2218
  }
2219
  
2220
   /* In eml2, the inline data wouldn't store in db, it store in file system
2221
   * The db stores file name(without path).
2222
   */
2223
  public static Reader readInlineDataFromFileSystem(String fileName) 
2224
                                              throws McdbException
2225
  {
2226
    //BufferedReader stringReader = null;
2227
    FileReader fileReader = null;
2228
    String path = MetaCatUtil.getOption("inlinedatafilepath");
2229
    // the new file name will look like path/docid.rev.2
2230
    File inlineDataDirectory = new File(path);
2231
    File dataFile = new File(inlineDataDirectory, fileName);
2232
    try
2233
    {
2234
      fileReader = new FileReader(dataFile);
2235
      //stringReader = new BufferedReader(fileReader);
2236
    }
2237
    catch (Exception e)
2238
    {
2239
      throw new McdbException(e.getMessage());
2240
    }
2241
   // return stringReader;
2242
   return fileReader;
2243
  }
2244
  
2245
  /* Delete relations */
2246
  private void deleteRelations() throws SAXException
2247
  {
2248
    PreparedStatement pStmt = null;
2249
    String sql = "DELETE FROM xml_relation where docid =?";
2250
    try
2251
    {
2252
      pStmt = connection.prepareStatement(sql);
2253
      //bind variable
2254
      pStmt.setString(1, docid);
2255
      //execute query
2256
      pStmt.execute();
2257
      pStmt.close();
2258
    }//try
2259
    catch (SQLException e) 
2260
    {
2261
       throw new 
2262
       SAXException("EMLSAXHandler.deleteRelations(): " + 
2263
                      e.getMessage());
2264
    }//catch
2265
    finally
2266
    {
2267
      try
2268
      {
2269
        pStmt.close();
2270
      }//try
2271
      catch(SQLException ee)
2272
      {
2273
        throw new 
2274
        SAXException("EMLSAXHandler.deleteRelations: " + 
2275
        ee.getMessage());
2276
      }//catch
2277
    }//finally
2278
  }
2279
  
2280
  /* Write an online data file id into xml_relation table*/
2281
  private void writeOnlineDataFileIdIntoRelationTable(String dataId) 
2282
                                                        throws SAXException
2283
  {
2284
    // Get rid of rev
2285
    dataId = MetaCatUtil.getDocIdFromString(dataId);
2286
    PreparedStatement pStmt = null;
2287
    String sql = "INSERT into xml_relation (docid, packagetype, subject, "+
2288
                 "relationship, object) values (?, ?, ?, ?, ?)";
2289
    try
2290
    {
2291
      pStmt = connection.prepareStatement(sql);
2292
      //bind variable
2293
      pStmt.setString(1, docid);
2294
      pStmt.setString(2, DocumentImpl.EMLNAMESPACE);
2295
      pStmt.setString(3, docid);
2296
      pStmt.setString(4, RELATION);
2297
      pStmt.setString(5, dataId);
2298
      //execute query
2299
      pStmt.execute();
2300
      pStmt.close();
2301
    }//try
2302
    catch (SQLException e) 
2303
    {
2304
       throw new 
2305
       SAXException("EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): " + 
2306
                      e.getMessage());
2307
    }//catch
2308
    finally
2309
    {
2310
      try
2311
      {
2312
        pStmt.close();
2313
      }//try
2314
      catch(SQLException ee)
2315
      {
2316
        throw new 
2317
        SAXException("EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): " + 
2318
        ee.getMessage());
2319
      }//catch
2320
    }//finally
2321
    
2322
  }//writeOnlineDataFileIdIntoRelationTable
2323
  
2324
 
2325
}
(34-34/58)