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-04-12 20:08:48 -0700 (Sat, 12 Apr 2003) $'
12
 * '$Revision: 1547 $'
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.File;
34
import java.io.FileReader;
35
import java.io.FileWriter;
36
import java.io.StringReader;
37
import java.util.Stack;
38
import java.util.Vector;
39
import java.util.Hashtable;
40
import java.util.Enumeration;
41
import java.util.EmptyStackException;
42

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

    
50
/**
51
 * A database aware Class implementing callback bethods for the SAX parser to
52
 * call when processing the XML stream and generating events
53
 */
54
public class EmlSAXHandler extends DBSAXHandler implements 
55
                                                      AccessControlInterface
56
{
57
   private Vector allowRules = new Vector();
58
   private Vector denyRules = new Vector();
59
   private String documentId = null;
60
   private Vector subDocumentIdList = new Vector();
61
   private boolean processTopLeverAccess = false;
62
   private boolean processAdditionalAccess = false;
63
   private boolean processOtherAccess = false;
64
   private AccessSection accessObject= null;
65
   private AccessRule accessRule = null;
66
   private Vector accessObjectList = new Vector(); // store every access rule
67
   private Hashtable topLevelAccessControlMap = new Hashtable();
68
   private Hashtable additionalAccessControlMap = new Hashtable();// store 
69
                                                 //subtree access for single
70
                                                 // additionalmetacat
71
   private Vector additionalAccessMapList = new Vector();// store maps for 
72
                                                       // every addionalmetadata
73
   private Vector describesId = new Vector(); // store the ids in
74
                                      //additionalmetadata/describes
75
   private Stack subTreeInfoStack = new Stack();
76
   private Vector subTreeList = new Vector();// store the final subtree
77
   private int inLineDataIndex = 1;
78
   private Hashtable unChangableSubTreeHash = new Hashtable();
79
   private Stack currentUnChangedableSubtreeNodeStack;
80
   private boolean startCriticalSubTree = false;
81
   private boolean firstElementForCriticalSubTree = false;
82
   private String firstElementNameForCriticalSubTree;
83
   private boolean needCheckingAccessModule = false;
84
   private Vector unChangableAccessSubTreeVector;
85
   private Stack currentUnchangableAccessModuleNodeStack;
86
   private AccessSection topAccessSection;
87
   
88
   // we need an another stack to store the access node which we pull out just
89
   // from xml. If a reference happend, we can use the stack the compare nodes
90
   private Stack storedAccessNodeStack = new Stack();
91
 
92
 
93
   // Constant
94
   private static final String EML ="eml";
95
   private static final String DESCRIBES = "describes";
96
   private static final String ADDITIONALMETADATA = "additionalMetadata";
97
   private static final String ORDER = "order";
98
   private static final String ID ="id";
99
   private static final String REFERENCES = "references";
100
   public  static final String INLINE = "inline";
101
   private static final String PERMISSIONERROR ="User try to update a subtree"+
102
                               " which it doesn't have write permission!";
103
   private static final String UPDATEACCESSERROR = "User try to update a " + 
104
                      "access module which it doesn't have \"ALL\" permission!";
105
   private static final String TOPLEVEL = "top";
106
   private static final String SUBTREELEVEL ="subtree";
107
  
108
    /** Construct an instance of the handler class
109
    * In this constructor, user can specify the version need to upadate
110
    *
111
    * @param conn the JDBC connection to which information is written
112
    * @param action - "INSERT" or "UPDATE"
113
    * @param docid to be inserted or updated into JDBC connection
114
    * @param revision, the user specified the revision need to be update
115
    * @param user the user connected to MetaCat servlet and owns the document
116
    * @param groups the groups to which user belongs
117
    * @param pub flag for public "read" access on document
118
    * @param serverCode the serverid from xml_replication on which this document
119
    *        resides.
120
    *
121
    */
122
   public EmlSAXHandler(DBConnection conn, String action, String docid,
123
     String revision, String user, String[] groups, String pub, int serverCode)
124
                              throws SAXException
125
   {
126
     super(conn, action, docid, revision, user, groups, pub, serverCode);
127
     // Get the unchangable subtrees (user doesn't have write permission)
128
     try
129
     {
130
       PermissionController control = new PermissionController(docid);
131
       //unChangableSubTreeHash = getUnchangableSubTree(control, user, groups);
132
       
133
       
134
       //If the action is update and user doesn't have "ALL" permission
135
       // we need to check if user update access subtree
136
       if (action.equals("UPDATE") && 
137
         !control.hasPermission(user, groups, AccessControlInterface.ALLSTRING))
138
       {
139
         needCheckingAccessModule = true;
140
         unChangableAccessSubTreeVector = getAccessSubTreeListFromDB();
141
       }
142
     }
143
     catch (Exception e)
144
     {
145
       throw new SAXException(e.getMessage());
146
     }
147
   }
148
   
149
   /* Pass a permission control and get the list of unchangable subtree*/
150
   private Hashtable getUnchangableSubTree(PermissionController controller,
151
                                           String user, String[]groups)
152
                                           throws Exception
153
   {
154
     Hashtable list = null;
155
     Hashtable result = new Hashtable();
156
     // get unwritable sutree from controller
157
     list = controller.hasUnaccessableSubTree(user, groups, 
158
                                          AccessControlInterface.WRITESTRING);
159
      if (list != null)
160
      {
161
       
162
         Enumeration en = list.elements();
163
         while (en.hasMoreElements())
164
         {
165
           // Get  a subtree without node record list
166
           SubTree treeWithoutStack = (SubTree)en.nextElement();
167
           String subTreeId   = treeWithoutStack.getSubTreeId();
168
           MetaCatUtil.debugMessage("unchangable subtree id: " + subTreeId, 40);
169
           long   startNodeId = treeWithoutStack.getStartNodeId();
170
           MetaCatUtil.debugMessage("unchangable subtree startnodeid: " +
171
                                    startNodeId, 40);
172
           long   endNodeId   = treeWithoutStack.getEndNodeId();
173
           MetaCatUtil.debugMessage("unchangable subtree endnodeid: " +
174
                                     endNodeId, 40);
175
           // Get a subtree has the nodelist
176
           SubTree tree = new SubTree(docid, subTreeId, startNodeId, endNodeId);
177
           // add this tree to the result
178
           result.put(subTreeId, tree);
179
         
180
          }//while
181
      
182
      }//if
183
      
184
      return result;
185
   }
186
   
187
   
188
   /*
189
    * Get the subtree node info from xml_accesssubtree table
190
    */
191
   private Vector getAccessSubTreeListFromDB() throws Exception
192
   {
193
      Vector result = new Vector();
194
      PreparedStatement pstmt = null;
195
      ResultSet rs = null;
196
      String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid " + 
197
                   "FROM xml_accesssubtree WHERE docid like ? " +
198
                   "ORDER BY startnodeid ASC";
199
              
200
      try 
201
      {
202
     
203
        pstmt = connection.prepareStatement(sql);
204
        // Increase DBConnection usage count
205
        connection.increaseUsageCount(1);
206
        // Bind the values to the query
207
        pstmt.setString(1, docid);
208
        pstmt.execute();
209
        
210
        // Get result set
211
        rs = pstmt.getResultSet();
212
        while (rs.next())
213
        {
214
          String level = rs.getString(1);
215
          String sectionId = rs.getString(2);
216
          long startNodeId = rs.getLong(3);
217
          long endNodeId = rs.getLong(4);
218
          // create a new access section
219
          AccessSection accessObj = new AccessSection();
220
          accessObj.setControlLevel(level);
221
          accessObj.setDocId(docid);
222
          accessObj.setSubTreeId(sectionId);
223
          accessObj.setStartNodeId(startNodeId);
224
          accessObj.setEndNodeId(endNodeId); 
225
          Stack nodeStack = accessObj.getSubTreeNodeList();
226
          accessObj.setSubTreeNodeStack(nodeStack);
227
          // add this access obj into vector
228
          result.add(accessObj);
229
          // Get the top level access subtree control
230
          if ( level != null && level.equals(TOPLEVEL))
231
          {
232
            topAccessSection = accessObj;
233
          }
234
        }
235
        pstmt.close();
236
      }//try 
237
      catch (SQLException e) 
238
      {
239
        throw new 
240
        SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): " + 
241
                      e.getMessage());
242
      }//catch
243
      finally
244
      {
245
        try
246
        {
247
          pstmt.close();
248
        }
249
        catch(SQLException ee)
250
        {
251
          throw new 
252
          SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): " + 
253
          ee.getMessage());
254
        }
255
      }//finally
256
      return result;
257
   }
258
   /** SAX Handler that is called at the start of each XML element */
259
   public void startElement(String uri, String localName,
260
                            String qName, Attributes atts)
261
               throws SAXException 
262
  {
263
      // for element <eml:eml...> qname is "eml:eml", local name is "eml"            
264
     // for element <acl....> both qname and local name is "eml"
265
     // uri is namesapce
266
     MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
267
     MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
268
     MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
269
     
270
     
271
     DBSAXNode parentNode = null;
272
     DBSAXNode currentNode = null;
273

    
274
     // Get a reference to the parent node for the id
275
     try 
276
     {
277
       parentNode = (DBSAXNode)nodeStack.peek();
278
     } 
279
     catch (EmptyStackException e) 
280
     {
281
       parentNode = null;
282
     }
283
     
284
     // If hit a text node, we need write this text for current's parent node
285
     // This will happend if the element is mixted
286
     if (hitTextNode && parentNode != null)
287
     {
288
       //compare text node data for unchangesubtree
289
       if (startCriticalSubTree)
290
       {
291
         compareTextNode(currentUnChangedableSubtreeNodeStack, textBuffer, 
292
                         PERMISSIONERROR);
293
       }//if
294
      
295
       //compare top level access module
296
       if (processTopLeverAccess && needCheckingAccessModule)
297
       {
298
          compareTextNode(currentUnchangableAccessModuleNodeStack, 
299
                          textBuffer, UPDATEACCESSERROR);
300
       }
301
       
302
       if (needCheckingAccessModule && 
303
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
304
       {
305
        // stored the pull out nodes into storedNode stack
306
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
307
                      null, null, MetaCatUtil.normalize(textBuffer.toString()));
308
        storedAccessNodeStack.push(nodeElement);
309
                                         
310
      }
311
        
312
       // write the textbuffer into db for parent node.
313
        endNodeId = writeTextForDBSAXNode(textBuffer, parentNode);
314
        // rest hitTextNode
315
        hitTextNode =false;
316
        // reset textbuffer
317
        textBuffer = null;
318
        textBuffer = new StringBuffer();
319
       
320
     }
321
     
322
  
323
     // Document representation that points to the root document node
324
     if (atFirstElement) 
325
     {
326
       atFirstElement = false;
327
       // If no DOCTYPE declaration: docname = root element
328
       // doctype = root element name or name space
329
       if (docname == null) 
330
       {
331
         docname = localName;
332
         // if uri isn't null doctype = uri(namespace)
333
         // othewise root element
334
         if (uri != null && !(uri.trim()).equals(""))
335
         {
336
           doctype = uri;
337
         }
338
         else
339
         {
340
           doctype = docname;
341
         }
342
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
343
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
344
       } 
345
       else if (doctype == null) 
346
       {
347
         // because docname is not null and it is declared in dtd
348
         // so could not be in schema, no namespace
349
         doctype = docname;
350
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
351
       }
352
       rootNode.writeNodename(docname);
353
       try 
354
       {
355
         // for validated XML Documents store a reference to XML DB Catalog
356
         // Because this is select statement and it needn't to roll back if
357
         // insert document action fialed.
358
         // In order to decrease DBConnection usage count, we get a new
359
         // dbconnection from pool
360
         String catalogid = null;
361
         DBConnection dbConn = null;
362
         int serialNumber = -1;
363

    
364
         if ( systemid != null ) 
365
         {
366
           try
367
           {
368
            // Get dbconnection
369
            dbConn=DBConnectionPool.getDBConnection
370
                                          ("DBSAXHandler.startElement");
371
            serialNumber=dbConn.getCheckOutSerialNumber();
372

    
373
            Statement stmt = dbConn.createStatement();
374
            ResultSet rs = stmt.executeQuery(
375
                          "SELECT catalog_id FROM xml_catalog " +
376
                          "WHERE entry_type = 'DTD' " +
377
                          "AND public_id = '" + doctype + "'");
378
            boolean hasRow = rs.next();
379
            if ( hasRow ) {
380
              catalogid = rs.getString(1);
381
            }
382
            stmt.close();
383
           }//try
384
           finally
385
           {
386
             // Return dbconnection
387
             DBConnectionPool.returnDBConnection(dbConn, serialNumber);
388
           }//finally
389
         }
390

    
391
         //create documentImpl object by the constructor which can specify
392
         //the revision
393
         currentDocument = new DocumentImpl(connection, rootNode.getNodeID(),
394
                               docname, doctype, docid, revision, action, user,
395
                               this.pub, catalogid, this.serverCode);
396

    
397

    
398
       } 
399
       catch (Exception ane) 
400
       {
401
         throw (new SAXException("Error in DBSaxHandler.startElement " +
402
                                 action, ane));
403
       }
404
     }
405

    
406
     // Create the current node representation
407
     currentNode = new DBSAXNode(connection, qName, localName, parentNode,
408
                                 currentDocument.getRootNodeID(),docid,
409
                                 currentDocument.getDoctype());
410
     // Use a local variable to store the element node id
411
     // If this element is a start point of subtree(section), it will be stored
412
     // otherwise, it will be discated
413
     long startNodeId = currentNode.getNodeID();
414
     // Add all of the namespaces
415
     String prefix =null;
416
     String nsuri = null;
417
     Enumeration prefixes = namespaces.keys();
418
     while ( prefixes.hasMoreElements() ) 
419
     {
420
       prefix = (String)prefixes.nextElement();
421
       nsuri = (String)namespaces.get(prefix);
422
       endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
423
     }
424
   
425

    
426
     // Add all of the attributes
427
     for (int i=0; i<atts.getLength(); i++) 
428
     {
429
       String attributeName = atts.getQName(i);
430
       String attributeValue = atts.getValue(i);
431
       endNodeId = 
432
                currentNode.setAttribute(attributeName, attributeValue, docid);
433
       
434
       // To handle name space and schema location if the attribute name is
435
       // xsi:schemaLocation. If the name space is in not in catalog table
436
       // it will be regeistered.
437
       if (attributeName != null && 
438
           attributeName.indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1)
439
       {
440
         SchemaLocationResolver resolver = 
441
                                  new SchemaLocationResolver(attributeValue);
442
         resolver.resolveNameSpace();
443
         
444
       }
445
       else if (attributeName !=null && attributeName.equals(ID))
446
       {
447
        
448
        
449
         //check unchangedable subtree hash if contains this subtree id
450
         if (unChangableSubTreeHash.containsKey(attributeValue))
451
         {
452
           // this subtree couldn't be changed by the user and move it from hash
453
           SubTree currentUnChangedableSubtree = (SubTree)
454
                                  unChangableSubTreeHash.remove(attributeValue);
455
           currentUnChangedableSubtreeNodeStack = currentUnChangedableSubtree.
456
                                                         getSubTreeNodeStack();
457
           startCriticalSubTree = true;
458
           firstElementForCriticalSubTree = true;
459
         }
460
         
461
         // handle subtree info
462
         SubTree subTress = new SubTree();
463
         // set sub tree id
464
         subTress.setSubTreeId(attributeValue);
465
         // set sub tree sstart lement name
466
         subTress.setStartElementName(currentNode.getTagName());
467
         // set start node number
468
         subTress.setStartNodeId(startNodeId);
469
         // add to stack, but it didn't get end node id yet
470
         subTreeInfoStack.push(subTress);
471
         
472
       }
473
     }//for
474
   
475
     // handle access stuff
476
     if (localName.equals(ACCESS))
477
     {
478
       // if it is in addtionalmetacat
479
       if (parentNode.getTagName() == ADDITIONALMETADATA)
480
       {
481
         processAdditionalAccess = true;
482
        
483
       }
484
       else
485
       {
486
         //make sure the access is top level
487
         // this mean current node's parent's parent should be "eml"
488
         DBSAXNode tmpNode = (DBSAXNode) nodeStack.pop();// pop out parent node
489
         //peek out grandParentNode
490
         DBSAXNode grandParentNode = (DBSAXNode)nodeStack.peek();
491
         // put parent node back
492
         nodeStack.push(tmpNode);
493
         String grandParentTag = grandParentNode.getTagName();
494
         if (grandParentTag.equals(EML))
495
         {
496
           processTopLeverAccess = true;
497
         }
498
         else
499
         {
500
           // process other access embedded into resource level module
501
           processOtherAccess = true;
502
         }
503
        
504
       }
505
       // create access object 
506
       accessObject = new AccessSection();
507
         // set permission order
508
       String permOrder = currentNode.getAttribute(ORDER);
509
       accessObject.setPermissionOrder(permOrder);
510
       // set access id
511
       String accessId = currentNode.getAttribute(ID);
512
       accessObject.setSubTreeId(accessId);
513
       accessObject.setStartNodeId(startNodeId);
514
       accessObject.setDocId(docid);
515
       
516
       // load top level node stack to currentUnchangableAccessModuleNodeStack
517
       if (processTopLeverAccess && needCheckingAccessModule)
518
       {
519
         // get the node stack for
520
         currentUnchangableAccessModuleNodeStack = 
521
                                        topAccessSection.getSubTreeNodeStack();
522
       }
523
                 
524
       
525
     }
526
     // Set up a access rule for allow
527
     else if (parentNode.getTagName() != null && 
528
       (parentNode.getTagName()).equals(ACCESS) && localName.equals(ALLOW))
529
     {
530
      
531
       accessRule = new AccessRule(); 
532
      
533
       //set permission type "allow"
534
       accessRule.setPermissionType(ALLOW);
535
      
536
     }
537
     // set up an access rule for den
538
     else if (parentNode.getTagName() != null 
539
       && (parentNode.getTagName()).equals(ACCESS) && localName.equals(DENY))
540
     {
541
       accessRule = new AccessRule();
542
       //set permission type "allow"
543
       accessRule.setPermissionType(DENY);
544
     }
545
      
546
     // Add the node to the stack, so that any text data can be
547
     // added as it is encountered
548
     nodeStack.push(currentNode);
549
     // Add the node to the vector used by thread for writing XML Index
550
     nodeIndex.addElement(currentNode);
551
    
552
    // handle critical subtree
553
    if (startCriticalSubTree && firstElementForCriticalSubTree)
554
    {
555
      //store the element name
556
      firstElementNameForCriticalSubTree = qName;
557
      firstElementForCriticalSubTree = false;
558
    }//for first element
559
    
560
    // handle critical subtree
561
    if (startCriticalSubTree)
562
    {
563
      compareElementNameSpaceAttributes(currentUnChangedableSubtreeNodeStack,
564
                                        namespaces, atts, localName, 
565
                                        PERMISSIONERROR);
566
      
567
    }
568
    //compare top access level module
569
    if (processTopLeverAccess && needCheckingAccessModule)
570
    {
571
      compareElementNameSpaceAttributes(currentUnchangableAccessModuleNodeStack, 
572
                                        namespaces, atts, localName, 
573
                                        UPDATEACCESSERROR);
574
       
575
    }
576
    
577
    // store access module element and attributes into stored stack
578
    if (needCheckingAccessModule && 
579
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
580
    {
581
       // stored the pull out nodes into storedNode stack
582
       NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT", 
583
                                localName, prefix, MetaCatUtil.normalize(null));
584
       storedAccessNodeStack.push(nodeElement);
585
       for (int i=0; i<atts.getLength(); i++) 
586
       {
587
         String attributeName = atts.getQName(i);
588
         String attributeValue = atts.getValue(i);
589
         NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2, "ATTRIBUTE",
590
                    attributeName, null, MetaCatUtil.normalize(attributeValue));
591
         storedAccessNodeStack.push(nodeAttribute);
592
       }
593
                                   
594
    }
595
   
596
    // reset name space
597
    namespaces = null;
598
    namespaces = new Hashtable();
599
  }
600
  
601
  private void compareElementNameSpaceAttributes(Stack unchangableNodeStack, 
602
                                            Hashtable nameSpaces,
603
                                            Attributes attributes,
604
                                            String localName, String error) 
605
                                            throws SAXException
606
  {
607
     //Get element subtree node stack (element node)
608
      NodeRecord elementNode = null;
609
      try
610
      {
611
        elementNode= (NodeRecord) unchangableNodeStack.pop();
612
      }
613
      catch (EmptyStackException ee)
614
      {
615
        MetaCatUtil.debugMessage("Node stack is empty for element data", 35);
616
        throw new SAXException(error);
617
      }
618
      MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
619
      MetaCatUtil.debugMessage("node type from stack: " + 
620
                                  elementNode.getNodeType(), 40);
621
      MetaCatUtil.debugMessage("node name from xml document: " + 
622
                                  localName, 40);
623
      MetaCatUtil.debugMessage("node name from stack: " +
624
                                  elementNode.getNodeName(), 40);
625
      MetaCatUtil.debugMessage("node data from stack: " +
626
                                  elementNode.getNodeData(), 40);
627
      MetaCatUtil.debugMessage("node id is: "+ elementNode.getNodeId(), 40);
628
      // if this node is not element or local name not equal or name space not
629
      // equals, throw an exception
630
      if (!elementNode.getNodeType().equals("ELEMENT") || 
631
          !localName.equals(elementNode.getNodeName()))
632
        //  (uri != null && !uri.equals(elementNode.getNodePrefix())))
633
      {
634
        MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
635
        MetaCatUtil.debugMessage("current node type from xml is ELEMENT", 40);
636
        MetaCatUtil.debugMessage("node type from stack: " + 
637
                                  elementNode.getNodeType(), 40);
638
        MetaCatUtil.debugMessage("node name from xml document: " + 
639
                                  localName, 40);
640
        MetaCatUtil.debugMessage("node name from stack: " +
641
                                  elementNode.getNodeName(), 40);
642
        MetaCatUtil.debugMessage("node data from stack: " +
643
                                  elementNode.getNodeData(), 40);
644
        MetaCatUtil.debugMessage("node id is: "+ elementNode.getNodeId(), 40);
645
        throw new SAXException(error);
646
      }
647
      
648
      //compare namespace
649
     Enumeration nameEn = nameSpaces.keys();
650
     while ( nameEn.hasMoreElements() ) 
651
     {
652
       //Get namespacke node stack (element node)
653
       NodeRecord nameNode = null;
654
       try
655
       { 
656
         nameNode = (NodeRecord) unchangableNodeStack.pop();
657
       }
658
       catch (EmptyStackException ee)
659
       {
660
         MetaCatUtil.debugMessage("Node stack is empty for namespace data", 35);
661
         throw new SAXException(error);
662
       }
663
       
664
       String prefixName = (String)nameEn.nextElement(); 
665
       String nameSpaceUri = (String)nameSpaces.get(prefixName);
666
       if (!nameNode.getNodeType().equals("NAMESPACE") || 
667
           !prefixName.equals(nameNode.getNodeName()) || 
668
           !nameSpaceUri.equals(nameNode.getNodeData()))
669
       { 
670
         MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
671
         MetaCatUtil.debugMessage("current node type from xml is NAMESPACE", 40);
672
         MetaCatUtil.debugMessage("node type from stack: " + 
673
                                  nameNode.getNodeType(), 40);
674
         MetaCatUtil.debugMessage("current node name from xml is: " + 
675
                                   prefixName, 40);
676
         MetaCatUtil.debugMessage("node name from stack: " +
677
                                  nameNode.getNodeName(), 40);
678
         MetaCatUtil.debugMessage("current node data from xml is: " + 
679
                                   nameSpaceUri, 40);
680
         MetaCatUtil.debugMessage("node data from stack: " +
681
                                  nameNode.getNodeData(), 40);
682
         MetaCatUtil.debugMessage("node id is: "+ nameNode.getNodeId(), 40);
683
         throw new SAXException(error);
684
       }
685
      
686
     }//while
687
      
688
      //compare attributes
689
      for (int i=0; i<attributes.getLength(); i++)
690
      {
691
        NodeRecord attriNode = null;
692
        try
693
        {
694
          attriNode = (NodeRecord)unchangableNodeStack.pop();
695
          
696
        }
697
        catch (EmptyStackException ee)
698
        {
699
          MetaCatUtil.debugMessage("Node stack is empty for attribute data", 35);
700
          throw new SAXException(error);
701
        }
702
        String attributeName = attributes.getQName(i);
703
        String attributeValue = attributes.getValue(i);
704
        MetaCatUtil.debugMessage("current node type from xml is ATTRIBUTE ", 40);
705
        MetaCatUtil.debugMessage("node type from stack: " + 
706
                                   attriNode.getNodeType(), 40);
707
        MetaCatUtil.debugMessage("current node name from xml is: " + 
708
                                    attributeName, 40);
709
        MetaCatUtil.debugMessage("node name from stack: " +
710
                                    attriNode.getNodeName(), 40);
711
        MetaCatUtil.debugMessage("current node data from xml is: " + 
712
                                    attributeValue, 40);
713
        MetaCatUtil.debugMessage("node data from stack: " +
714
                                    attriNode.getNodeData(), 40);
715
        MetaCatUtil.debugMessage("node id  is: "+ attriNode.getNodeId(), 40);
716
        
717
        if (!attriNode.getNodeType().equals("ATTRIBUTE") || 
718
            !attributeName.equals(attriNode.getNodeName()) ||
719
            !attributeValue.equals(attriNode.getNodeData()))
720
        {
721
          MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
722
          MetaCatUtil.debugMessage("current node type from xml is ATTRIBUTE ", 40);
723
          MetaCatUtil.debugMessage("node type from stack: " + 
724
                                   attriNode.getNodeType(), 40);
725
          MetaCatUtil.debugMessage("current node name from xml is: " + 
726
                                    attributeName, 40);
727
          MetaCatUtil.debugMessage("node name from stack: " +
728
                                    attriNode.getNodeName(), 40);
729
          MetaCatUtil.debugMessage("current node data from xml is: " + 
730
                                    attributeValue, 40);
731
          MetaCatUtil.debugMessage("node data from stack: " +
732
                                    attriNode.getNodeData(), 40);
733
          MetaCatUtil.debugMessage("node is: "+ attriNode.getNodeId(), 40);
734
          throw new SAXException(error);
735
        }
736
      }//for
737
    
738
  }
739
  
740
  /* mehtod to compare current text node and node in db*/                                         
741
  private void compareTextNode(Stack nodeStack, StringBuffer text, String error) 
742
                               throws SAXException
743
  {
744
    NodeRecord node = null;
745
    //get node from current stack
746
    try
747
    { 
748
      node = (NodeRecord)nodeStack.pop();
749
    }
750
    catch (EmptyStackException ee)
751
    {
752
      MetaCatUtil.
753
          debugMessage("Node stack is empty for text data in startElement", 35);
754
      throw new SAXException(error);
755
    }
756
    MetaCatUtil.debugMessage("current node type from xml is TEXT in start element", 40);
757
    MetaCatUtil.debugMessage("node type from stack: " + 
758
                                        node.getNodeType(), 40);
759
    MetaCatUtil.debugMessage("current node data from xml is: " + 
760
                                        text.toString(), 40);
761
    MetaCatUtil.debugMessage("node data from stack: " +
762
                                        node.getNodeData(), 40);
763
    MetaCatUtil.debugMessage("node name from stack: " +
764
                                        node.getNodeName(), 40);
765
    MetaCatUtil.debugMessage("node is: "+ node.getNodeId(), 40);              
766
    if (!node.getNodeType().equals("TEXT") || 
767
        !(text.toString()).equals(node.getNodeData())) 
768
    { 
769
      MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
770
      MetaCatUtil.debugMessage("current node type from xml is TEXT in start element", 40);
771
      MetaCatUtil.debugMessage("node type from stack: " + 
772
                                        node.getNodeType(), 40);
773
      MetaCatUtil.debugMessage("current node data from xml is: " + 
774
                                        text.toString(), 40);
775
      MetaCatUtil.debugMessage("node data from stack: " +
776
                                        node.getNodeData(), 40);
777
      MetaCatUtil.debugMessage("node name from stack: " +
778
                                        node.getNodeName(), 40);
779
      MetaCatUtil.debugMessage("node is: "+ node.getNodeId(), 40);
780
      throw new SAXException(error);
781
    }//if
782
  } 
783
  /** SAX Handler that is called at the end of each XML element */
784
   public void endElement(String uri, String localName,
785
                          String qName) throws SAXException 
786
  {
787
     MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
788

    
789
     // Get the node from the stack
790
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
791
     String currentTag = currentNode.getTagName();
792
    
793
     // If before the end element, the parser hit text nodes and store them
794
     // into the buffer, write the buffer to data base. The reason we put
795
     // write database here is for xerces some time split text node
796
     if (hitTextNode)
797
     {
798
        // get access value
799
        String data = null;
800
        // add principal
801
       if (currentTag.equals(PRINCIPAL) && accessRule != null) 
802
       {
803
          data = (textBuffer.toString()).trim();
804
          accessRule.addPrincipal(data);
805

    
806
       } 
807
       else if (currentTag.equals(PERMISSION) && accessRule != null) 
808
       {
809
         data = (textBuffer.toString()).trim();
810
         // we conbine different a permission into one value
811
         int permission = accessRule.getPermission();
812
         // add permision
813
         if ( data.toUpperCase().equals(READSTRING) ) 
814
         {
815
           permission = permission | READ;
816
         } 
817
         else if ( data.toUpperCase().equals(WRITESTRING) ) 
818
         {
819
           permission = permission | WRITE;
820
         } 
821
         else if ( data.toUpperCase().equals(CHMODSTRING)) 
822
         {
823
           permission = permission | CHMOD;
824
         } 
825
         else if ( data.toUpperCase().equals(ALLSTRING) ) 
826
         {
827
          permission = permission | ALL;
828
         }
829
         accessRule.setPermission(permission);
830
       }
831
       // put additionalmetadata/describes into vector
832
       else if (currentTag.equals(DESCRIBES))
833
       {
834
          data = (textBuffer.toString()).trim();
835
          describesId.add(data);
836
       }
837
       else if (currentTag.equals(REFERENCES) && 
838
               (processTopLeverAccess ||
839
                processAdditionalAccess || processOtherAccess))
840
       {
841
         // get reference 
842
         data = (textBuffer.toString()).trim();
843
         // put reference id into accessSection
844
         accessObject.setReferences(data);
845
         
846
       }
847
       // write text to db if it is not inline data
848
       if (!localName.equals(INLINE))
849
       {
850
          MetaCatUtil.debugMessage("Write text into DB in End Element", 50);
851
          //compare text node if need
852
          if (startCriticalSubTree)
853
          {
854
            compareTextNode(currentUnChangedableSubtreeNodeStack, textBuffer, 
855
                            PERMISSIONERROR);
856
          }//if
857
          //compare top level access module
858
          if (processTopLeverAccess && needCheckingAccessModule)
859
          {
860
             compareTextNode(currentUnchangableAccessModuleNodeStack, 
861
                            textBuffer, UPDATEACCESSERROR);
862
          }
863
          // write text node into db
864
          endNodeId = writeTextForDBSAXNode(textBuffer, currentNode);
865
       }
866
       else
867
       {
868
          MetaCatUtil.debugMessage("Write inline data into file system", 35);
869
          
870
          //check if user changed inine data or not if user doesn't have
871
          // write permission
872
          if (startCriticalSubTree)
873
          {
874
            NodeRecord node = null;
875
            String inlineData;
876
            try
877
            {
878
              node = (NodeRecord)currentUnChangedableSubtreeNodeStack.pop();
879
              // get file name from db
880
              String fileName = node.getNodeData();
881
              MetaCatUtil.debugMessage("in handle inline data", 35);
882
              MetaCatUtil.debugMessage("the inline data file name from node is: "+
883
                                      fileName, 40);
884
              inlineData = readInlineDataFromFileSystem(fileName);
885
            }
886
            catch (EmptyStackException ee)
887
            {
888
              MetaCatUtil.debugMessage("the stack is empty for text data", 32);
889
              throw new SAXException(PERMISSIONERROR);
890
            }
891
            catch (McdbException eee)
892
            {
893
              throw new SAXException(eee.getMessage());
894
            }
895
            
896
            if (!(textBuffer.toString()).equals(inlineData))
897
            {
898
              MetaCatUtil.debugMessage("inline data was changed by a user" +
899
                                       " who doesn't have permission", 30);
900
              throw new SAXException(PERMISSIONERROR);
901
            }//if
902
          }//if
903
          // write inline data into file system and return file name
904
          textBuffer = writeInlineDataIntoFile(textBuffer);
905
          // write file name into db
906
          endNodeId = writeTextForDBSAXNode(textBuffer, currentNode);
907
       }
908
       
909
       if (needCheckingAccessModule && 
910
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
911
       {
912
        // stored the pull out nodes into storedNode stack
913
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
914
                      null, null, MetaCatUtil.normalize(textBuffer.toString()));
915
        storedAccessNodeStack.push(nodeElement);
916
                                         
917
      }
918
     }//if
919
     
920
     //end crtical subtree(user doesn't have permission to write)
921
     //When reach the first element and stack is empty
922
     if (localName.equals(firstElementNameForCriticalSubTree) && 
923
         currentUnChangedableSubtreeNodeStack.isEmpty()) 
924
     {
925
       startCriticalSubTree = false;
926
     }
927
     
928
     
929
     //set hitText false
930
     hitTextNode = false;
931
     // reset textbuff
932
     textBuffer = null;
933
     textBuffer = new StringBuffer();
934
     
935
     // hand sub stree stuff
936
     if (!subTreeInfoStack.empty())
937
     {
938
       SubTree tree = (SubTree)subTreeInfoStack.peek();// get last subtree
939
       if (tree != null && tree.getStartElementName() != null && 
940
         (tree.getStartElementName()).equals(currentTag))
941
       {
942
         // find the end of sub tree and set the end node id
943
         tree.setEndNodeId(endNodeId);
944
         // add the subtree into the final store palace
945
         subTreeList.add(tree);
946
         // get rid of it from stack
947
         subTreeInfoStack.pop();
948
       }//if
949
     }//if
950

    
951
     // access stuff
952
     if (currentTag.equals(ALLOW) || currentTag.equals(DENY))
953
     {
954
       // finish parser a ccess rule and  assign it to new one
955
       AccessRule newRule = accessRule;
956
       //add the new rule to access section object
957
       accessObject.addAccessRule(newRule);
958
       // reset access rule
959
       accessRule = null;
960
     }
961
     else if (currentTag.equals(ACCESS))
962
     {
963
       // finish parse a access setction and assign it to new one
964
       accessObject.setEndNodeId(endNodeId);
965
       AccessSection newAccessObject = accessObject;
966
       if (newAccessObject != null)
967
       {
968
        // add the accessSection into a vector to store it
969
        // if it is not a reference, need to store it
970
        if ( newAccessObject.getReferences() == null)
971
        {
972
          newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
973
          accessObjectList.add(newAccessObject);
974
        }
975
        if (processTopLeverAccess)
976
        {
977
          // top level access control will handle whole document -docid
978
          topLevelAccessControlMap.put(docid, newAccessObject);
979
          // reset processtopleveraccess tag
980
          
981
        }//if
982
        else if (processAdditionalAccess)
983
        {
984
          // for additional control
985
          // put everything in describes value and access object into hash
986
       
987
          for ( int i=0; i<describesId.size(); i++)
988
          {
989
           
990
            String subId = (String)describesId.elementAt(i);
991
            if (subId != null)
992
            {
993
              additionalAccessControlMap.put(subId, newAccessObject);
994
            }//if
995
          }//for
996
          // add this hashtable in to vector
997
         
998
          additionalAccessMapList.add(additionalAccessControlMap);
999
          // reset this hashtable in order to store another additional 
1000
          //accesscontrol
1001
          additionalAccessControlMap = null;
1002
          additionalAccessControlMap = new Hashtable();
1003
        }//if
1004
       }//if
1005
       //check if  access node stack is empty after parsing top access
1006
       //module
1007
       if (!currentUnchangableAccessModuleNodeStack.isEmpty() &&
1008
           processTopLeverAccess && needCheckingAccessModule)
1009
       {
1010
         MetaCatUtil.debugMessage("Access node stack is not empty after " + 
1011
                                   "parsing access subtree", 40);
1012
         throw new SAXException(UPDATEACCESSERROR);
1013
                                  
1014
       }
1015
       //reset access section object
1016
       accessObject = null;
1017
       // reset tmp stored node stack
1018
       storedAccessNodeStack = null;
1019
       storedAccessNodeStack = new Stack();
1020
       // reset flag
1021
       processAdditionalAccess =false;
1022
       processTopLeverAccess =false;
1023
       processOtherAccess = false;
1024
      
1025
     }
1026
     else if (currentTag.equals(ADDITIONALMETADATA))
1027
     {
1028
        //reset describesId
1029
        describesId = null;
1030
        describesId = new Vector();
1031
     }
1032
   }
1033
   
1034
   /**
1035
    * SAX Handler that receives notification of comments in the DTD
1036
    */
1037
   public void comment(char[] ch, int start, int length) throws SAXException {
1038
     MetaCatUtil.debugMessage("COMMENT", 50);
1039
     if ( !processingDTD ) 
1040
     {
1041
       DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
1042
       String str = new String(ch, start, length);
1043
       
1044
       //compare comment if need
1045
       if (startCriticalSubTree)
1046
       {
1047
         compareCommentNode(currentUnChangedableSubtreeNodeStack, str, 
1048
                            PERMISSIONERROR);
1049
       }//if
1050
       //compare top level access module
1051
       if (processTopLeverAccess && needCheckingAccessModule)
1052
       {
1053
         compareCommentNode(currentUnchangableAccessModuleNodeStack, str,
1054
                            UPDATEACCESSERROR);
1055
       }
1056
       endNodeId = currentNode.writeChildNodeToDB("COMMENT", null, str, docid);
1057
       if (needCheckingAccessModule && 
1058
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1059
       {
1060
        // stored the pull out nodes into storedNode stack
1061
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "COMMENT", 
1062
                                        null, null, MetaCatUtil.normalize(str));
1063
        storedAccessNodeStack.push(nodeElement);
1064
                                         
1065
      }
1066
     }
1067
   }
1068
   
1069
   /* Comparet comment from xml and db */
1070
   private void compareCommentNode(Stack nodeStack, String string, String error)
1071
                                   throws SAXException
1072
   {
1073
     NodeRecord node = null;
1074
     try
1075
     {
1076
       node = (NodeRecord)nodeStack.pop();
1077
     }
1078
     catch (EmptyStackException ee)
1079
     {
1080
       MetaCatUtil.debugMessage("the stack is empty for comment data", 32);
1081
       throw new SAXException(error);
1082
     }
1083
     MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
1084
     MetaCatUtil.debugMessage("node type from stack: " + 
1085
                                    node.getNodeType(), 40);
1086
     MetaCatUtil.debugMessage("current node data from xml is: " + 
1087
                                    string, 40);
1088
     MetaCatUtil.debugMessage("node data from stack: " +
1089
                                    node.getNodeData(), 40);
1090
     MetaCatUtil.debugMessage("node is from stack: " + 
1091
                                    node.getNodeId(), 40);
1092
     // if not consistent terminate program and throw a exception
1093
     if (!node.getNodeType().equals("COMMENT") || 
1094
         !string.equals(node.getNodeData())) 
1095
     { 
1096
       MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1097
       MetaCatUtil.debugMessage("current node type from xml is COMMENT", 40);
1098
       MetaCatUtil.debugMessage("node type from stack: " + 
1099
                                    node.getNodeType(), 40);
1100
       MetaCatUtil.debugMessage("current node data from xml is: " + 
1101
                                    string, 40);
1102
       MetaCatUtil.debugMessage("node data from stack: " +
1103
                                    node.getNodeData(), 40);
1104
       MetaCatUtil.debugMessage("node is from stack: " + 
1105
                                        node.getNodeId(), 40);
1106
       throw new SAXException(error);
1107
     }//if
1108
   }
1109
   
1110
      /**
1111
    * SAX Handler that is called for each XML text node that is
1112
    * Ignorable white space
1113
    */
1114
   public void ignorableWhitespace(char[] cbuf, int start, int len)
1115
               throws SAXException 
1116
  {
1117
     // When validation is turned "on", white spaces are reported here
1118
     // When validation is turned "off" white spaces are not reported here,
1119
     // but through characters() callback
1120
     MetaCatUtil.debugMessage("IGNORABLEWHITESPACE", 50);
1121
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
1122
     String data = null;
1123
     int leftover = len;
1124
     int offset = start;
1125
     boolean moredata = true;
1126

    
1127
     // This loop deals with the case where there are more characters
1128
     // than can fit in a single database text field (limit is
1129
     // MAXDATACHARS).  If the text to be inserted exceeds MAXDATACHARS,
1130
     // write a series of nodes that are MAXDATACHARS long, and then the
1131
     // final node contains the remainder
1132
     while (moredata) 
1133
     {
1134
       if (leftover > MAXDATACHARS) 
1135
       {
1136
         data = new String(cbuf, offset, MAXDATACHARS);
1137
         leftover -= MAXDATACHARS;
1138
         offset += MAXDATACHARS;
1139
       } 
1140
       else 
1141
       {
1142
         data = new String(cbuf, offset, leftover);
1143
         moredata = false;
1144
       }
1145

    
1146
       //compare whitespace if need
1147
       if (startCriticalSubTree)
1148
       {
1149
         compareWhiteSpace(currentUnChangedableSubtreeNodeStack, data, 
1150
                           PERMISSIONERROR);
1151
       }//if
1152
       
1153
       //compare whitespace in access top module
1154
       if (processTopLeverAccess && needCheckingAccessModule)
1155
       {
1156
         compareWhiteSpace(currentUnchangableAccessModuleNodeStack, data, 
1157
                           UPDATEACCESSERROR);
1158
       }
1159
       // Write the content of the node to the database
1160
       if (needCheckingAccessModule && 
1161
       (processAdditionalAccess || processOtherAccess || processTopLeverAccess))
1162
       {
1163
        // stored the pull out nodes into storedNode stack
1164
        NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", 
1165
                                     null, null, MetaCatUtil.normalize(data));
1166
        storedAccessNodeStack.push(nodeElement);
1167
                                         
1168
       }
1169
       endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data, docid);
1170
     }
1171
   }
1172
   
1173
   /* Compare whitespace from xml and db */
1174
   private void compareWhiteSpace(Stack nodeStack, String string, String error)
1175
                                  throws SAXException
1176
   {
1177
      NodeRecord node = null;
1178
      try
1179
      {
1180
        node = (NodeRecord)nodeStack.pop();
1181
      }
1182
      catch (EmptyStackException ee)
1183
      {
1184
        MetaCatUtil.debugMessage("the stack is empty for whitespace data", 32);
1185
        throw new SAXException(error);
1186
      }
1187
      if (!node.getNodeType().equals("TEXT") || 
1188
          !string.equals(node.getNodeData())) 
1189
      { 
1190
        MetaCatUtil.debugMessage("Inconsistence happend: ", 40);
1191
        MetaCatUtil.debugMessage("current node type from xml is WHITESPACE TEXT", 40);
1192
        MetaCatUtil.debugMessage("node type from stack: " + 
1193
                                  node.getNodeType(), 40);
1194
        MetaCatUtil.debugMessage("current node data from xml is: " + 
1195
                                  string, 40);
1196
        MetaCatUtil.debugMessage("node data from stack: " +
1197
                                  node.getNodeData(), 40);
1198
        MetaCatUtil.debugMessage("node is from stack: " + 
1199
                                  node.getNodeId(), 40);
1200
        throw new SAXException(error);
1201
     }//if
1202
   }
1203
   
1204
   /** SAX Handler that receives notification of end of the document */
1205
   public void endDocument() throws SAXException 
1206
   {
1207
     MetaCatUtil.debugMessage("end Document", 50);
1208
     // There are some unchangable subtree didn't be compare
1209
     // This maybe cause user change the subtree id
1210
     if (!unChangableSubTreeHash.isEmpty())
1211
     {
1212
       MetaCatUtil.debugMessage("The unChangealbe subtree is not empty", 40);
1213
       throw new SAXException(PERMISSIONERROR);
1214
     }
1215
     
1216
     // write access rule to db
1217
     writeAccessRuleToDB();
1218
   
1219
     // Starting new thread for writing XML Index.
1220
     // It calls the run method of the thread.
1221
     try 
1222
     {
1223
       xmlIndex.start();
1224
     } 
1225
     catch (NullPointerException e) 
1226
     {
1227
       xmlIndex = null;
1228
       throw new
1229
       SAXException("Problem with starting thread for writing XML Index. " +
1230
                    e.getMessage());
1231
     }
1232
   
1233
   }
1234
   
1235
  /* The method to write all access rule intodb */
1236
  private void writeAccessRuleToDB() throws SAXException
1237
  {
1238
    //Delete old permssion
1239
    deletePermissionsInAccessTable(docid);
1240
    //write top leve access rule
1241
    writeTopLevelAccessRuleToDB();
1242
    //write additional access rule
1243
    //writeAddtionalAccessRuleToDB();
1244
  }//writeAccessRuleToDB
1245
   
1246
  /* The method to write top level access rule into db. */
1247
  private void writeTopLevelAccessRuleToDB() throws SAXException
1248
  {
1249
    
1250
    // for top document level
1251
    Object accessSection = topLevelAccessControlMap.get(docid);
1252
    boolean top = true;
1253
    String subSectionId = null;
1254
    if ( accessSection != null )
1255
    {
1256
       AccessSection accessSectionObj = (AccessSection)accessSection;
1257
           
1258
       // if accessSection is not null and is not reference
1259
       if ( accessSectionObj.getReferences() == null)
1260
       {
1261
          // write the top level access module into xml_accesssubtree to store info
1262
          // and then when update to check if the user can update it or not
1263
          deleteAccessSubTreeRecord(docid);
1264
          writeAccessSubTreeIntoDB(accessSectionObj,TOPLEVEL);
1265
          //write access section into xml_access table
1266
          writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1267
       }
1268
       else
1269
       {
1270
   
1271
        // this is a reference and go trough the vector which contains all
1272
        // access object
1273
        String referenceId = accessSectionObj.getReferences();
1274
        boolean findAccessObject = false;
1275
        MetaCatUtil.debugMessage("referered id for top access: "+ 
1276
                               referenceId, 35);
1277
        for (int i=0; i<accessObjectList.size(); i++)
1278
        {
1279
          AccessSection accessObj = (AccessSection)accessObjectList.elementAt(i);
1280
          String accessObjId = accessObj.getSubTreeId();
1281
          if (referenceId != null && accessObj != null &&
1282
              referenceId.equals(accessObjId))
1283
          {
1284
            // make sure the user didn't change any thing in this access moduel
1285
            // too if user doesn't have all permission
1286
            if (needCheckingAccessModule)
1287
            {
1288
              
1289
              Stack newStack = accessObj.getStoredTmpNodeStack();
1290
              //revise order
1291
              newStack = MetaCatUtil.reviseStack(newStack);
1292
               // go throught the vector of unChangableAccessSubtreevector
1293
              // and find the one whose id is as same as referenceid
1294
              AccessSection oldAccessObj = 
1295
                       getAccessSectionFromUnchangableAccessVector(referenceId);
1296
              //if oldAccessObj is null something is wrong
1297
              if (oldAccessObj == null)
1298
              {
1299
                throw new SAXException(UPDATEACCESSERROR);
1300
              }//if
1301
              else
1302
              {
1303
                // Get the node stack from old access obj
1304
                Stack oldStack = oldAccessObj.getSubTreeNodeStack();
1305
                comparingNodeStacks(newStack, oldStack);
1306
              }//else
1307
            }//if
1308
            
1309
            writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1310
            //write the reference access into xml_accesssubtree too
1311
             // write the top level access module into xml_accesssubtree to store info
1312
             // and then when update to check if the user can update it or not
1313
            deleteAccessSubTreeRecord(docid);
1314
            writeAccessSubTreeIntoDB(accessSectionObj,TOPLEVEL);
1315
            writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1316
            findAccessObject = true;
1317
            break;
1318
          }
1319
        }//for
1320
        // if we couldn't find an access subtree id for this reference id
1321
        if (!findAccessObject)
1322
        {
1323
          throw new SAXException("The referenceid: " + referenceId +
1324
                               " is not access subtree");
1325
        }//if
1326
      }//else
1327
      
1328
     
1329
    }//if
1330
    else
1331
    {
1332
      // couldn't find a access section object 
1333
      MetaCatUtil.debugMessage("couldn't find access control for document: "+
1334
                                docid, 35);
1335
    }
1336
    
1337
  }//writeTopLevelAccessRuletoDB
1338
  
1339
  /* Given a subtree id and find the responding access section*/
1340
  private AccessSection getAccessSectionFromUnchangableAccessVector(String id)
1341
  {
1342
    AccessSection result = null;
1343
    // Makse sure the id
1344
    if (id == null || id.equals(""))
1345
    {
1346
      return result;
1347
    }
1348
    // go throught vector and find the list
1349
    for (int i=0; i<unChangableAccessSubTreeVector.size();i++)
1350
    {
1351
      AccessSection accessObj = (AccessSection)
1352
                                 unChangableAccessSubTreeVector.elementAt(i);
1353
      if (accessObj.getSubTreeId() != null && 
1354
         (accessObj.getSubTreeId()).equals(id))
1355
      {
1356
        result = accessObj;
1357
      }//if
1358
    }//for
1359
    return result;
1360
  }//getAccessSectionFromUnchangableAccessVector
1361
      
1362
  /* Compare two node stacks to see if they are same */
1363
  private void comparingNodeStacks(Stack stack1, Stack stack2) 
1364
                                 throws SAXException
1365
  {
1366
    // make sure stack1 and stack2 are not empty
1367
    if (stack1.isEmpty() || stack2.isEmpty())
1368
    {
1369
      MetaCatUtil.debugMessage("Because stack is empty!", 35);
1370
      throw new SAXException(UPDATEACCESSERROR);
1371
    }
1372
    // go throw two stacks and compare every element
1373
    while (!stack1.isEmpty())
1374
    {
1375
      // Pop an element from stack1
1376
      NodeRecord record1 = (NodeRecord) stack1.pop();
1377
      // Pop an element from stack2(stack 2 maybe empty)
1378
      NodeRecord record2 = null;
1379
      try
1380
      {
1381
        record2 = (NodeRecord) stack2.pop();
1382
      }
1383
      catch (EmptyStackException ee)
1384
      {
1385
        MetaCatUtil.debugMessage("Node stack2 is empty but stack1 isn't!", 35);
1386
        throw new SAXException(UPDATEACCESSERROR);
1387
      }
1388
      // if two records are not same throw a exception
1389
      if (!record1.contentEquals(record2))
1390
      {
1391
        MetaCatUtil.debugMessage("Two records from new and old stack are not "+
1392
                                 "same!", 30);
1393
        throw new SAXException(UPDATEACCESSERROR);
1394
      }//if
1395
    }//while
1396
    
1397
    // now stack1 is empty and we should make sure stack2 is empty too
1398
    if(!stack2.isEmpty())
1399
    {
1400
      MetaCatUtil.debugMessage("stack2 still have some elements while stack "+
1401
                               "is empty! ", 30);
1402
      throw new SAXException(UPDATEACCESSERROR);
1403
    }//if
1404
 }//comparingNodeStacks
1405
  
1406
   /* The method to write addtional access rule into db. */
1407
  private void writeAddtionalAccessRuleToDB() throws SAXException
1408
  {
1409
    
1410
     PreparedStatement pstmt = null;
1411
     boolean topLevel =false;
1412
    // go through the vector which contains the additional access control 
1413
    //hashtable. Each hashtable has info for one additonalmetadata container 
1414
   for (int j= 0; j < additionalAccessMapList.size(); j++)
1415
   {
1416
     
1417
     Hashtable accessControlMap = 
1418
                                (Hashtable)additionalAccessMapList.elementAt(j);
1419
     // additional access rule
1420
     Enumeration en = accessControlMap.keys();
1421
     
1422
     while(en.hasMoreElements())
1423
     {
1424
       try
1425
       {
1426
         // Get subsection id
1427
          String subSectionId = (String)en.nextElement();
1428
          MetaCatUtil.debugMessage("sub section id in additional access mapping"
1429
                                   +"(go through): "+ subSectionId, 35);
1430
          
1431
          if (subSectionId == null)
1432
          {
1433
            // if id is null, terminate the program
1434
            throw new SAXException("subtree id is null");
1435
          }
1436
          // Get AccessSection Object
1437
          Object accessSectionObj = accessControlMap.get(subSectionId);
1438
          if (accessSectionObj == null)
1439
          {
1440
            // if accesssection is null, terminate the program
1441
            throw new SAXException("access subtree is null");
1442
          }
1443
          else
1444
          {
1445
            AccessSection accessControlObj = (AccessSection)accessSectionObj;
1446
            // if the access section is not references, write it to db
1447
            if (accessControlObj.getReferences() == null)
1448
            {
1449
              writeGivenAccessRuleIntoDB(accessControlObj, topLevel, 
1450
                                         subSectionId);
1451
            }
1452
            else
1453
            {
1454
              // this is a reference and go trough the vector which contains all
1455
              // access object
1456
              String referenceId = accessControlObj.getReferences();
1457
            
1458
              boolean findAccessObject = false;
1459
              MetaCatUtil.debugMessage("referered id for additional access "+
1460
                                     "mapping(go through): "+ referenceId, 35);
1461
              for (int i=0; i<accessObjectList.size(); i++)
1462
              {
1463
                AccessSection accessObj = 
1464
                                (AccessSection)accessObjectList.elementAt(i);
1465
                String accessObjId = accessObj.getSubTreeId();
1466
                MetaCatUtil.debugMessage("access obj id in the list(go through): "
1467
                                        + accessObjId, 35);
1468
                if (referenceId != null && accessObj != null &&
1469
                    referenceId.equals(accessObjId))
1470
                {
1471
                  writeGivenAccessRuleIntoDB(accessObj, topLevel, subSectionId);
1472
                  findAccessObject = true;
1473
                }//if
1474
              }//for
1475
              // if we couldn't find an access subtree id for this reference id
1476
              if (!findAccessObject)
1477
              {
1478
                throw new SAXException("The referenceid: " + referenceId +
1479
                               " is not access subtree");
1480
              }//if
1481
            }//else
1482
          }//else
1483
       }//try
1484
       catch (Exception e)
1485
       {
1486
         
1487
         MetaCatUtil.debugMessage("error in EmlSAXHandler.writeAddtionalAccess"
1488
                                   + ": "+e.getMessage(), 30);
1489
         throw new SAXException(e.getMessage());
1490
       }
1491
     }//while
1492
    }//for
1493
  }//writeAccessRuletoDB
1494
  
1495
  /* Write a gaven access rule into db*/
1496
  private void writeGivenAccessRuleIntoDB(AccessSection accessSection, 
1497
                                         boolean topLevel, String subSectionId) 
1498
                                         throws SAXException
1499
  {
1500
     if (accessSection == null)
1501
     {
1502
       throw new SAXException("The access object is null");
1503
     }
1504
     
1505
      String permOrder = accessSection.getPermissionOrder();
1506
      String sql = null;
1507
      PreparedStatement pstmt = null;
1508
      if (topLevel)
1509
      {
1510
        sql = "INSERT INTO xml_access (docid, principal_name, permission, "+
1511
                 "perm_type, perm_order, accessfileid) VALUES " +
1512
                 " (?, ?, ?, ?, ?, ?)";
1513
      }
1514
      else
1515
      {
1516
        sql ="INSERT INTO xml_access (docid,principal_name, "+ 
1517
             "permission, perm_type, perm_order, accessfileid, subtreeid, "+
1518
             " startnodeid, endnodeid) VALUES" +
1519
             " (?, ?, ?, ?, ?, ?, ?, ?, ?)";
1520
      }
1521
      try 
1522
      {
1523
     
1524
        pstmt = connection.prepareStatement(sql);
1525
        // Increase DBConnection usage count
1526
        connection.increaseUsageCount(1);
1527
        // Bind the values to the query
1528
        pstmt.setString(1, docid);
1529
        MetaCatUtil.debugMessage("Docid in accesstable: "+ docid, 35);
1530
        pstmt.setString(6, docid);
1531
        MetaCatUtil.debugMessage("Accessfileid in accesstable: "+ docid, 35);
1532
        pstmt.setString(5, permOrder);
1533
        MetaCatUtil.debugMessage("PermOder in accesstable: "+ permOrder, 35);
1534
        // if it is not top level, set subsection id
1535
        if (!topLevel)
1536
        {
1537
          long startNodeId = 0;
1538
          long endNodeId = 0;
1539
          // for subtree should specify the
1540
          if (subSectionId == null)
1541
          {
1542
            throw new SAXException("The subsection is null");
1543
          }
1544
          // go through the substree list vector and found the start node id
1545
          // and stop node id for this subtree id
1546
          for (int i=0; i<subTreeList.size(); i++)
1547
          {
1548
            SubTree tree = (SubTree)subTreeList.elementAt(i);
1549
            String subTreeId = tree.getSubTreeId();
1550
            if (subSectionId.equals(subTreeId))
1551
            {
1552
              startNodeId = tree.getStartNodeId();
1553
              endNodeId = tree.getEndNodeId(); 
1554
            }//if
1555
          }//for
1556
          if (startNodeId == 0 || endNodeId == 0)
1557
          {
1558
            throw new SAXException("Could find the subtree"
1559
                                   + "for this id: "+subSectionId);
1560
          }
1561
          pstmt.setString(7, subSectionId);
1562
          MetaCatUtil.debugMessage("SubSectionId in accesstable: "+ 
1563
                                    subSectionId, 35);
1564
          pstmt.setLong(8, startNodeId);
1565
          MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
1566
          pstmt.setLong(9, endNodeId);
1567
          MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1568
          
1569
        }
1570
      
1571
        Vector accessRules = accessSection.getAccessRules();
1572
        // go through every rule
1573
        for (int i=0; i<accessRules.size(); i++)
1574
        {
1575
          AccessRule rule = (AccessRule)accessRules.elementAt(i);
1576
          String permType = rule.getPermissionType();
1577
          int permission = rule.getPermission();
1578
          pstmt.setInt(3, permission);
1579
          MetaCatUtil.debugMessage("permission in accesstable: "+ permission, 35);
1580
          pstmt.setString(4, permType);
1581
          MetaCatUtil.debugMessage("Permtype in accesstable: "+ permType, 35);
1582
          // go through every principle in rule
1583
          Vector nameVector = rule.getPrincipal();
1584
          for ( int j = 0; j < nameVector.size(); j++ ) 
1585
          {
1586
            String prName = (String)nameVector.elementAt(j);
1587
            pstmt.setString(2, prName);
1588
            MetaCatUtil.debugMessage("Principal in accesstable: "+prName, 35);
1589
            pstmt.execute();
1590
          }//for
1591
        }//for
1592
        pstmt.close();
1593
      }//try 
1594
      catch (SQLException e) 
1595
      {
1596
        throw new 
1597
        SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + e.getMessage());
1598
      }//catch
1599
      finally
1600
      {
1601
        try
1602
        {
1603
          pstmt.close();
1604
        }
1605
        catch(SQLException ee)
1606
        {
1607
          throw new 
1608
          SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + 
1609
          ee.getMessage());
1610
        }
1611
      }//finally
1612
     
1613
  }//writeGivenAccessRuleIntoDB
1614
  
1615
  /* Delete from db all permission for resources related to @aclid if any.*/
1616
  private void deletePermissionsInAccessTable(String aclid) 
1617
          throws SAXException 
1618
  {
1619
    Statement stmt = null;
1620
    try
1621
    {
1622
      // delete all acl records for resources related to @aclid if any
1623
      stmt = connection.createStatement();
1624
      // Increase DBConnection usage count
1625
      connection.increaseUsageCount(1);
1626
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid +
1627
                   "'"); 
1628
    
1629
    }
1630
    catch (SQLException e)
1631
    {
1632
      throw new SAXException(e.getMessage());
1633
    }
1634
    finally
1635
    {
1636
      try
1637
      {
1638
        stmt.close();
1639
      }
1640
      catch (SQLException ee)
1641
      {
1642
        throw new SAXException(ee.getMessage());
1643
      }
1644
    }
1645
  }//deletePermissionsInAccessTable
1646
  
1647
  
1648
  /* In order to make sure only usr has "all" permission can update access
1649
   * subtree in eml document we need to keep access subtree info in 
1650
   * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1651
   */
1652
  private void writeAccessSubTreeIntoDB(AccessSection accessSection, 
1653
                                         String level) 
1654
                                         throws SAXException
1655
  {
1656
     if (accessSection == null)
1657
     {
1658
       throw new SAXException("The access object is null");
1659
     }
1660
     
1661
      String sql = null;
1662
      PreparedStatement pstmt = null;
1663
      sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "+
1664
                 "subtreeid, startnodeid, endnodeid) VALUES " +
1665
                 " (?, ?, ?, ?, ?, ?)";
1666
      try 
1667
      {
1668
     
1669
        pstmt = connection.prepareStatement(sql);
1670
        // Increase DBConnection usage count
1671
        connection.increaseUsageCount(1);
1672
        long startNodeId = accessSection.getStartNodeId();
1673
        long endNodeId = accessSection.getEndNodeId();
1674
        String sectionId = accessSection.getSubTreeId();
1675
        // Bind the values to the query
1676
        pstmt.setString(1, docid);
1677
        MetaCatUtil.debugMessage("Docid in access-subtreetable: "+ docid, 35);
1678
        pstmt.setString(2, revision );
1679
        MetaCatUtil.debugMessage("rev in accesssubtreetable: "+ revision, 35);
1680
        pstmt.setString(3, level);
1681
        MetaCatUtil.debugMessage("contorl level in access-subtree table: "+
1682
                                  level, 35);
1683
        pstmt.setString(4, sectionId);
1684
        MetaCatUtil.debugMessage("Subtree id in access-subtree table: "+ 
1685
                                  sectionId, 35);
1686
        pstmt.setLong(5, startNodeId);
1687
        MetaCatUtil.debugMessage("Start node id is: " + startNodeId, 35);
1688
        pstmt.setLong(6, endNodeId);
1689
        MetaCatUtil.debugMessage("End node id is: " + endNodeId, 35);
1690
        pstmt.execute();
1691
        pstmt.close();
1692
      }//try 
1693
      catch (SQLException e) 
1694
      {
1695
        throw new 
1696
        SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): " + 
1697
                      e.getMessage());
1698
      }//catch
1699
      finally
1700
      {
1701
        try
1702
        {
1703
          pstmt.close();
1704
        }
1705
        catch(SQLException ee)
1706
        {
1707
          throw new 
1708
          SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): " + 
1709
          ee.getMessage());
1710
        }
1711
      }//finally
1712
     
1713
  }//writeAccessSubtreeIntoDB
1714
  
1715
   /* Delete every access subtree record from xml_accesssubtree.*/
1716
  private void deleteAccessSubTreeRecord(String docId) throws SAXException 
1717
  {
1718
    Statement stmt = null;
1719
    try
1720
    {
1721
      // delete all acl records for resources related to @aclid if any
1722
      stmt = connection.createStatement();
1723
      // Increase DBConnection usage count
1724
      connection.increaseUsageCount(1);
1725
      stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '" + docId + "'"); 
1726
   
1727
    }
1728
    catch (SQLException e)
1729
    {
1730
      throw new SAXException(e.getMessage());
1731
    }
1732
    finally
1733
    {
1734
      try
1735
      {
1736
        stmt.close();
1737
      }
1738
      catch (SQLException ee)
1739
      {
1740
        throw new SAXException(ee.getMessage());
1741
      }
1742
    }
1743
  }//deleteAccessSubTreeRecord
1744
  
1745
  // write inline data into file system and return file name(without path)
1746
  private StringBuffer writeInlineDataIntoFile(StringBuffer data) 
1747
                                               throws SAXException
1748
  {
1749
    StringBuffer fileNameBuffer = null;
1750
    String fileName = null;
1751
    String docidWithoutRev = MetaCatUtil.getDocIdFromString(docid);
1752
    String path = MetaCatUtil.getOption("inlinedatafilepath");
1753
    String seperator = MetaCatUtil.getOption("accNumSeparator");
1754
    // the new file name will look like path/docid.rev.2
1755
    fileName = docidWithoutRev + seperator+revision+seperator +inLineDataIndex;
1756
    File inlineDataDirectory = new File(path);
1757
    File newFile = new File(inlineDataDirectory, fileName); 
1758
    // incease inLinedataindex for next one
1759
    inLineDataIndex++ ;
1760
    try
1761
    {
1762
      FileWriter writer = new FileWriter(newFile);
1763
      writer.write(data.toString());
1764
      writer.close();
1765
    }
1766
    catch (Exception e)
1767
    {
1768
      throw new SAXException(e.getMessage());
1769
    }
1770
    
1771
    fileNameBuffer = new StringBuffer(fileName);
1772
    return fileNameBuffer;
1773
  }
1774
  
1775
  /* In eml2, the inline data wouldn't store in db, it store in file system
1776
   * The db stores file name(without path).
1777
   */
1778
  public static String readInlineDataFromFileSystem(String fileName) 
1779
                                              throws McdbException
1780
  {
1781
    String data = null;
1782
    String path = MetaCatUtil.getOption("inlinedatafilepath");
1783
    // the new file name will look like path/docid.rev.2
1784
    File inlineDataDirectory = new File(path);
1785
    File dataFile = new File(inlineDataDirectory, fileName);
1786
    try
1787
    {
1788
      FileReader fileReader = new FileReader(dataFile);
1789
      BufferedReader stringReader = new BufferedReader(fileReader);
1790
      // read first line of data
1791
      String tmp = stringReader.readLine();
1792
      // pass first line data to data varible
1793
      data = tmp;
1794
      // at the end tmp will be null
1795
      while (tmp != null)
1796
      {
1797
        // read a new line
1798
        tmp = stringReader.readLine();
1799
        // append new line to data
1800
        if (tmp != null)
1801
        {
1802
          data = data+tmp;
1803
        }
1804
      }
1805
      
1806
    }
1807
    catch (Exception e)
1808
    {
1809
      throw new McdbException(e.getMessage());
1810
    }
1811
    MetaCatUtil.debugMessage("the inline data retrieve from file: "+data, 50);
1812
    return data;
1813
  }
1814
}
(33-33/56)