Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author: tao $'
11
 *     '$Date: 2003-02-14 17:23:36 -0800 (Fri, 14 Feb 2003) $'
12
 * '$Revision: 1410 $'
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.StringReader;
33
import java.util.Stack;
34
import java.util.Vector;
35
import java.util.Hashtable;
36
import java.util.Enumeration;
37
import java.util.EmptyStackException;
38

    
39
import org.xml.sax.Attributes;
40
import org.xml.sax.SAXException;
41
import org.xml.sax.SAXParseException;
42
import org.xml.sax.ext.DeclHandler;
43
import org.xml.sax.ext.LexicalHandler;
44
import org.xml.sax.helpers.DefaultHandler;
45

    
46
/**
47
 * A database aware Class implementing callback bethods for the SAX parser to
48
 * call when processing the XML stream and generating events
49
 */
50
public class EmlSAXHandler extends DBSAXHandler implements 
51
                                                      AccessControlInterface
52
{
53
   private Vector allowRules = new Vector();
54
   private Vector denyRules = new Vector();
55
   private String documentId = null;
56
   private Vector subDocumentIdList = new Vector();
57
   private boolean processTopLeverAccess = false;
58
   private boolean processAdditionalAccess = false;
59
   private AccessSection accessObject= null;
60
   private AccessRule accessRule = null;
61
   private Hashtable topLevelAccessControlMap = new Hashtable();
62
   private Hashtable additionalAccessControlMap = new Hashtable();
63
   
64
   
65
   // Constant
66
   private static final String DESCRIBES = "describes";
67
   private static final String ADDITIONALMETADATA = "additionalMetadata";
68
   private static final String ORDER = "order";
69
   private static final String ID ="id";
70
    
71
    /** Construct an instance of the handler class
72
    *
73
    * @param conn the JDBC connection to which information is written
74
    * @param action - "INSERT" or "UPDATE"
75
    * @param docid to be inserted or updated into JDBC connection
76
    * @param user the user connected to MetaCat servlet and owns the document
77
    * @param groups the groups to which user belongs
78
    * @param pub flag for public "read" access on document
79
    * @param serverCode the serverid from xml_replication on which this document
80
    *        resides.
81
    *
82
    */
83
   public EmlSAXHandler(DBConnection conn, String action, String docid,
84
                      String user, String[] groups, String pub, int serverCode)
85
   {
86
     super(conn, action, docid, user, groups, pub, serverCode);
87
   }
88
   
89
    /** Construct an instance of the handler class
90
    * In this constructor, user can specify the version need to upadate
91
    *
92
    * @param conn the JDBC connection to which information is written
93
    * @param action - "INSERT" or "UPDATE"
94
    * @param docid to be inserted or updated into JDBC connection
95
    * @param revision, the user specified the revision need to be update
96
    * @param user the user connected to MetaCat servlet and owns the document
97
    * @param groups the groups to which user belongs
98
    * @param pub flag for public "read" access on document
99
    * @param serverCode the serverid from xml_replication on which this document
100
    *        resides.
101
    *
102
    */
103
   public EmlSAXHandler(DBConnection conn, String action, String docid,
104
     String revision, String user, String[] groups, String pub, int serverCode)
105
   {
106
     super(conn, action, docid, revision, user, groups, pub, serverCode);
107
   }
108
   
109
   /** SAX Handler that is called at the start of each XML element */
110
   public void startElement(String uri, String localName,
111
                            String qName, Attributes atts)
112
               throws SAXException 
113
  {
114
      // for element <eml:eml...> qname is "eml:eml", local name is "eml"            
115
     // for element <acl....> both qname and local name is "eml"
116
     // uri is namesapce
117
     MetaCatUtil.debugMessage("Start ELEMENT(qName) " + qName, 50);
118
     MetaCatUtil.debugMessage("Start ELEMENT(localName) " + localName, 50);
119
     MetaCatUtil.debugMessage("Start ELEMENT(uri) " + uri, 50);
120
     
121
     
122
     DBSAXNode parentNode = null;
123
     DBSAXNode currentNode = null;
124

    
125
     // Get a reference to the parent node for the id
126
     try {
127
       parentNode = (DBSAXNode)nodeStack.peek();
128
     } catch (EmptyStackException e) {
129
       parentNode = null;
130
     }
131

    
132
     // Document representation that points to the root document node
133
     if (atFirstElement) 
134
     {
135
       atFirstElement = false;
136
       // If no DOCTYPE declaration: docname = root element
137
       // doctype = root element name or name space
138
       if (docname == null) 
139
       {
140
         docname = localName;
141
         // if uri isn't null doctype = uri(namespace)
142
         // othewise root element
143
         if (uri != null && !(uri.trim()).equals(""))
144
         {
145
           doctype = uri;
146
         }
147
         else
148
         {
149
           doctype = docname;
150
         }
151
         MetaCatUtil.debugMessage("DOCNAME-a: " + docname, 30);
152
         MetaCatUtil.debugMessage("DOCTYPE-a: " + doctype, 30);
153
       } 
154
       else if (doctype == null) 
155
       {
156
         // because docname is not null and it is declared in dtd
157
         // so could not be in schema, no namespace
158
         doctype = docname;
159
         MetaCatUtil.debugMessage("DOCTYPE-b: " + doctype, 30);
160
       }
161
       rootNode.writeNodename(docname);
162
       try {
163
         // for validated XML Documents store a reference to XML DB Catalog
164
         // Because this is select statement and it needn't to roll back if
165
         // insert document action fialed.
166
         // In order to decrease DBConnection usage count, we get a new
167
         // dbconnection from pool
168
         String catalogid = null;
169
         DBConnection dbConn = null;
170
         int serialNumber = -1;
171

    
172
         if ( systemid != null ) {
173
           try
174
           {
175
            // Get dbconnection
176
            dbConn=DBConnectionPool.getDBConnection
177
                                          ("DBSAXHandler.startElement");
178
            serialNumber=dbConn.getCheckOutSerialNumber();
179

    
180
            Statement stmt = dbConn.createStatement();
181
            ResultSet rs = stmt.executeQuery(
182
                          "SELECT catalog_id FROM xml_catalog " +
183
                          "WHERE entry_type = 'DTD' " +
184
                          "AND public_id = '" + doctype + "'");
185
            boolean hasRow = rs.next();
186
            if ( hasRow ) {
187
              catalogid = rs.getString(1);
188
            }
189
            stmt.close();
190
           }//try
191
           finally
192
           {
193
             // Return dbconnection
194
             DBConnectionPool.returnDBConnection(dbConn, serialNumber);
195
           }//finally
196
         }
197

    
198
         //create documentImpl object by the constructor which can specify
199
         //the revision
200
         currentDocument = new DocumentImpl(connection, rootNode.getNodeID(),
201
                               docname, doctype, docid, revision, action, user,
202
                               this.pub, catalogid, this.serverCode);
203

    
204

    
205
       } catch (Exception ane) {
206
         throw (new SAXException("Error in DBSaxHandler.startElement " +
207
                                 action, ane));
208
       }
209
     }
210

    
211
     // Create the current node representation
212
     currentNode = new DBSAXNode(connection, qName, localName, parentNode,
213
                                 currentDocument.getRootNodeID(),docid,
214
                                 currentDocument.getDoctype());
215

    
216
     // Add all of the namespaces
217
     String prefix;
218
     String nsuri;
219
     Enumeration prefixes = namespaces.keys();
220
     while ( prefixes.hasMoreElements() ) {
221
       prefix = (String)prefixes.nextElement();
222
       nsuri = (String)namespaces.get(prefix);
223
       currentNode.setNamespace(prefix, nsuri, docid);
224
     }
225
     namespaces = null;
226
     namespaces = new Hashtable();
227

    
228
     // Add all of the attributes
229
     for (int i=0; i<atts.getLength(); i++) 
230
     {
231
       String attributeName = atts.getQName(i);
232
       String attributeValue = atts.getValue(i);
233
       currentNode.setAttribute(attributeName, attributeValue, docid);
234
       
235
       // To handle name space and schema location if the attribute name is
236
       // xsi:schemaLocation. If the name space is in not in catalog table
237
       // it will be regeistered.
238
       if (attributeName != null && 
239
           attributeName.indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1)
240
       {
241
         SchemaLocationResolver resolver = 
242
                                  new SchemaLocationResolver(attributeValue);
243
         resolver.resolveNameSpace();
244
         
245
       }
246
     }
247
   
248
     // handle access stuff
249
     if (localName.equals(ACCESS))
250
     {
251
       // if it is in addtionalmetacat
252
       if (parentNode.getTagName() == ADDITIONALMETADATA)
253
       {
254
          processAdditionalAccess = true;
255
        
256
       }
257
       else
258
       {
259
         processTopLeverAccess = true;
260
        
261
       }
262
       // create access object 
263
        accessObject = new AccessSection();
264
         // set permission order
265
       String permOrder = currentNode.getAttribute(ORDER);
266
       accessObject.setPermissionOrder(permOrder);
267
       // set access id
268
       String accessId = currentNode.getAttribute(ID);
269
       accessObject.setAccessSectionId(accessId);
270
       
271
     }
272
     
273
    
274
     // Set up a access rule
275
     if (parentNode.getTagName() != null && 
276
       (parentNode.getTagName()).equals(ACCESS) && localName.equals(ALLOW))
277
     {
278
      
279
       accessRule = new AccessRule(); 
280
      
281
       //set permission type "allow"
282
       accessRule.setPermissionType(ALLOW);
283
      
284
     }
285
     
286
     // set up an access rule
287
     if (parentNode.getTagName() != null 
288
       && (parentNode.getTagName()).equals(ACCESS) && localName.equals(DENY))
289
     {
290
       accessRule = new AccessRule();
291
       //set permission type "allow"
292
       accessRule.setPermissionType(DENY);
293
     }
294
       
295
  
296
     // Add the node to the stack, so that any text data can be
297
     // added as it is encountered
298
     nodeStack.push(currentNode);
299
     // Add the node to the vector used by thread for writing XML Index
300
     nodeIndex.addElement(currentNode);
301

    
302
  }
303
  
304
    /** SAX Handler that is called for each XML text node */
305
  public void characters(char[] cbuf, int start, int len) throws SAXException 
306
  {
307
     super.characters(cbuf, start, len);
308
    
309
     // access stuff
310
     DBSAXNode currentNode = (DBSAXNode)nodeStack.peek();
311
     String currentTag = currentNode.getTagName();
312
     String data = null;
313
     // add principal
314
     if (currentTag.equals(PRINCIPAL) && accessRule != null) 
315
     {
316
        data = (new String(cbuf, start, len)).trim();
317
        accessRule.addPrincipal(data);
318

    
319
     } 
320
     else if (currentTag.equals(PERMISSION) && accessRule != null) 
321
     {
322
        data = (new String(cbuf, start, len)).trim();
323
        // we conbine different a permission into one value
324
        int permission = accessRule.getPermission();
325
        // add permision
326
        if ( data.toUpperCase().equals("READ") ) 
327
        {
328
          permission = permission | READ;
329
        } 
330
        else if ( data.toUpperCase().equals("WRITE") ) 
331
        {
332
          permission = permission | WRITE;
333
        } 
334
        else if ( data.toUpperCase().equals("CHANGEPERMISSION")) 
335
        {
336
          permission = permission | CHMOD;
337
        } 
338
        else if ( data.toUpperCase().equals("ALL") ) 
339
        {
340
          permission = permission | ALL;
341
        }
342
        accessRule.setPermission(permission);
343
     }
344
   }//character
345
  
346
  /** SAX Handler that is called at the end of each XML element */
347
   public void endElement(String uri, String localName,
348
                          String qName) throws SAXException 
349
  {
350
     MetaCatUtil.debugMessage("End ELEMENT " + qName, 50);
351

    
352
     // Get the node from the stack
353
     DBSAXNode currentNode = (DBSAXNode)nodeStack.pop();
354
     
355
     // access stuff
356
     if ((currentNode.getTagName()).equals(ALLOW) ||
357
         (currentNode.getTagName()).equals(DENY))
358
     {
359
       // finish parser a ccess rule and  assign it to new one
360
       AccessRule newRule = accessRule;
361
       //add the new rule to access section object
362
       accessObject.addAccessRule(newRule);
363
       // reset access rule
364
       accessRule = null;
365
     }
366
     else if ((currentNode.getTagName()).equals(ACCESS))
367
     {
368
       // finish parse a access setction and assign it to new one
369
       AccessSection newAccessObject = accessObject;
370
       if (processTopLeverAccess)
371
       {
372
         // top level access control will handle whole document -docid
373
         topLevelAccessControlMap.put(docid, newAccessObject);
374
         // reset processtopleveraccess tag
375
         processTopLeverAccess =false;
376
       }
377
       else if (processAdditionalAccess)
378
       {
379
         // for additional control
380
       }
381
       
382
       //reset access section object
383
       accessObject = null;
384
     }
385
   }
386
   
387
   /** SAX Handler that receives notification of end of the document */
388
   public void endDocument() throws SAXException 
389
   {
390
     MetaCatUtil.debugMessage("end Document", 50);
391
     // write access rule to db
392
     writeAccessRuleToDB();
393
     // Starting new thread for writing XML Index.
394
     // It calls the run method of the thread.
395
     try 
396
     {
397
       xmlIndex.start();
398
     } 
399
     catch (NullPointerException e) 
400
     {
401
       xmlIndex = null;
402
       throw new
403
       SAXException("Problem with starting thread for writing XML Index. " +
404
                    e.getMessage());
405
     }
406
   }
407
  /* The method to write access rule into db. */
408
  private void writeAccessRuleToDB() throws SAXException
409
  {
410
    
411
    // for top document level
412
    AccessSection accessSection = (AccessSection)
413
                                          topLevelAccessControlMap.get(docid);
414
    // if accessSection is null stop it
415
    if( accessSection == null)
416
    {
417
      return;
418
    }
419
    String permOrder = accessSection.getPermissionOrder();
420
    String sql = "INSERT INTO xml_access (docid, principal_name, permission, "+
421
                 "perm_type, perm_order, accessfileid) VALUES " +
422
                 " (?, ?, ?, ?, ?, ?)";
423
    PreparedStatement pstmt = null;
424
   
425
    try 
426
    {
427
     
428
      pstmt = connection.prepareStatement(sql);
429
      // Increase DBConnection usage count
430
      connection.increaseUsageCount(1);
431
      // Bind the values to the query
432
      pstmt.setString(1, docid);
433
      pstmt.setString(6, docid);
434
      pstmt.setString(5, permOrder);
435
      
436
      Vector accessRules = accessSection.getAccessRules();
437
      // go through every rule
438
      for (int i=0; i<accessRules.size(); i++)
439
      {
440
        AccessRule rule = (AccessRule)accessRules.elementAt(i);
441
        String permType = rule.getPermissionType();
442
        int permission = rule.getPermission();
443
        pstmt.setInt(3, permission);
444
        pstmt.setString(4, permType);
445
        // go through every principle in rule
446
        Vector nameVector = rule.getPrincipal();
447
        for ( int j = 0; j < nameVector.size(); j++ ) 
448
       {
449
         String prName = (String)nameVector.elementAt(j);
450
         pstmt.setString(2, prName);
451
         pstmt.execute();
452
       }//for
453
     }//for
454
     pstmt.close();
455
    }//try 
456
    catch (SQLException e) 
457
    {
458
      throw new 
459
      SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + e.getMessage());
460
    }//catch
461
    finally
462
    {
463
      try
464
      {
465
        pstmt.close();
466
      }
467
      catch(SQLException ee)
468
      {
469
        throw new 
470
        SAXException("EMLSAXHandler.writeAccessRuletoDB(): " + ee.getMessage());
471
      }
472
    }//finally
473
  }//writeAccessRuletoDB
474
     
475
 
476
}
(32-32/52)