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: tao $'
11
 *     '$Date: 2003-07-29 09:08:20 -0700 (Tue, 29 Jul 2003) $'
12
 * '$Revision: 1764 $'
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.sql.*;
32
import java.io.BufferedReader;
33
import java.io.IOException;
34
import java.io.File;
35
import java.io.FileReader;
36
import java.io.FileWriter;
37
import java.io.Reader;
38
import java.io.StringReader;
39
import java.util.Stack;
40
import java.util.Vector;
41
import java.util.Hashtable;
42
import java.util.Enumeration;
43
import java.util.EmptyStackException;
44

    
45
import org.xml.sax.Attributes;
46
import org.xml.sax.SAXException;
47
import org.xml.sax.SAXParseException;
48
import org.xml.sax.ext.DeclHandler;
49
import org.xml.sax.ext.LexicalHandler;
50
import org.xml.sax.helpers.DefaultHandler;
51

    
52
/**
53
 * A database aware Class implementing callback bethods for the SAX parser to
54
 * call when processing the XML stream and generating events
55
 */
56
public class EmlSAXHandler extends DBSAXHandler implements 
57
                                                      AccessControlInterface
58
{
59
   private Vector allowRules = new Vector();
60
   private Vector denyRules = new Vector();
61
   private String documentId = null;
62
   private Vector subDocumentIdList = new Vector();
63
   private boolean processTopLeverAccess = false;
64
   private boolean processAdditionalAccess = false;
65
   private boolean processOtherAccess = false;
66
   private AccessSection accessObject= null;
67
   private AccessRule accessRule = null;
68
   private Vector accessObjectList = new Vector(); // store every access rule
69
   private Hashtable topLevelAccessControlMap = new Hashtable();
70
   private Hashtable additionalAccessControlMap = new Hashtable();// store 
71
                                                 //subtree access for single
72
                                                 // additionalmetacat
73
   private Vector additionalAccessMapList = new Vector();// store maps for 
74
                                                       // every addionalmetadata
75
   private Vector describesId = new Vector(); // store the ids in
76
                                      //additionalmetadata/describes
77
   private Stack subTreeInfoStack = new Stack();
78
   private Vector subTreeList = new Vector();// store the final subtree
79
   private Hashtable unChangableSubTreeHash = new Hashtable();
80
   private Stack currentUnChangedableSubtreeNodeStack =new Stack();
81
   private boolean startCriticalSubTree = false;
82
   private boolean firstElementForCriticalSubTree = false;
83
   private String firstElementNameForCriticalSubTree;
84
   private boolean needCheckingAccessModule = false;
85
   private Vector unChangableAccessSubTreeVector = new Vector();
86
   private Stack currentUnchangableAccessModuleNodeStack = new Stack();
87
   private AccessSection topAccessSection;
88
   
89
   // we need an another stack to store the access node which we pull out just
90
   // from xml. If a reference happend, we can use the stack the compare nodes
91
   private Stack storedAccessNodeStack = new Stack();
92
   // vector stored the data file id which will be write into relation table
93
   private Vector onlineDataFileIdVector = new Vector();
94
   // Indicator of inline data
95
   private boolean handleInlineData = false;
96
   private Stack   inlineDataNodeStack = null;
97
   private Hashtable inlineDataNameSpace = null;
98
   private FileWriter inlineDataFileWriter = null;
99
   private String inlineDataFileName = null;
100
   private int inLineDataIndex = 0;
101
 
102
   // Constant
103
   private static final String EML ="eml";
104
   private static final String DESCRIBES = "describes";
105
   private static final String ADDITIONALMETADATA = "additionalMetadata";
106
   private static final String ORDER = "order";
107
   private static final String ID ="id";
108
   private static final String REFERENCES = "references";
109
   public  static final String INLINE = "inline";
110
   private static final String ONLINE = "online";
111
   private static final String URL    = "url";
112
   private static final String PERMISSIONERROR ="User try to update a subtree"+
113
                               " which it doesn't have write permission!";
114
   private static final String UPDATEACCESSERROR = "User try to update a " + 
115
                      "access module which it doesn't have \"ALL\" permission!";
116
   private static final String TOPLEVEL = "top";
117
   private static final String SUBTREELEVEL ="subtree";
118
   private static final String RELATION = "Provides info for";
119
  
120
    /** Construct an instance of the handler class
121
    * In this constructor, user can specify the version need to upadate
122
    *
123
    * @param conn the JDBC connection to which information is written
124
    * @param action - "INSERT" or "UPDATE"
125
    * @param docid to be inserted or updated into JDBC connection
126
    * @param revision, the user specified the revision need to be update
127
    * @param user the user connected to MetaCat servlet and owns the document
128
    * @param groups the groups to which user belongs
129
    * @param pub flag for public "read" access on document
130
    * @param serverCode the serverid from xml_replication on which this document
131
    *        resides.
132
    *
133
    */
134
   public EmlSAXHandler(DBConnection conn, String action, String docid,
135
     String revision, String user, String[] groups, String pub, int serverCode)
136
                              throws SAXException
137
   {
138
     super(conn, action, docid, revision, user, groups, pub, serverCode);
139
     // Get the unchangable subtrees (user doesn't have write permission)
140
     try
141
     {
142
       PermissionController control = new PermissionController(docid);
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
     }
313
     
314
     
315
     // If hit a text node, we need write this text for current's parent node
316
     // This will happend if the element is mixted
317
     if (hitTextNode && parentNode != null)
318
     {
319
       //compare text node data for unchangesubtree
320
       if (startCriticalSubTree)
321
       {
322
         compareTextNode(currentUnChangedableSubtreeNodeStack, textBuffer, 
323
                         PERMISSIONERROR);
324
       }//if
325
      
326
       //compare top level access module
327
       if (processTopLeverAccess && needCheckingAccessModule)
328
       {
329
          compareTextNode(currentUnchangableAccessModuleNodeStack, 
330
                          textBuffer, UPDATEACCESSERROR);
331
       }
332
       
333
       if (needCheckingAccessModule && 
334
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
335
       {
336
        // stored the pull out nodes into storedNode stack
337
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
338
                      null, null, MetaCatUtil.normalize(textBuffer.toString()));
339
        storedAccessNodeStack.push(nodeElement);
340
                                         
341
      }
342
        
343
       // write the textbuffer into db for parent node.
344
        endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
345
        // rest hitTextNode
346
        hitTextNode =false;
347
        // reset textbuffer
348
        textBuffer = null;
349
        textBuffer = new StringBuffer();
350
       
351
     }
352
     
353
  
354
     // Document representation that points to the root document node
355
     if (atFirstElement) 
356
     {
357
       atFirstElement = false;
358
       // If no DOCTYPE declaration: docname = root element
359
       // doctype = root element name or name space
360
       if (docname == null) 
361
       {
362
         docname = localName;
363
         // if uri isn't null doctype = uri(namespace)
364
         // othewise root element
365
         if (uri != null && !(uri.trim()).equals(""))
366
         {
367
           doctype = uri;
368
         }
369
         else
370
         {
371
           doctype = docname;
372
         }
373
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
374
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
375
       } 
376
       else if (doctype == null) 
377
       {
378
         // because docname is not null and it is declared in dtd
379
         // so could not be in schema, no namespace
380
         doctype = docname;
381
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
382
       }
383
       rootNode.writeNodename(docname);
384
       try 
385
       {
386
         // for validated XML Documents store a reference to XML DB Catalog
387
         // Because this is select statement and it needn't to roll back if
388
         // insert document action fialed.
389
         // In order to decrease DBConnection usage count, we get a new
390
         // dbconnection from pool
391
         String catalogid = null;
392
         DBConnection dbConn = null;
393
         int serialNumber = -1;
394

    
395
        
396
         try
397
         {
398
            // Get dbconnection
399
            dbConn=DBConnectionPool.getDBConnection
400
                                          ("DBSAXHandler.startElement");
401
            serialNumber=dbConn.getCheckOutSerialNumber();
402

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

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

    
428

    
429
       } 
430
       catch (Exception ane) 
431
       {
432
         throw (new SAXException("Error in EMLSaxHandler.startElement " +
433
                                 action, ane));
434
       }
435
     }
436

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

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

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

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

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

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

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