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
 *
9
 *   '$Author: leinfelder $'
10
 *     '$Date: 2008-10-13 09:11:45 -0700 (Mon, 13 Oct 2008) $'
11
 * '$Revision: 4447 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.io.*;
31
import java.sql.*;
32
import java.util.Stack;
33
import java.util.Vector;
34
import java.util.Hashtable;
35
import java.net.URL;
36
import java.net.MalformedURLException;
37

    
38
import org.apache.log4j.Logger;
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
import edu.ucsb.nceas.metacat.service.DatabaseService;
51
import edu.ucsb.nceas.metacat.service.PropertyService;
52
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
53
import edu.ucsb.nceas.metacat.util.SystemUtil;
54
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55

    
56
/** 
57
 * A Class that loads eml-access.xml file containing ACL for a metadata
58
 * document into relational DB. It extends DefaultHandler class to handle
59
 * SAX parsing events when processing the XML stream.
60
 */
61
public class AccessControlList extends DefaultHandler 
62
                               implements AccessControlInterface 
63
{
64

    
65
 
66
  private static String sysdate = DatabaseService.getDBAdapter().getDateTimeFunction();
67
  private static String isnull = DatabaseService.getDBAdapter().getIsNULLFunction();
68
  
69
  private DBConnection connection;
70
  private String parserName;
71
  private Stack elementStack;
72
  private String server;
73
  private String sep;
74
 
75
  private boolean	processingDTD;
76
  private String  user;
77
  private String[] groups;
78
  private String  aclid;
79
  private int     rev;
80
  private String 	docname;
81
  private String 	doctype;
82
  private String 	systemid;
83

    
84
  private String docurl;
85
  private Vector resourceURL;
86
  private Vector resourceID;
87
  private Vector principal;
88
  private int    permission;
89
  private String permType;
90
  private String permOrder;
91
//  private String publicAcc;
92
  private String beginTime;
93
  private String endTime;
94
  private int    ticketCount;
95
  private int    serverCode = 1;
96

    
97
  private Vector aclObjects = new Vector();
98
  private boolean instarttag = true;
99
  private String tagName = "";
100
  
101
  private static Logger logMetacat = Logger.getLogger(AccessControlList.class);
102
  /**
103
   * Construct an instance of the AccessControlList class.
104
   * It is used by the permission check up from DBQuery or DocumentImpl
105
   * and from "getaccesscontrol" action
106
   *
107
   * @param conn the JDBC connection where acl info is get
108
   */
109
  public AccessControlList(DBConnection conn) throws SQLException
110
  {
111
    this.connection = conn;
112
  }
113
  
114

    
115
  
116

    
117
  /**
118
   * Construct an instance of the AccessControlList class.
119
   * It parse acl file and loads acl data into db connection.
120
   *
121
   * @param conn the JDBC connection where acl data are loaded
122
   * @param aclid the Accession# of the document with the acl data
123
   * @param acl the acl file containing acl data
124
   * @param user the user connected to MetaCat servlet and owns the document
125
   * @param groups the groups to which user belongs
126
   * @param serverCode the serverid from xml_replication on which this document
127
   *        resides.
128
   */
129
  public AccessControlList(DBConnection conn, String aclid, int rev,
130
                           String user, String[] groups, int serverCode)
131
                  throws SAXException, IOException, McdbException, PropertyNotFoundException
132
  {
133
		String parserName = PropertyService.getProperty("xml.saxparser");
134
		this.server = SystemUtil.getSecureServerURL();
135
		this.sep = PropertyService.getProperty("document.accNumSeparator");
136

    
137
		this.connection = conn;
138
		this.parserName = parserName;
139
		this.processingDTD = false;
140
		this.elementStack = new Stack();
141

    
142
		this.user = user;
143
		this.groups = groups;
144
		this.aclid = aclid;
145
		this.resourceURL = new Vector();
146
		this.resourceID = new Vector();
147
		this.principal = new Vector();
148
		this.permission = 0;
149
		this.ticketCount = 0;
150
		// this.publicAcc = null;
151
		this.serverCode = serverCode;
152

    
153
		// read the access file from db connection
154
		DocumentImpl acldoc = new DocumentImpl(aclid + sep + rev);
155
		String acl = acldoc.toString();
156
		this.rev = acldoc.getRev();
157

    
158
		// Initialize the parse
159
		XMLReader parser = initializeParser();
160
		// parse the access file and write the info to xml_access
161
		parser.parse(new InputSource(new StringReader(acl)));
162
	}
163

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

    
189
    // Get an instance of the parser
190
    parser = XMLReaderFactory.createXMLReader(parserName);
191

    
192
    // Turn off validation
193
    parser.setFeature("http://xml.org/sax/features/validation", true);
194
      
195
    // Set Handlers in the parser
196
    // Set the ContentHandler to this instance
197
    parser.setContentHandler((ContentHandler)this);
198

    
199
    // make a DBEntityResolver instance
200
    // Set the EntityReslover to DBEntityResolver instance
201
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
202
    parser.setEntityResolver((EntityResolver)eresolver);
203

    
204
    // Set the ErrorHandler to this instance
205
    parser.setErrorHandler((ErrorHandler)this);
206

    
207
    return parser; 
208
  }
209
  
210
  /**
211
   * Callback method used by the SAX Parser when beginning of the document
212
   */
213
  public void startDocument() throws SAXException 
214
  {
215
    //delete all previously submitted permissions @ relations
216
    //this happens only on UPDATE of the access file
217
    try {
218
      this.aclObjects = getACLObjects(aclid);
219

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

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

    
279
      if (currentTag.equals("principal")) {
280

    
281
        principal.addElement(inputString);
282

    
283
      } else if (currentTag.equals("permission")) {
284

    
285
        if ( inputString.trim().toUpperCase().equals("READ") ) {
286
          permission = permission | READ;
287
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
288
          permission = permission | WRITE;
289
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION")) 
290
        {
291
          permission = permission | CHMOD;
292
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
293
          permission = permission | ALL;
294
        }/*else{
295
          throw new SAXException("Unknown permission type: " + inputString);
296
        }*/
297

    
298
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
299
        beginTime = inputString.trim();
300

    
301
      } else if ( currentTag.equals("stopDate") && endTime == null) {
302
        endTime = inputString.trim();
303

    
304
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
305
        try {
306
          ticketCount = (new Integer(inputString.trim())).intValue();
307
        } catch (NumberFormatException nfe) {
308
          throw new SAXException("Wrong integer format for:" + inputString);
309
        }
310
      }
311
  }
312

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

    
325
    if ( leavingTagName.equals("allow") ||
326
         leavingTagName.equals("deny")    ) {
327
      
328
      if ( permission > 0 ) {
329

    
330
        // insert into db calculated permission for the list of principals
331
        try {
332
          // go through the objects in xml_relation about this acl doc
333
          for (int i=0; i < aclObjects.size(); i++) {
334
            // docid of the current object
335
            String docid = (String)aclObjects.elementAt(i); 
336
            //DocumentIdentifier docID = new DocumentIdentifier(docid);
337
            //docid = docID.getIdentifier();
338
            // the docid get here has revision number, so we need to 
339
            // remove it.
340
            //docid = MetaCatUtil.getDocIdFromAccessionNumber(docid);
341
            //System.out.println("The docid insert is!!!!!!!!!! "+ docid);
342
            insertPermissions(docid,leavingTagName);
343
          }
344
          
345
          // if acl is not in object list
346
          //should insert permission for aclid itself into database
347
          /*if (!aclObjects.contains(aclid))
348
          {
349
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
350
            String aclIdString = aclIdItself.getIdentifier();
351
            insertPermissions(aclIdString,leavingTagName);
352
          }*/
353
          
354

    
355
        } catch (SQLException sqle) {
356
          throw new SAXException(sqle);
357
        } catch (Exception e) {
358
          throw new SAXException(e);
359
        }
360
      }
361

    
362
      // reset the allow/deny permission
363
      principal = new Vector();
364
      permission = 0;
365
      beginTime = null;
366
      endTime = null;
367
      ticketCount = 0;
368
    
369
    }
370

    
371
  }
372

    
373
  /** 
374
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
375
    * @param name name of the DTD
376
    * @param publicId Public Identifier of the DTD
377
    * @param systemId System Identifier of the DTD
378
    */
379
  public void startDTD(String name, String publicId, String systemId) 
380
              throws SAXException {
381
    docname = name;
382
    doctype = publicId;
383
    systemid = systemId;
384
  }
385

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

    
396
  /** 
397
   * SAX Handler that receives notification of the end of entities.
398
   * @param name name of the entity
399
   */
400
  public void endEntity(String name) throws SAXException {
401
    if (name.equals("[dtd]")) {
402
      processingDTD = false;
403
    }
404
  }
405

    
406
  /**
407
   * Get the document name.
408
   */
409
  public String getDocname() {
410
    return docname;
411
  }
412

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

    
469
  /* Delete from db all permission for resources related to @aclid if any.*/
470
  private void deletePermissionsForRelatedResources(String aclid) 
471
          throws SQLException 
472
  {
473
    //DBConnection conn = null;
474
    //int serialNumber = -1;
475
    Statement stmt = null;
476
    try
477
    {
478
      //check out DBConenction
479
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
480
      //serialNumber=conn.getCheckOutSerialNumber();
481
      // delete all acl records for resources related to @aclid if any
482
      stmt = connection.createStatement();
483
      // Increase DBConnection usage count
484
      connection.increaseUsageCount(1);
485
      logMetacat.debug("running sql: " + stmt.toString());
486
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid 
487
                                                                      + "'");
488
      //increase usageCount!!!!!!
489
      //conn.increaseUsageCount(1);
490
    }
491
    catch (SQLException e)
492
    {
493
      throw e;
494
    }
495
    finally
496
    {
497
      stmt.close();
498
      //retrun DBConnection
499
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
500
    }
501
  }
502

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

    
564
    } catch (SQLException e) {
565
      throw new 
566
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
567
    }
568
    finally
569
    {
570
      pstmt.close();
571
      //return the DBConnection
572
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
573
    }
574
  }
575

    
576
  /* Get permissions with permission order different than @permOrder. */
577
  private int getPermissions(int permission, String principal,
578
                             String docid, String permOrder)
579
          throws SQLException 
580
  {
581
    PreparedStatement pstmt = null;
582
    DBConnection conn = null;
583
    int serialNumber = -1;
584
    try
585
    {
586
      //check out DBConnection
587
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
588
      serialNumber=conn.getCheckOutSerialNumber();
589
      pstmt = conn.prepareStatement(
590
            "SELECT permission FROM xml_access " +
591
            "WHERE docid = ? " +
592
            "AND principal_name = ? " +
593
            "AND perm_order NOT = ?");
594
      pstmt.setString(1, docid);
595
      pstmt.setString(2, principal);
596
      pstmt.setString(3, permOrder);
597
      logMetacat.debug("running sql: " + pstmt.toString());
598
      pstmt.execute();
599
      ResultSet rs = pstmt.getResultSet();
600
      boolean hasRow = rs.next();
601
      int perm = 0;
602
      while ( hasRow ) {
603
        perm = rs.getInt(1);
604
        perm = permission & perm;
605
        if ( perm != 0 ) {
606
          pstmt.close();
607
          return perm;
608
        }
609
        hasRow = rs.next();
610
      }
611
    }//try
612
    catch (SQLException e)
613
    {
614
      throw e;
615
    }
616
    finally
617
    {
618
      try
619
      {
620
        pstmt.close();
621
      }
622
      finally
623
      {
624
        DBConnectionPool.returnDBConnection(conn, serialNumber);
625
      }
626
    }
627
    return 0;
628
  }
629

    
630
  /* Get the int value of READ, WRITE or ALL. */
631
  public static int intValue ( String permission )
632
  {
633
    if ( permission.equalsIgnoreCase("READ") ) {
634
      return READ;
635
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
636
      return WRITE;
637
    } else if ( permission.equalsIgnoreCase("ALL") ) {
638
      return ALL;
639
    }
640
    
641
    return -1;
642
  }
643

    
644
  /* Get the text value of READ, WRITE or ALL. */
645
  public static String txtValue ( int permission )
646
  {
647
    StringBuffer txtPerm = new StringBuffer();
648
    if (permission == READ) {
649
      txtPerm.append("READ");
650
    } 
651
    if (permission == WRITE) {
652
      txtPerm.append("WRITE");
653
    }
654
    if (permission == ALL) {
655
      txtPerm.append("ALL");
656
    }
657

    
658
    return txtPerm.toString();
659
  }
660

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

    
716
      
717
      pstmt = conn.prepareStatement(
718
              "SELECT distinct accessfileid, principal_name, permission, " +
719
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
720
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
721
              "FROM xml_access WHERE docid = ? " +
722
              "ORDER BY accessfileid, perm_order, perm_type, permission");
723
      // Bind the values to the query
724
      pstmt.setString(1, docid);
725
      logMetacat.debug("running sql: " + pstmt.toString());
726
      pstmt.execute();
727
      ResultSet rs = pstmt.getResultSet();
728
      boolean hasRows = rs.next();
729
      while (hasRows) {
730

    
731
        acfid = rs.getString(1);
732
        principal = rs.getString(2);
733
        permission = rs.getInt(3);
734
        permType = rs.getString(4);
735
        permOrder = rs.getString(5);
736
        beginTime = rs.getString(6);
737
        endTime = rs.getString(7);
738
        ticketCount = rs.getInt(8);
739

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

    
827
      // close <allow> or <deny> if anything left in outTemp var
828
      output.append(outTemp.toString());
829

    
830
      // If there are no any acl info for @docid accessible by @user/@group,
831
      // extract only the following information
832
      if ( permOrder.equals("") ) {
833
        output.append("  <resource public=\"" + publicAcc + "\">\n");
834
        output.append("    <resourceIdentifier>" + docurl + 
835
                      "</resourceIdentifier>\n");
836
      }
837
      
838
      // always close them
839
      output.append("  </resource>\n");
840
      output.append("</acl>\n");
841
      
842
      pstmt.close();
843

    
844
      return output.toString();
845

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

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

    
934
  /* Get SystemID for @publicID from Metacat DB Catalog. */
935
  private String getSystemID(String publicID) throws SQLException, PropertyNotFoundException {
936

    
937
		String systemID = "";
938
		PreparedStatement pstmt = null;
939
		DBConnection conn = null;
940
		int serialNumber = -1;
941

    
942
		try {
943
			//check out DBConnection
944
			conn = DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
945
			serialNumber = conn.getCheckOutSerialNumber();
946

    
947
			pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog "
948
					+ "WHERE entry_type = 'DTD' " + "AND public_id = ?");
949
			pstmt.setString(1, publicID);
950
			pstmt.execute();
951
			ResultSet rs = pstmt.getResultSet();
952
			boolean hasRow = rs.next();
953
			if (hasRow) {
954
				systemID = rs.getString(1);
955
				// system id may not have server url on front.  Add it if not.
956
				if (!systemID.startsWith("http://")) {
957
					systemID = SystemUtil.getContextURL() + systemID;
958
				}
959
			}
960

    
961
			return systemID;
962
		}//try
963
		finally {
964
			try {
965
				pstmt.close();
966
			} finally {
967
				DBConnectionPool.returnDBConnection(conn, serialNumber);
968
			}
969
		}//finally
970
	}
971

    
972
}
(3-3/67)