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

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

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

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

    
433

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

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

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

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

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

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

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

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