Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that loads eml-access.xml file containing ACL 
4
 *             for a metadata document into relational DB
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author: tao $'
11
 *     '$Date: 2003-02-26 17:29:47 -0800 (Wed, 26 Feb 2003) $'
12
 * '$Revision: 1426 $'
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.io.*;
32
import java.sql.*;
33
import java.util.Stack;
34
import java.util.Vector;
35
import java.util.Hashtable;
36
import java.net.URL;
37
import java.net.MalformedURLException;
38

    
39
import org.xml.sax.Attributes;
40
import org.xml.sax.InputSource;
41
import org.xml.sax.ContentHandler;
42
import org.xml.sax.EntityResolver;
43
import org.xml.sax.ErrorHandler;
44
import org.xml.sax.SAXException;
45
import org.xml.sax.SAXParseException;
46
import org.xml.sax.XMLReader;
47
import org.xml.sax.helpers.XMLReaderFactory;
48
import org.xml.sax.helpers.DefaultHandler;
49

    
50
/** 
51
 * A Class that loads eml-access.xml file containing ACL for a metadata
52
 * document into relational DB. It extends DefaultHandler class to handle
53
 * SAX parsing events when processing the XML stream.
54
 */
55
public class AccessControlList extends DefaultHandler 
56
                               implements AccessControlInterface 
57
{
58

    
59
 
60
  private static String sysdate = MetaCatUtil.dbAdapter.getDateTimeFunction();
61
  private static String isnull = MetaCatUtil.dbAdapter.getIsNULLFunction();
62
  
63
  private DBConnection connection;
64
  private String parserName;
65
  private Stack elementStack;
66
  private String server;
67
  private String sep;
68
 
69
  private boolean	processingDTD;
70
  private String  user;
71
  private String[] groups;
72
  private String  aclid;
73
  private int     rev;
74
  private String 	docname;
75
  private String 	doctype;
76
  private String 	systemid;
77

    
78
  private String docurl;
79
  private Vector resourceURL;
80
  private Vector resourceID;
81
  private Vector principal;
82
  private int    permission;
83
  private String permType;
84
  private String permOrder;
85
//  private String publicAcc;
86
  private String beginTime;
87
  private String endTime;
88
  private int    ticketCount;
89
  private int    serverCode = 1;
90

    
91
  private Vector aclObjects = new Vector();
92
  private boolean instarttag = true;
93
  private String tagName = "";
94
  /**
95
   * Construct an instance of the AccessControlList class.
96
   * It is used by the permission check up from DBQuery or DocumentImpl
97
   * and from "getaccesscontrol" action
98
   *
99
   * @param conn the JDBC connection where acl info is get
100
   */
101
  public AccessControlList(DBConnection conn) throws SQLException
102
  {
103
    this.connection = conn;
104
  }
105
  
106

    
107
  
108

    
109
  /**
110
   * Construct an instance of the AccessControlList class.
111
   * It parse acl file and loads acl data into db connection.
112
   *
113
   * @param conn the JDBC connection where acl data are loaded
114
   * @param aclid the Accession# of the document with the acl data
115
   * @param acl the acl file containing acl data
116
   * @param user the user connected to MetaCat servlet and owns the document
117
   * @param groups the groups to which user belongs
118
   * @param serverCode the serverid from xml_replication on which this document
119
   *        resides.
120
   */
121
  public AccessControlList(DBConnection conn, String aclid, //Reader acl,
122
                           String user, String[] groups, int serverCode)
123
                  throws SAXException, IOException, McdbException
124
  {
125
    String parserName = MetaCatUtil.getOption("saxparser");
126
    this.server = MetaCatUtil.getOption("server");
127
    this.sep = MetaCatUtil.getOption("accNumSeparator");
128

    
129
    this.connection = conn;
130
    this.parserName = parserName;
131
    this.processingDTD = false;
132
    this.elementStack = new Stack();
133
    
134
    this.user = user;
135
    this.groups = groups;
136
    this.aclid = aclid;
137
    this.resourceURL = new Vector();
138
    this.resourceID = new Vector();
139
    this.principal = new Vector();
140
    this.permission = 0;
141
    this.ticketCount = 0;
142
  //  this.publicAcc = null;
143
    this.serverCode = serverCode;
144
    
145
    // read the access file from db connection
146
    DocumentImpl acldoc = new DocumentImpl(aclid);
147
    String acl = acldoc.toString();
148
    this.rev = acldoc.getRev();
149

    
150
    // Initialize the parse
151
    XMLReader parser = initializeParser();
152
    // parse the access file and write the info to xml_access
153
    parser.parse(new InputSource(new StringReader(acl)));
154
    
155
  }
156

    
157
// NOT USED
158
//  /**
159
//   * Construct an instance of the AccessControlList class.
160
//   * It parses eml-access file and loads acl data into db connection.
161
//   * It is used from command line execution.
162
//   *
163
//   * @param conn the JDBC connection where acl data are loaded
164
//   * @param docid the Accession# of the document with the acl data
165
//   * @param aclfilename the name of acl file containing acl data
166
//   * @param user the user connected to MetaCat servlet and owns the document
167
//   * @param groups the groups to which user belongs
168
//   */
169
//  public AccessControlList( Connection conn, String aclid, String aclfilename,
170
//                           String user, String[] groups )
171
//                  throws SAXException, IOException, McdbException
172
//  {
173
//    this(conn, aclid, new FileReader(new File(aclfilename).toString()), 
174
//         user, groups, 1);
175
//  }
176
  
177
  /* Set up the SAX parser for reading the XML serialized ACL */
178
  private XMLReader initializeParser() throws SAXException 
179
  {
180
    XMLReader parser = null;
181

    
182
    // Get an instance of the parser
183
    parser = XMLReaderFactory.createXMLReader(parserName);
184

    
185
    // Turn off validation
186
    parser.setFeature("http://xml.org/sax/features/validation", true);
187
      
188
    // Set Handlers in the parser
189
    // Set the ContentHandler to this instance
190
    parser.setContentHandler((ContentHandler)this);
191

    
192
    // make a DBEntityResolver instance
193
    // Set the EntityReslover to DBEntityResolver instance
194
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
195
    parser.setEntityResolver((EntityResolver)eresolver);
196

    
197
    // Set the ErrorHandler to this instance
198
    parser.setErrorHandler((ErrorHandler)this);
199

    
200
    return parser; 
201
  }
202
  
203
  /**
204
   * Callback method used by the SAX Parser when beginning of the document
205
   */
206
  public void startDocument() throws SAXException 
207
  {
208
    //delete all previously submitted permissions @ relations
209
    //this happens only on UPDATE of the access file
210
    try {
211
      this.aclObjects = getACLObjects(aclid);
212

    
213
      //delete all permissions for resources related to @aclid if any
214
      if ( aclid != null ) {
215
        deletePermissionsForRelatedResources(aclid);
216
      }
217
    } catch (SQLException sqle) {
218
      throw new SAXException(sqle);
219
    }
220
  }
221
  
222
  /**
223
   * Callback method used by the SAX Parser when the start tag of an 
224
   * element is detected. Used in this context to parse and store
225
   * the acl information in class variables.
226
   */
227
  public void startElement (String uri, String localName, 
228
                            String qName, Attributes atts) 
229
         throws SAXException 
230
  {
231
    instarttag = true;
232
    if(localName.equals("allow"))
233
    {
234
      tagName = "allow";
235
    }
236
    else if(localName.equals("deny"))
237
    {
238
      tagName = "deny";
239
    }
240
    BasicNode currentNode = new BasicNode(localName);
241
    if (atts != null) {
242
      int len = atts.getLength();
243
      for (int i = 0; i < len; i++) {
244
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
245
      }
246
    }
247
    if ( currentNode.getTagName().equals("acl") ) {
248
      permOrder = currentNode.getAttribute("order");
249
    //  publicAcc = currentNode.getAttribute("public");
250
    }
251
    elementStack.push(currentNode); 
252
  }
253

    
254
  /**
255
   * Callback method used by the SAX Parser when the text sequences of an 
256
   * xml stream are detected. Used in this context to parse and store
257
   * the acl information in class variables.
258
   */ 
259
  public void characters(char ch[], int start, int length)
260
         throws SAXException 
261
  {
262
    if(!instarttag)
263
    {
264
      return;
265
    }
266
    String inputString = new String(ch, start, length);
267
    inputString = inputString.trim(); 
268
    //System.out.println("==============inputString: " + inputString);
269
    BasicNode currentNode = (BasicNode)elementStack.peek(); 
270
    String currentTag = currentNode.getTagName();
271

    
272
      if (currentTag.equals("principal")) {
273

    
274
        principal.addElement(inputString);
275

    
276
      } else if (currentTag.equals("permission")) {
277

    
278
        if ( inputString.trim().toUpperCase().equals("READ") ) {
279
          permission = permission | READ;
280
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
281
          permission = permission | WRITE;
282
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION")) 
283
        {
284
          permission = permission | CHMOD;
285
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
286
          permission = permission | ALL;
287
        }/*else{
288
          throw new SAXException("Unknown permission type: " + inputString);
289
        }*/
290

    
291
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
292
        beginTime = inputString.trim();
293

    
294
      } else if ( currentTag.equals("stopDate") && endTime == null) {
295
        endTime = inputString.trim();
296

    
297
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
298
        try {
299
          ticketCount = (new Integer(inputString.trim())).intValue();
300
        } catch (NumberFormatException nfe) {
301
          throw new SAXException("Wrong integer format for:" + inputString);
302
        }
303
      }
304
  }
305

    
306
  /**
307
   * Callback method used by the SAX Parser when the end tag of an 
308
   * element is detected. Used in this context to parse and store
309
   * the acl information in class variables.
310
   */
311
  public void endElement (String uri, String localName, String qName)
312
         throws SAXException 
313
  {
314
    instarttag = false;
315
    BasicNode leaving = (BasicNode)elementStack.pop();
316
    String leavingTagName = leaving.getTagName();
317

    
318
    if ( leavingTagName.equals("allow") ||
319
         leavingTagName.equals("deny")    ) {
320
      
321
      if ( permission > 0 ) {
322

    
323
        // insert into db calculated permission for the list of principals
324
        try {
325
          // go through the objects in xml_relation about this acl doc
326
          for (int i=0; i < aclObjects.size(); i++) {
327
            // docid of the current object
328
            String docid = (String)aclObjects.elementAt(i); 
329
            DocumentIdentifier docID = new DocumentIdentifier(docid);
330
            docid = docID.getIdentifier();
331
            insertPermissions(docid,leavingTagName);
332
          }
333
          
334
          // if acl is not in object list
335
          //should insert permission for aclid itself into database
336
          /*if (!aclObjects.contains(aclid))
337
          {
338
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
339
            String aclIdString = aclIdItself.getIdentifier();
340
            insertPermissions(aclIdString,leavingTagName);
341
          }*/
342
          
343

    
344
        } catch (SQLException sqle) {
345
          throw new SAXException(sqle);
346
        } catch (Exception e) {
347
          throw new SAXException(e);
348
        }
349
      }
350

    
351
      // reset the allow/deny permission
352
      principal = new Vector();
353
      permission = 0;
354
      beginTime = null;
355
      endTime = null;
356
      ticketCount = 0;
357
    
358
    }
359

    
360
  }
361

    
362
  /** 
363
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
364
    * @param name name of the DTD
365
    * @param publicId Public Identifier of the DTD
366
    * @param systemId System Identifier of the DTD
367
    */
368
  public void startDTD(String name, String publicId, String systemId) 
369
              throws SAXException {
370
    docname = name;
371
    doctype = publicId;
372
    systemid = systemId;
373
  }
374

    
375
  /** 
376
   * SAX Handler that receives notification of the start of entities.
377
   * @param name name of the entity
378
   */
379
  public void startEntity(String name) throws SAXException {
380
    if (name.equals("[dtd]")) {
381
      processingDTD = true;
382
    }
383
  }
384

    
385
  /** 
386
   * SAX Handler that receives notification of the end of entities.
387
   * @param name name of the entity
388
   */
389
  public void endEntity(String name) throws SAXException {
390
    if (name.equals("[dtd]")) {
391
      processingDTD = false;
392
    }
393
  }
394

    
395
  /**
396
   * Get the document name.
397
   */
398
  public String getDocname() {
399
    return docname;
400
  }
401

    
402
  /**
403
   * Get the document processing state.
404
   */
405
  public boolean processingDTD() {
406
    return processingDTD;
407
  }
408
  
409
  /* Get all objects associated with @aclid from db.*/
410
  private Vector getACLObjects(String aclid) 
411
          throws SQLException 
412
  {
413
    Vector aclObjects = new Vector();
414
    DBConnection conn = null;
415
    int serialNumber = -1;
416
    PreparedStatement pstmt = null;
417
    try
418
    {
419
      //get connection from DBConnectionPool
420
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
421
      serialNumber=conn.getCheckOutSerialNumber();
422
      
423
      // delete all acl records for resources related to @aclid if any
424
      pstmt = conn.prepareStatement(
425
                             "SELECT object FROM xml_relation " +
426
                             "WHERE subject = ? ");
427
      pstmt.setString(1,aclid);
428
      pstmt.execute();
429
      ResultSet rs = pstmt.getResultSet();
430
      boolean hasRows = rs.next();
431
      while (hasRows) {
432
        aclObjects.addElement(rs.getString(1));
433
        hasRows = rs.next();
434
      }//whil
435
    }
436
    catch (SQLException e)
437
    {
438
      throw e;
439
    }
440
    finally
441
    {
442
      try
443
      {
444
        pstmt.close();
445
      }
446
      finally
447
      {
448
        //retrun DBConnection
449
        DBConnectionPool.returnDBConnection(conn,serialNumber);
450
      }
451
    }
452
    
453
    return aclObjects;
454
  }
455

    
456
  /* Delete from db all permission for resources related to @aclid if any.*/
457
  private void deletePermissionsForRelatedResources(String aclid) 
458
          throws SQLException 
459
  {
460
    //DBConnection conn = null;
461
    //int serialNumber = -1;
462
    Statement stmt = null;
463
    try
464
    {
465
      //check out DBConenction
466
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
467
      //serialNumber=conn.getCheckOutSerialNumber();
468
      // delete all acl records for resources related to @aclid if any
469
      stmt = connection.createStatement();
470
      // Increase DBConnection usage count
471
      connection.increaseUsageCount(1);
472
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid 
473
                                                                      + "'");
474
      //increase usageCount!!!!!!
475
      //conn.increaseUsageCount(1);
476
    }
477
    catch (SQLException e)
478
    {
479
      throw e;
480
    }
481
    finally
482
    {
483
      stmt.close();
484
      //retrun DBConnection
485
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
486
    }
487
  }
488

    
489
  /* Insert into db calculated permission for the list of principals 
490
   * The DBConnection it is use is class field. Because we want to keep rollback
491
   * features and it need use same connection
492
  */
493
  
494
  private void insertPermissions(String docid, String permType ) 
495
                                            throws SQLException 
496
  {
497
    PreparedStatement pstmt = null;
498
    //DBConnection conn = null;
499
    //int serialNumber = -1;
500
    try {
501
      //Check out DBConnection
502
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
503
      //serialNumber=conn.getCheckOutSerialNumber();
504
      
505
      pstmt = connection.prepareStatement(
506
              "INSERT INTO xml_access " + 
507
              "(docid, principal_name, permission, perm_type, perm_order," +
508
              "begin_time,end_time,ticket_count, accessfileid) VALUES " +
509
              "(?,?,?,?,?,to_date(?,'mm/dd/yy'),to_date(?,'mm/dd/yy'),?,?)");
510
      // Increase DBConnection usage count
511
      connection.increaseUsageCount(1);
512
      // Bind the values to the query
513
      pstmt.setString(1, docid);
514
      pstmt.setInt(3, permission);
515
      pstmt.setString(4, permType);
516
      pstmt.setString(5, permOrder);
517
      pstmt.setString(6, beginTime);
518
      pstmt.setString(7, endTime);
519
      pstmt.setString(9, aclid);
520
      if ( ticketCount > 0 ) {
521
        pstmt.setString(8, "" + ticketCount);
522
      } else {
523
        pstmt.setString(8, null);
524
      }
525
      
526
      //incrase usagecount for DBConnection
527
      //conn.increaseUsageCount(1);
528
      String prName;
529
      for ( int j = 0; j < principal.size(); j++ ) {
530
        prName = (String)principal.elementAt(j);
531
        pstmt.setString(2, prName);
532
        pstmt.execute();
533
      /*    
534
        // check if there are conflict with permission's order
535
        String permOrderOpos = permOrder;
536
        int perm = getPermissions(permission, prName, docid, permOrder);
537
        if (  perm != 0 ) {
538
          if ( permOrder.equals("allowFirst") ) {
539
            permOrderOpos = "denyFirst";
540
          } else if ( permOrder.equals("denyFirst") ) {
541
            permOrderOpos = "allowFirst";
542
          }
543
          throw new SQLException("Permission(s) " + txtValue(perm) + 
544
                    " for \"" + prName + "\" on document #" + docid +
545
                    " has/have been used with \"" + permOrderOpos + "\"");
546
        }
547
      */
548
      }
549
      pstmt.close();
550

    
551
    } catch (SQLException e) {
552
      throw new 
553
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
554
    }
555
    finally
556
    {
557
      pstmt.close();
558
      //return the DBConnection
559
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
560
    }
561
  }
562

    
563
  /* Get permissions with permission order different than @permOrder. */
564
  private int getPermissions(int permission, String principal,
565
                             String docid, String permOrder)
566
          throws SQLException 
567
  {
568
    PreparedStatement pstmt = null;
569
    DBConnection conn = null;
570
    int serialNumber = -1;
571
    try
572
    {
573
      //check out DBConnection
574
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
575
      serialNumber=conn.getCheckOutSerialNumber();
576
      pstmt = conn.prepareStatement(
577
            "SELECT permission FROM xml_access " +
578
            "WHERE docid = ? " +
579
            "AND principal_name = ? " +
580
            "AND perm_order NOT = ?");
581
      pstmt.setString(1, docid);
582
      pstmt.setString(2, principal);
583
      pstmt.setString(3, permOrder);
584
      pstmt.execute();
585
      ResultSet rs = pstmt.getResultSet();
586
      boolean hasRow = rs.next();
587
      int perm = 0;
588
      while ( hasRow ) {
589
        perm = rs.getInt(1);
590
        perm = permission & perm;
591
        if ( perm != 0 ) {
592
          pstmt.close();
593
          return perm;
594
        }
595
        hasRow = rs.next();
596
      }
597
    }//try
598
    catch (SQLException e)
599
    {
600
      throw e;
601
    }
602
    finally
603
    {
604
      try
605
      {
606
        pstmt.close();
607
      }
608
      finally
609
      {
610
        DBConnectionPool.returnDBConnection(conn, serialNumber);
611
      }
612
    }
613
    return 0;
614
  }
615

    
616
  /* Get the int value of READ, WRITE or ALL. */
617
  public static int intValue ( String permission )
618
  {
619
    if ( permission.equalsIgnoreCase("READ") ) {
620
      return READ;
621
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
622
      return WRITE;
623
    } else if ( permission.equalsIgnoreCase("ALL") ) {
624
      return ALL;
625
    }
626
    
627
    return -1;
628
  }
629

    
630
  /* Get the text value of READ, WRITE or ALL. */
631
  private String txtValue ( int permission )
632
  {
633
    StringBuffer txtPerm = new StringBuffer("\"");
634
    if ( (permission & READ) != 0 ) {
635
      txtPerm.append("read");
636
    } 
637
    if ( (permission & WRITE) != 0 ) {
638
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
639
      txtPerm.append("write");
640
    }
641
    if ( (permission & ALL) != 0 ) {
642
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
643
      txtPerm.append("all");
644
    }
645

    
646
    return txtPerm.append("\"").toString();
647
  }
648

    
649
  /**
650
    * Get Access Control List information for document from db connetion.
651
    * User or Group should have permissions for reading
652
    * access control information for a document specified by @docid.
653
    * @param docid document identifier which acl info to get
654
    * @param user name of user connected to Metacat system
655
    * @param groups names of user's groups to which user belongs
656
    */
657
  public String getACL(String docid, String user, String[] groups) 
658
          throws SQLException, Exception
659
  {
660
    StringBuffer output = new StringBuffer();
661
    StringBuffer outTemp = new StringBuffer();
662
    MetaCatUtil util = new MetaCatUtil();
663
    String accDoctype = util.getOption("accessdoctype");
664
    String server = util.getOption("server");
665
    String docurl = "metacat://" + server + "/?docid=" + docid;
666
    String systemID;
667
    boolean isOwned = false;
668
    boolean hasPermission = false;
669
    String publicAcc;
670
    
671
    String acfid = "";
672
    String acfid_prev = "";
673
    String principal;
674
    Vector principalArr = new Vector();
675
    int permission;
676
    int perm_prev = -1;
677
    String permType;
678
    String permOrder = "";
679
    String permOrder_prev = "";
680
    String beginTime = "";
681
    String begin_prev = "";
682
    String endTime = "";
683
    String end_prev = "";
684
    int ticketCount = -1;
685
    int ticket_prev = -1;
686
    DBConnection conn = null;
687
    int serialNumber = -1;
688
    PreparedStatement pstmt = null;
689
    try {
690
      
691
      //check out DBConnection
692
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
693
      serialNumber=conn.getCheckOutSerialNumber();
694
      
695
      isOwned = isOwned(docid, user);
696
      systemID = getSystemID((String)MetaCatUtil.
697
                                      getOptionList(accDoctype).elementAt(0));
698
      publicAcc = getPublicAccess(docid);
699
        
700
      output.append("<?xml version=\"1.0\"?>\n");
701
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
702
                    systemID + "\">\n");
703
      output.append("<acl authSystem=\"\">\n");
704

    
705
      
706
      pstmt = conn.prepareStatement(
707
              "SELECT distinct accessfileid, principal_name, permission, " +
708
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
709
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
710
              "FROM xml_access WHERE docid = ? " +
711
              "ORDER BY accessfileid, perm_order, perm_type, permission");
712
      // Bind the values to the query
713
      pstmt.setString(1, docid);
714
      pstmt.execute();
715
      ResultSet rs = pstmt.getResultSet();
716
      boolean hasRows = rs.next();
717
      while (hasRows) {
718

    
719
        acfid = rs.getString(1);
720
        principal = rs.getString(2);
721
        permission = rs.getInt(3);
722
        permType = rs.getString(4);
723
        permOrder = rs.getString(5);
724
        beginTime = rs.getString(6);
725
        endTime = rs.getString(7);
726
        ticketCount = rs.getInt(8);
727

    
728
        // if @docid is not owned by @user, only ACL info from that
729
        // access files to which @user/@groups has "read" permission
730
        // is extracted
731
        if ( !isOwned ) {
732
          if ( !acfid.equals(acfid_prev) ) {
733
            acfid_prev = acfid;
734
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
735
             PermissionController controller = new PermissionController(acfid);
736
             hasPermission = controller.hasPermission(user,groups,
737
                                            AccessControlInterface.READSTRING);
738
          }
739
          if ( !hasPermission ) {
740
            rs.next();
741
            continue;
742
          }
743
        }
744
        
745
        // open <resource> tag
746
        if ( !permOrder.equals(permOrder_prev) ) {
747
          // close </resource> tag if any was opened 
748
          output.append(outTemp.toString());
749
          outTemp = new StringBuffer();
750
          if ( !permOrder_prev.equals("") ) {
751
            output.append("  </resource>\n");
752
          }
753
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
754
                        publicAcc + "\">\n");
755
          output.append("    <resourceIdentifier>" + docurl + 
756
                        "</resourceIdentifier>\n");
757
          permOrder_prev = permOrder;
758
        }
759
        
760
        // close </allow> or </deny> tag then open new one
761
        if ( permission != perm_prev ||
762
             (endTime == null) && (end_prev != null) ||
763
             (beginTime == null) && (begin_prev != null) ||
764
             endTime != null && !endTime.equals(end_prev)  ||
765
             beginTime != null && !beginTime.equals(begin_prev) ||
766
             ticketCount != ticket_prev )  {
767
          output.append(outTemp.toString());
768
          outTemp = new StringBuffer();
769
          principalArr.removeAllElements();
770
          output.append("    <" + permType + ">\n");
771
        }
772
        
773
        // put all principals here for the same 
774
        // permission, duration and ticket_count
775
        if ( !principalArr.contains(principal) ) {
776
          principalArr.addElement(principal);
777
          output.append("      <principal>" + principal + "</principal>\n");
778
        } 
779
        
780
        // prepare <permission> tags, <duration> and <ticketCount>
781
        // if any to put within <allow> (<deny>) by next cicle
782
        if ( permission != perm_prev || 
783
             (endTime == null) && (end_prev != null) ||
784
             (beginTime == null) && (begin_prev != null) ||
785
             endTime != null && !endTime.equals(end_prev)  ||
786
             beginTime != null && !beginTime.equals(begin_prev) ||
787
             ticketCount != ticket_prev )  {
788
          if ( (permission & READ) != 0 ) {
789
            outTemp.append("      <permission>read</permission>\n");
790
          }
791
          if ( (permission & WRITE) != 0 ) {
792
            outTemp.append("      <permission>write</permission>\n");
793
          }
794
          if ( (permission & ALL) != 0 ) {
795
            outTemp.append("      <permission>all</permission>\n");
796
          }
797
          if ( (beginTime != null) || (endTime != null) ) {
798
            outTemp.append("      <duration>" + beginTime + " " + endTime +
799
                          "</duration>\n");
800
          }
801
          if ( ticketCount > 0 ) {
802
            outTemp.append("      <ticketCount>" + ticketCount + 
803
                          "</ticketCount>\n");
804
          }
805
          outTemp.append("    </" + permType + ">\n");
806
          perm_prev = permission;
807
          ticket_prev = ticketCount;
808
          begin_prev = beginTime;
809
          end_prev = endTime;
810
        }
811
        
812
        hasRows = rs.next();
813
      }
814

    
815
      // close <allow> or <deny> if anything left in outTemp var
816
      output.append(outTemp.toString());
817

    
818
      // If there are no any acl info for @docid accessible by @user/@group,
819
      // extract only the following information
820
      if ( permOrder.equals("") ) {
821
        output.append("  <resource public=\"" + publicAcc + "\">\n");
822
        output.append("    <resourceIdentifier>" + docurl + 
823
                      "</resourceIdentifier>\n");
824
      }
825
      
826
      // always close them
827
      output.append("  </resource>\n");
828
      output.append("</acl>\n");
829
      
830
      pstmt.close();
831

    
832
      return output.toString();
833

    
834
    } catch (SQLException e) {
835
      throw new 
836
      SQLException("AccessControlList.getACL(). " + e.getMessage());
837
    }
838
    finally
839
    {
840
      try
841
      {
842
        pstmt.close();
843
      }
844
      finally
845
      {
846
        DBConnectionPool.returnDBConnection(conn, serialNumber);
847
      }
848
    }
849
  }
850
  
851
  /* Check if @user is owner of @docid from db conn. */
852
  private boolean isOwned(String docid, String user) throws SQLException {
853
    
854
    PreparedStatement pstmt = null;
855
    DBConnection conn = null;
856
    int serialNumber = -1;
857
    try
858
    {
859
      //check out DBConnection
860
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
861
      serialNumber=conn.getCheckOutSerialNumber();
862
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
863
                                  "WHERE docid = ? " + 
864
                                  "AND user_owner = ?");
865
      pstmt.setString(1, docid);
866
      pstmt.setString(2, user);
867
      pstmt.execute();
868
      ResultSet rs = pstmt.getResultSet();
869
      boolean hasRow = rs.next();
870
      return hasRow;
871
    }
872
    finally
873
    {
874
      try
875
      {
876
        pstmt.close();
877
      }
878
      finally
879
      {
880
        DBConnectionPool.returnDBConnection(conn, serialNumber);
881
      }
882
    }
883
  }
884

    
885
  /* Get the flag for public "read" access for @docid from db conn. */
886
  private String getPublicAccess(String docid) throws SQLException {
887
    
888
    int publicAcc = 0;
889
    PreparedStatement pstmt = null;
890
    DBConnection conn = null;
891
    int serialNumber = -1;
892
    try
893
    {
894
      //check out DBConnection
895
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
896
      serialNumber=conn.getCheckOutSerialNumber();
897
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
898
                                  "WHERE docid = ?");
899
      pstmt.setString(1, docid);
900
      pstmt.execute();
901
      ResultSet rs = pstmt.getResultSet();
902
      boolean hasRow = rs.next();
903
      if ( hasRow ) {
904
        publicAcc = rs.getInt(1);
905
      }
906
    
907
      return (publicAcc == 1) ? "yes" : "no";
908
    }
909
    finally
910
    {
911
      try
912
      {
913
        pstmt.close();
914
      }
915
      finally
916
      {
917
        DBConnectionPool.returnDBConnection(conn, serialNumber);
918
      }
919
    }
920
  }
921

    
922
  /* Get SystemID for @publicID from Metacat DB Catalog. */
923
  private String getSystemID(String publicID) throws SQLException {
924
    
925
    String systemID = "";
926
    PreparedStatement pstmt = null;
927
    DBConnection conn = null;
928
    int serialNumber = -1;
929
    
930
    try
931
    {
932
      //check out DBConnection
933
      conn=DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
934
      serialNumber=conn.getCheckOutSerialNumber();
935
    
936
      pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog " +
937
                                  "WHERE entry_type = 'DTD' " + 
938
                                  "AND public_id = ?");
939
      pstmt.setString(1, publicID);
940
      pstmt.execute();
941
      ResultSet rs = pstmt.getResultSet();
942
      boolean hasRow = rs.next();
943
      if ( hasRow ) {
944
        systemID = rs.getString(1);
945
      }
946
    
947
      return systemID;
948
    }//try
949
    finally
950
    {
951
      
952
      try
953
      {
954
        pstmt.close();
955
      }
956
      finally
957
      {
958
        DBConnectionPool.returnDBConnection(conn, serialNumber);
959
      }
960
    }//finally
961
  }
962

    
963
}
(3-3/56)