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

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

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

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

    
434

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

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

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

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

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

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

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

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