Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that manages database access of xml access  
4
 *             information.
5
 *  Copyright: 2009 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Michael Daigle
8
 * 
9
 *   '$Author: daigle $'
10
 *     '$Date: 2009-03-23 13:56:56 -0800 (Mon, 23 Mar 2009) $'
11
 * '$Revision: 4854 $'
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.accesscontrol;
29

    
30
import java.sql.PreparedStatement;
31
import java.sql.ResultSet;
32
import java.sql.SQLException;
33
import java.util.List;
34
import java.util.Vector;
35

    
36
import org.apache.log4j.Logger;
37

    
38
import edu.ucsb.nceas.metacat.AccessionNumber;
39
import edu.ucsb.nceas.metacat.DBUtil;
40
import edu.ucsb.nceas.metacat.IdentifierManager;
41
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
42
import edu.ucsb.nceas.metacat.database.DBConnection;
43
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
44
import edu.ucsb.nceas.metacat.shared.AccessException;
45
import edu.ucsb.nceas.metacat.shared.BaseAccess;
46

    
47
public class XMLAccessAccess extends BaseAccess {
48
	
49
	private Logger logMetacat = Logger.getLogger(XMLAccessAccess.class);
50
	
51
	private static String DOCID = "docid";
52
	
53
	private static String GUID = "guid";
54

    
55
	private String idAttribute = DOCID;
56
	
57
	// Constructor
58
	public XMLAccessAccess() throws AccessException {}
59
	
60
	public XMLAccessAccess(boolean useGuid) {
61
		if (useGuid) {
62
			idAttribute = GUID;
63
		}
64
	}
65

    
66
	/**
67
	 * Get all xml access for a document
68
	 * 
69
	 * @param id
70
	 *            the id of the document
71
	 * @return an xml access DAO list
72
	 */ 
73
	public Vector<XMLAccessDAO> getXMLAccessForDoc(String id) throws AccessException {
74

    
75
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
76
		
77
		if (id == null) {
78
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - doc id " + 
79
					"must be specified when selecting xml_access record");
80
		}
81
			
82
		// first get the xml access from the db and put it into a DAO list
83
		PreparedStatement pstmt = null;
84
		DBConnection conn = null;
85
		int serialNumber = -1;
86
		try {			
87
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForDoc");
88
    		serialNumber = conn.getCheckOutSerialNumber();
89

    
90
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ?";
91
			pstmt = conn.prepareStatement(sql);
92

    
93
			pstmt.setString(1, id);
94
			
95
			String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
96
			sqlReport += " [" + id + "]";
97
			
98
			logMetacat.info(sqlReport);
99
			
100
			pstmt.execute();
101
			
102
			ResultSet resultSet = pstmt.getResultSet();
103
			while (resultSet.next()) {
104
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
105
				xmlAccessList.add(xmlAccessDAO);
106
			}
107
					
108
			// make sure permission orders do not conflict in the database
109
			validateDocXMLAccessList(xmlAccessList);
110
			
111
			return xmlAccessList;
112
			
113
		} catch (SQLException sqle) {
114
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - SQL error when getting access " + 
115
					" for id: " + id  + " : "  + sqle.getMessage());
116
		} catch (PermOrderException poe) {
117
			String errorStr = "XMLAccessAccess.getXMLAccessForDoc - Permission order error when getting " + 
118
				"access record for doc id: " + id + " : "  + poe.getMessage();
119
			logMetacat.error(errorStr);
120
			throw new AccessException(errorStr);
121
		} finally {
122
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
123
		}		
124
	}
125
	
126
	/**
127
	 * Get all xml access for a principal for a certain document
128
	 * 
129
	 * @param id
130
	 *            the id of the document
131
	 * @param principalName
132
	 *            the credentials of the principal in the database
133
	 * @return an xml access DAO list
134
	 */ 
135
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName) 
136
			throws AccessException {
137

    
138
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
139
		
140
		if (id == null) { 
141
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " + 
142
					"must be specified when selecting xml_access record");
143
		}
144
		if (principalName == null) { 
145
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " + 
146
					"must be specified when selecting xml_access record");
147
		}
148
			
149
		// first get the xml access for this principal from the db and put it into a DAO list
150
		PreparedStatement pstmt = null;
151
		DBConnection conn = null;
152
		int serialNumber = -1;
153
		try {
154
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
155
    		serialNumber = conn.getCheckOutSerialNumber();
156
			
157
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
158
			pstmt = conn.prepareStatement(sql);
159

    
160
			pstmt.setString(1, id);
161
			pstmt.setString(2, principalName);
162
			
163
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
164
			sqlReport += " [" + id + "," + principalName + "]";
165
			
166
			logMetacat.info(sqlReport);
167
			
168
			pstmt.execute();
169
			
170
			ResultSet resultSet = pstmt.getResultSet();
171
			while (resultSet.next()) {
172
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
173
				xmlAccessList.add(xmlAccessDAO);
174
			}
175
			
176
			// make sure permission orders do not conflict in the database
177
			validatePrincipalXMLAccessList(xmlAccessList);
178
			
179
			return xmlAccessList;
180
			
181
		} catch (SQLException sqle) {
182
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " + 
183
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
184
		} catch (PermOrderException poe) {
185
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " + 
186
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
187
			logMetacat.error(errorStr);
188
			throw new AccessException(errorStr);
189
		} finally {
190
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
191
		}		
192
	}
193
	
194
	/**
195
	 * Get all xml access for a principal/permType/permOrder for a certain document
196
	 * 
197
	 * @param id
198
	 *            the id of the document
199
	 * @param principalName
200
	 *            the credentials of the principal in the database
201
	 * @return an xml access DAO list
202
	 */ 
203
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder) 
204
			throws AccessException {
205

    
206
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
207
		
208
		if (id == null) { 
209
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " + 
210
					"must be specified when selecting xml_access record");
211
		}
212
		if (principalName == null) { 
213
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " + 
214
					"must be specified when selecting xml_access record");
215
		}
216
		if (permType == null) { 
217
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - permission type " + 
218
					"must be specified when selecting xml_access record");
219
		}
220
		if (permOrder == null) { 
221
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - permission order " + 
222
					"must be specified when selecting xml_access record");
223
		}
224
					
225
		// first get the xml access for this principal from the db and put it into a DAO list
226
		PreparedStatement pstmt = null;
227
		DBConnection conn = null;
228
		int serialNumber = -1;
229
		try {
230
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
231
    		serialNumber = conn.getCheckOutSerialNumber();
232
    		
233
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " + 
234
				"AND perm_type = ? AND perm_order = ?";
235
			pstmt = conn.prepareStatement(sql);
236

    
237
			pstmt.setString(1, id);
238
			pstmt.setString(2, principalName);
239
			pstmt.setString(3, permType);			
240
			pstmt.setString(4, permOrder);
241
			
242
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
243
			sqlReport += " [" + id + "," + principalName + "," +  permType + "," + permOrder + "]";
244
			
245
			logMetacat.info(sqlReport);
246
			
247
			pstmt.execute();
248
			
249
			ResultSet resultSet = pstmt.getResultSet();
250
			while (resultSet.next()) {
251
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
252
				xmlAccessList.add(xmlAccessDAO);
253
			}
254
			
255
			validatePrincipalXMLAccessList(xmlAccessList);
256
			
257
			return xmlAccessList;
258
			
259
		} catch (SQLException sqle) {
260
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " + 
261
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
262
		} catch (PermOrderException poe) {
263
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " + 
264
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
265
			logMetacat.error(errorStr);
266
			throw new AccessException(errorStr);
267
		} finally {
268
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
269
		}		
270
	}
271
	
272
	/**
273
	 * Add permissions for a given principal on a given document. If the
274
	 * principal already exists, bitwise OR the permission to the existing
275
	 * permission and update.
276
	 * 
277
	 * @param id
278
	 *            document id
279
	 * @param principalName
280
	 *            principal credentials
281
	 * @param permission
282
	 *            permission bitmap
283
	 * @param permType
284
	 *            permission type
285
	 * @param permOrder
286
	 *            permission order
287
	 */
288
	public void addXMLAccess(String id, String principalName, Long permission, String permType, 
289
			String permOrder, String accessFileId, String subTreeId) throws AccessException, PermOrderException {
290
		
291
		permOrderConflict(id, permOrder);
292
		
293
		Vector<XMLAccessDAO> xmlAccessList = 
294
			getXMLAccessForPrincipal(id, principalName, permType, permOrder);
295
		
296
		// if more than one record exists for this principal on this document with the same
297
		// access type / access order combination, call cleanup to combine common access and then
298
		// re-retrieve the access list.
299
		if (xmlAccessList.size() == 0) {
300
			insertXMLAccess(id, principalName, permission, permType, permOrder, accessFileId, subTreeId);
301
			return;
302
		}
303
		
304
		if (xmlAccessList.size() > 1) {
305
			cleanupXMLAccessForPrincipal(xmlAccessList);
306
			xmlAccessList = getXMLAccessForPrincipal(id, principalName, permType, permOrder);
307
		}
308
		
309
		if (xmlAccessList.size() == 0) {
310
			throw new AccessException("XMLAccessAccess.addXMLAccess - xml access list is empty when " + 
311
				"it shouldn't be for id: " + id + ", prinicpal name: " + principalName + ", perm type " + 
312
				permType + ", perm order: " + permOrder);	
313
		}
314
		
315
		XMLAccessDAO xmlAccessDAO = xmlAccessList.get(0);
316
				
317
		// if the permission on the xml access dao does not already contain the permission we are 
318
		//trying to add, update the access record with the existing permission bitwis OR-ed with our
319
		// new permission
320
		if ((xmlAccessDAO.getPermission() & permission) != permission) {		
321
			updateXMLAccessPermission(id, principalName, xmlAccessDAO.getPermission() | permission);
322
		}
323
	}
324
	
325
	/**
326
	 * Set permissions for a given document. This means first removing all access control for the
327
	 * document and then adding the given rules.
328
	 * 
329
	 * @param id
330
	 *            document id
331
	 * @param xmlAccessList
332
	 *            list of xml access dao objects that hold new access for the document
333
	 */
334
	public void replaceAccess(String id, List<XMLAccessDAO> xmlAccessList) throws AccessException {
335
		deleteXMLAccessForDoc(id);
336
		
337
		// if more than one record exists for this principal on this document with the same
338
		// access type / access order combination, call cleanup to combine common access and then
339
		// re-retrieve the access list.
340
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
341
			insertXMLAccess(id, xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(), 
342
					xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder(), xmlAccessDAO.getAccessFileId(), xmlAccessDAO.getSubTreeId());
343
		}
344
	}
345
	
346
	/**
347
	 * Insert an xml access record.  It is assumed that the checks have already been made to 
348
	 * make sure the principal does not already have an access record for this document.  If 
349
	 * one does already exist, that record should be updated and this insert not called.
350
	 * 
351
	 * @param id
352
	 *            document id
353
	 * @param principal
354
	 *            principal credentials
355
	 * @param permission
356
	 *            permission bitmap
357
	 * @param permType
358
	 *            permission type
359
	 * @param permOrder
360
	 *            permission order
361
	 */
362
	private void insertXMLAccess(String id, String principalName, Long permission, String permType,
363
			String permOrder, String accessFileId, String subTreeId) throws AccessException {
364
	    //System.out.println("permission in insertXMLAccess: " + permission);
365
	    try
366
	    {
367
	        if(permission == -1)
368
	        {
369
	            throw new Exception("Permission is -1 in XMLAccessAccess.insertXMLAccess().");
370
	        }
371
	    }
372
	    catch(Exception e)
373
	    {
374
	        e.printStackTrace();
375
	        logMetacat.warn(e.getMessage());
376
	    }
377
	    
378
		if (id == null) {
379
			throw new AccessException("XMLAccessAccess.insertXMLAccess - id is required when " + 
380
					"inserting XML access record");
381
		}
382
		if (principalName == null) {
383
			throw new AccessException("XMLAccessAccess.insertXMLAccess - principal is required when " + 
384
					"inserting XML access record");
385
		}
386
		if (permission == null) {
387
			throw new AccessException("XMLAccessAccess.insertXMLAccess - permission is required when " + 
388
					"inserting XML access record");
389
		}
390
		if (permType == null) {
391
			throw new AccessException("XMLAccessAccess.insertXMLAccess - permType is required when " + 
392
					"inserting XML access record");
393
		}
394
		if (permOrder == null) {
395
			permOrder = AccessControlInterface.ALLOWFIRST;
396
		}
397
		
398
	    PreparedStatement pstmt = null;
399
		DBConnection conn = null;
400
		int serialNumber = -1;
401
		try {
402
			// check out DBConnection
403
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.insertXMLAccess");
404
			serialNumber = conn.getCheckOutSerialNumber();
405
			
406
			String sql = "INSERT INTO xml_access " +
407
				"(docid, guid, principal_name, permission, perm_type, perm_order, accessfileid, subtreeid ) " + 
408
				"VALUES (?,?,?,?,?,?,?,?)";
409
			pstmt = conn.prepareStatement(sql);
410

    
411
			String guid = null;
412
			String docid = null;
413
			if (idAttribute.equals(GUID)) {
414
				guid = id;
415
				try {
416
					docid = IdentifierManager.getInstance().getLocalId(id);
417
				} catch (McdbDocNotFoundException e) {
418
					//ignore
419
					logMetacat.warn("No local id mapping found for guid: " + id);
420
				}
421
			} else {
422
				int rev = DBUtil.getLatestRevisionInDocumentTable(id);
423
				try {
424
					guid = IdentifierManager.getInstance().getGUID(id, rev);
425
				} catch (McdbDocNotFoundException e) {
426
					//ignore
427
					logMetacat.warn("No guid mapping found for docid: " + id + "." + rev);
428
				}
429
				docid = id;
430
			}
431
			
432
			// Bind the values to the query
433
			pstmt.setString(1, docid);
434
			pstmt.setString(2, guid);
435
			pstmt.setString(3, principalName);
436
			pstmt.setLong(4, permission);
437
			pstmt.setString(5, permType);
438
			pstmt.setString(6, permOrder);
439
			pstmt.setString(7, accessFileId);
440
			pstmt.setString(8, subTreeId);
441
			
442
			String sqlReport = "XMLAccessAccess.insertXMLAccess - SQL: " + sql;
443
			sqlReport += " [" + docid + "," + guid + "," + principalName + "," +  permission + "," +  permType + "," + permOrder + "]";
444
			
445
			logMetacat.info(sqlReport);
446

    
447
			pstmt.execute();
448
		} catch (SQLException sqle) {
449
			throw new AccessException("XMLAccessAccess.insertXMLAccess - SQL error when inserting"
450
					+ "xml access permissions for id: " + id + ", principal: " + 
451
					principalName + ":" + sqle.getMessage());
452
		} finally {
453
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
454
		}   
455
	}
456
	
457
	/**
458
	 * Update existing xml access permissions in the db.  The permission value should be the combined
459
	 * value of pre-existing permissions plus new permissions.
460
	 * 
461
	 * @param id
462
	 *            document id
463
	 * @param principalName
464
	 *            principal credentials
465
	 * @param permission
466
	 *            permission bitmap
467
	 */
468
	private void updateXMLAccessPermission(String id, String principalName, Long permission)
469
			throws AccessException {
470
		if (id == null) {
471
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - id is required when " + 
472
					"updating XML access record");
473
		}
474
		if (principalName == null) {
475
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - principal is required when " + 
476
					"updating XML access record");
477
		}
478
		if (permission == null) {
479
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - permission is required when " + 
480
					"updating XML access record");
481
		}
482
		
483
	    PreparedStatement pstmt = null;
484
		DBConnection conn = null;
485
		int serialNumber = -1;
486
		try {
487
			// check out DBConnection
488
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.updateXMLAccessPermission");
489
			serialNumber = conn.getCheckOutSerialNumber();
490
			
491
			String sql = "UPDATE xml_access SET permission = ?" +
492
				"WHERE " + idAttribute + " = ? AND principal_name = ?";
493
			pstmt = conn.prepareStatement(sql);
494

    
495
			// Bind the values to the query
496
			pstmt.setLong(1, permission);
497
			pstmt.setString(2, id);
498
			pstmt.setString(3, principalName);
499
			
500
			String sqlReport = "XMLAccessAccess.updateXMLAccessPermission - SQL: " + sql;
501
			sqlReport += " [" + permission + "," + id + "," + principalName + "]";
502
			
503
			logMetacat.info(sqlReport);
504

    
505
			pstmt.execute();
506
		} catch (SQLException sqle) {
507
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - SQL error when updating"
508
					+ "xml access permissions for id: " + id + ", principal: " + 
509
					principalName + ":" + sqle.getMessage());
510
		} finally {
511
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
512
		}
513
		
514
	}
515
	
516
	/**
517
	 * Remove xml access.  This modifies the access in the database for a principal 
518
	 * for a given document.  If the provided permission is exactly the same as what 
519
	 * the principal has, the record is deleted from the database.
520
	 * 
521
	 * @param id
522
	 *            document id
523
	 * @param principalName
524
	 *            principal credentials
525
	 */
526
	public void removeXMLAccessForPrincipal(String id, String principalName, Long permission) throws AccessException {
527
		if (id == null) {
528
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - id is required when " + 
529
					"removing XML access");
530
		}
531
		if (principalName == null) {
532
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - principal is required when " + 
533
					"deleting XML access");
534
		}
535
		if (permission == null) {
536
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - permission is required when " + 
537
					"updating XML access");
538
		}
539
		
540
		Vector<XMLAccessDAO> xmlAccessList = getXMLAccessForPrincipal(id, principalName);
541
		if (xmlAccessList.size() == 0) {
542
			logMetacat.warn("XMLAccessAccess.removeXMLAccessForPrincipal - attempting to remove access when no " +
543
				"access record exists for id: " + id + ", principal: " + principalName);
544
		} else {
545
			long permissionMask = 0;
546
			for (XMLAccessDAO xmlAccessDAO : xmlAccessList) {
547
				permissionMask |= xmlAccessDAO.getPermission();
548
			}
549
			permissionMask |= permission;
550
			
551
			// in this case, the only existing permissions are the ones we want to remove, so 
552
			// delete the record(s) for this principal on this document
553
			if ((permissionMask & permission) == permission) {
554
				deleteXMLAccessForPrincipal(id, principalName);
555
			}
556
			
557
			if (xmlAccessList.size() > 1) {
558
				
559
			} else {
560
				updateXMLAccessPermission(id, principalName, permission);
561
			}
562
		}
563
	   
564
	}
565
	
566
	/**
567
	 * Delete xml access.  This removes all access records from the database for a given document
568
	 * 
569
	 * @param id
570
	 *            document id
571
	 */
572
	public void deleteXMLAccessForDoc(String id) throws AccessException {
573
		if (id == null) {
574
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " + 
575
					"deleting XML access record");
576
		}
577
		
578
	    PreparedStatement pstmt = null;
579
		DBConnection conn = null;
580
		int serialNumber = -1;
581
		try {
582
			// check out DBConnection
583
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForDoc");
584
    		serialNumber = conn.getCheckOutSerialNumber();
585
    		
586
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ?";
587
			pstmt = conn.prepareStatement(sql);
588

    
589
			// Bind the values to the query
590
			pstmt.setString(1, id);
591

    
592
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
593
			sqlReport += " [" + id + "]";
594
			
595
			logMetacat.info(sqlReport);
596

    
597
			pstmt.execute();
598
		} catch (SQLException sqle) {
599
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
600
					+ "xml access permissions for id: " + id + ":" + sqle.getMessage());
601
		} finally {
602
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
603
		}	   
604
	}
605
	
606
	/**
607
	 * Delete xml access.  This removes all access records from the database for a principal 
608
	 * for a given document
609
	 * 
610
	 * @param id
611
	 *            document id
612
	 * @param principal
613
	 *            principal credentials
614
	 */
615
	private void deleteXMLAccessForPrincipal(String id, String principalName) throws AccessException {
616
		if (id == null) {
617
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " + 
618
					"deleting XML access record");
619
		}
620
		if (principalName == null) {
621
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " + 
622
					"deleting XML access record");
623
		}
624
		
625
	    PreparedStatement pstmt = null;
626
		DBConnection conn = null;
627
		int serialNumber = -1;
628
		try {
629
			// check out DBConnection
630
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
631
    		serialNumber = conn.getCheckOutSerialNumber();
632
    		
633
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
634
			pstmt = conn.prepareStatement(sql);
635

    
636
			// Bind the values to the query
637
			pstmt.setString(1, id);
638
			pstmt.setString(2, principalName);
639

    
640
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
641
			sqlReport += " [" + id + "," + principalName + "]";
642
			
643
			logMetacat.info(sqlReport);
644

    
645
			pstmt.execute();
646
		} catch (SQLException sqle) {
647
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
648
					+ "xml access permissions for id: " + id + ", principal: " + 
649
					principalName + ":" + sqle.getMessage());
650
		} finally {
651
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
652
		}	   
653
	}
654
	
655
	/**
656
	 * Checks to see if there is a permission order conflict for a given document.  Each 
657
	 * document is only allowed to have a single permission order
658
	 * 
659
	 * @param id
660
	 *            document id
661
	 * @param principal
662
	 *            principal credentials
663
	 */
664
	private void permOrderConflict(String id, String permOrder) throws AccessException, PermOrderException {
665
		if (id == null) {
666
			throw new AccessException("XMLAccessAccess.permOrderConflict - id is required when " + 
667
					"determining perm order conflict");
668
		}
669
		if (permOrder == null) {
670
			throw new AccessException("XMLAccessAccess.permOrderConflict - perm order is required when " + 
671
					"determining perm order conflict");
672
		}
673
		
674
	    PreparedStatement pstmt = null;
675
		DBConnection conn = null;
676
		int serialNumber = -1;
677
		try {
678
			// check out DBConnection
679
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.permOrderConflict");
680
    		serialNumber = conn.getCheckOutSerialNumber();
681
    		
682
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND perm_order != ?";
683
			pstmt = conn.prepareStatement(sql);
684

    
685
			// Bind the values to the query
686
			pstmt.setString(1, id);
687
			pstmt.setString(2, permOrder);
688
			
689
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
690
			sqlReport += " [" + id + "," + permOrder + "]";
691
			
692
			logMetacat.info(sqlReport);
693

    
694
			pstmt.execute();
695
			
696
			ResultSet resultSet = pstmt.getResultSet();
697
			if (resultSet.next()) {			
698
				throw new PermOrderException("XMLAccessAccess.addXMLAccess - cannot add permission " + 
699
					"record for id: " + id + "with permOrder: " + permOrder + " due to permOrder conflict");
700
			}
701
		} catch (SQLException sqle) {
702
			throw new AccessException("XMLAccessAccess.permOrderConflict - SQL error when checking"
703
					+ "for perm order conflict on: " + id + ":" + sqle.getMessage());
704
		} finally {
705
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
706
		}
707
	   
708
	}
709
	
710
	/**
711
	 * Delete xml access.  This removes all access records from the database for a principal 
712
	 * for a given document, perm type and perm order
713
	 * 
714
	 * @param id
715
	 *            document id
716
	 * @param principal
717
	 *            principal credentials
718
	 */
719
	private void deleteXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder) throws AccessException {
720
		if (id == null) {
721
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " + 
722
					"deleting XML access record");
723
		}
724
		if (principalName == null) {
725
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " + 
726
					"deleting XML access record");
727
		}
728
		if (permType == null) {
729
			throw new AccessException(
730
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm type is required when "
731
							+ "deleting XML access record");
732
		}
733
		if (permOrder == null) {
734
			throw new AccessException(
735
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm order is required when "
736
							+ "deleting XML access record");
737
		}
738
		
739
	    PreparedStatement pstmt = null;
740
		DBConnection conn = null;
741
		int serialNumber = -1;
742
		try {
743
			// check out DBConnection
744
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
745
    		serialNumber = conn.getCheckOutSerialNumber();
746
    		
747
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
748
				"AND perm_type = ? AND perm_order = ?";
749
			pstmt = conn.prepareStatement(sql);
750

    
751
			// Bind the values to the query
752
			pstmt.setString(1, id);
753
			pstmt.setString(2, principalName);
754
			pstmt.setString(3, permType);
755
			pstmt.setString(4, permOrder);
756
			
757
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
758
			sqlReport += " [" + id + "," + principalName + "," + permType + "," + permOrder + "]";
759
			
760
			logMetacat.info(sqlReport);
761

    
762
			pstmt.execute();
763
		} catch (SQLException sqle) {
764
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
765
					+ "xml access permissions for id: " + id + ", principal: " + 
766
					principalName + ":" + sqle.getMessage());
767
		} finally {
768
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
769
		}
770
	   
771
	}
772

    
773
	/**
774
	 * Make sure that only one record exists per principal/permType/document. If
775
	 * more than one record exists, delete the existing records, consolidate the
776
	 * permissions insert the new record.
777
	 * 
778
	 * @param xmlAccessList the access dao list
779
	 */
780
	private void cleanupXMLAccessForPrincipal(Vector<XMLAccessDAO> xmlAccessList) throws AccessException{
781
		
782
		int numAllowRecords = 0;
783
		int numDenyRecords = 0;
784
		long allowPermissionMask = 0;
785
		long denyPermissionMask = 0;
786
		String id = null;
787
		String principalName = null;
788
		String permType = null;
789
		String permOrder = null;
790
		// TODO: handle these fields
791
		String accessFileId = null;
792
		String subTreeId = null;
793
	
794
		
795
		// iterate through the list of access dao objects and bttwise or the permissions.  Most
796
		// of this is just doing some error checking to make sure each record is valid.
797
		for (XMLAccessDAO xmlAccessDAO : xmlAccessList) {
798
			String daoId = xmlAccessDAO.getDocId();
799
			if (idAttribute.equals(GUID)) {
800
				daoId = xmlAccessDAO.getGuid();
801
			}
802
			if (id == null) {
803
				id = daoId;
804
			} else {
805
				if (!id.equals(daoId)) {
806
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " + 
807
							" Conflicting ids " + daoId + " and " + id);
808
				}
809
			}
810
			if (principalName == null) {
811
				principalName = xmlAccessDAO.getPrincipalName();
812
			} else {
813
				if (!principalName.equals(xmlAccessDAO.getPrincipalName())) {
814
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " + 
815
							" Conflicting prinicpal names " + xmlAccessDAO.getPrincipalName() +
816
							" and principalName " + principalName);
817
				}
818
			}
819
			if (permType == null) {
820
				permType = xmlAccessDAO.getPermType();
821
			} else {
822
				if (!permType.equals(xmlAccessDAO.getPermType())) {
823
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " + 
824
							" Conflicting permission orders for document " + daoId +
825
							"principalName " + principalName + ". Database intervention required ");
826
				}
827
			}
828
			if (permOrder == null) {
829
				permOrder = xmlAccessDAO.getPermOrder();
830
			} else {
831
				if (!permOrder.equals(xmlAccessDAO.getPermOrder())) {
832
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " + 
833
							" Conflicting permission types for document " + daoId +
834
							"principalName " + principalName + ". Database intervention required ");
835
				}
836
			}
837
			if (permType == null) {
838
				permType = xmlAccessDAO.getPermType();
839
			} else {
840
				if (!permType.equals(xmlAccessDAO.getPermType())) {
841
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " + 
842
							" Conflicting permission orders for document " + daoId +
843
							"principalName " + principalName + ". Database intervention required ");
844
				}
845
			}
846
			if (permType.equals(AccessControlInterface.ALLOW)) {
847
				numAllowRecords++;
848
				allowPermissionMask |= xmlAccessDAO.getPermission();
849
			} else if (permType.equals(AccessControlInterface.DENY)) {
850
				numDenyRecords++;
851
				denyPermissionMask |= xmlAccessDAO.getPermission();
852
			}
853
			if (accessFileId == null) {
854
				accessFileId = xmlAccessDAO.getAccessFileId();
855
			}
856
			if (subTreeId == null) {
857
				subTreeId = xmlAccessDAO.getSubTreeId();
858
			}
859
		}
860
		
861
		// if there was more than one allow record, remove all allow records for this user on this doc 
862
		// with this perm type and perm order then insert a single record 
863
		if (numAllowRecords > 1) {
864
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.ALLOW, permOrder);
865
			insertXMLAccess(id, principalName, allowPermissionMask, AccessControlInterface.ALLOW, permOrder, accessFileId, subTreeId);
866
		}
867
		// if there was more than one deny record, remove all deny records for this user on this doc 
868
		// with this perm type and perm order then insert a single record 
869
		if (numDenyRecords > 1) {
870
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.DENY, permOrder);
871
			insertXMLAccess(id, principalName, denyPermissionMask, AccessControlInterface.DENY, permOrder, accessFileId, subTreeId);
872
		}
873
	}
874
	
875
	/**
876
	 * Make sure for a given list of access DAOs that only one perm order
877
	 * exists. It is assumed that all the DAOs are for the same doc
878
	 * 
879
	 * @param xmlAccessList
880
	 *            the access dao list
881
	 */
882
	private void validateDocXMLAccessList(Vector<XMLAccessDAO> xmlAccessList) throws PermOrderException {
883
		String permOrder = null;
884
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
885
			String daoId = xmlAccessDAO.getDocId();
886
			if (idAttribute.equals(GUID)) {
887
				daoId = xmlAccessDAO.getGuid();
888
			}
889
			if (permOrder == null) {
890
				permOrder = xmlAccessDAO.getPermOrder();
891
			} else {
892
				if(!permOrder.equals(xmlAccessDAO.getPermOrder())) {
893
					throw new PermOrderException("XMLAccessAccess.validateXMLAccessList - " + 
894
						" Conflicting permission orders for document " + daoId +
895
						". Database intervention required ");
896
				}
897
			}
898
		}		
899
	}
900
	
901
	/**
902
	 * Check that only one permOrder exists for each principal. 
903
	 * TODO add check that one of each permType exists as well
904
	 * 
905
	 * @param xmlAccessList
906
	 *            the access dao list
907
	 */
908
	private void validatePrincipalXMLAccessList(Vector<XMLAccessDAO> xmlAccessList) 
909
			throws PermOrderException {
910
		
911
		boolean allowFirst = false;
912
		boolean denyFirst = false;
913
		String id = null;
914
		
915
		// These vectors will hold all combinations of access DAOs with different permission
916
		// orders and permission types.  
917
		Vector<XMLAccessDAO> allowFirstAllows = new Vector<XMLAccessDAO>();
918
		Vector<XMLAccessDAO> allowFirstDenys = new Vector<XMLAccessDAO>();
919
		Vector<XMLAccessDAO> denyFirstAllows = new Vector<XMLAccessDAO>();
920
		Vector<XMLAccessDAO> denyFirstDenys = new Vector<XMLAccessDAO>();
921
		
922
		// sort the access dao records into the appropriate vector
923
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
924
			String daoId = xmlAccessDAO.getDocId();
925
			if (idAttribute.equals(GUID)) {
926
				daoId = xmlAccessDAO.getGuid();
927
			}
928
			if (id == null) {
929
				id = daoId;
930
			}
931
			if (xmlAccessDAO.getPermOrder().equals(AccessControlInterface.ALLOWFIRST)) {
932
				allowFirst = true;
933
				if (xmlAccessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
934
					allowFirstAllows.add(xmlAccessDAO);
935
				} else if (xmlAccessDAO.getPermType().equals(AccessControlInterface.DENY)) {
936
					allowFirstDenys.add(xmlAccessDAO);
937
				} else {
938
					throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " + 
939
							" Invalid permission type: " + xmlAccessDAO.getPermType() + " for document " + 
940
							daoId + ". Database intervention required "); 
941
				}
942
			} else if (xmlAccessDAO.getPermOrder().equals(AccessControlInterface.DENYFIRST)) {
943
				denyFirst = true;
944
				if (xmlAccessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
945
					denyFirstAllows.add(xmlAccessDAO);
946
				} else if (xmlAccessDAO.getPermType().equals(AccessControlInterface.DENY)) {
947
					denyFirstDenys.add(xmlAccessDAO);
948
				} else {
949
					throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " + 
950
							" Invalid permission type: " + xmlAccessDAO.getPermType() + " for document " + 
951
							daoId + ". Database intervention required "); 
952
				}
953
			} else {
954
				throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " + 
955
						" Invalid permission order: " + xmlAccessDAO.getPermOrder() + " for document " + 
956
						daoId + ". Database intervention required "); 
957
			}
958
		}
959
		
960
		// for a given user, there cannot be allowfirst and denyfirst records on the same 
961
		// document
962
		if(allowFirst && denyFirst) {
963
			throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " + 
964
					" Conflicting permission orders for document " + id +
965
					". Database intervention required ");
966
		}	
967
	}
968
	
969
	/**
970
	 * Populate a job data object with the current row in a resultset
971
	 * 
972
	 * @param resultSet
973
	 *            the result set which is already pointing to the desired row.
974
	 * @return a scheduled job data object
975
	 */
976
	protected XMLAccessDAO populateDAO(ResultSet resultSet) throws SQLException {
977

    
978
		XMLAccessDAO xmlAccessDAO = new XMLAccessDAO();
979
		xmlAccessDAO.setDocId(resultSet.getString(idAttribute));
980
		xmlAccessDAO.setAccessFileId(resultSet.getString("accessfileid"));
981
		xmlAccessDAO.setPrincipalName(resultSet.getString("principal_name"));
982
		xmlAccessDAO.setPermission(resultSet.getLong("permission"));
983
		xmlAccessDAO.setPermType(resultSet.getString("perm_type"));
984
		xmlAccessDAO.setPermOrder(resultSet.getString("perm_order"));
985
		xmlAccessDAO.setBeginTime(resultSet.getDate("begin_time"));
986
		xmlAccessDAO.setEndTime(resultSet.getDate("end_time"));
987
		xmlAccessDAO.setTicketCount(resultSet.getLong("ticket_count"));
988
		xmlAccessDAO.setSubTreeId(resultSet.getString("subtreeid"));
989
		xmlAccessDAO.setStartNodeId(resultSet.getString("startnodeid"));
990
		xmlAccessDAO.setEndNodeId(resultSet.getString("endnodeid"));
991

    
992
		return xmlAccessDAO;
993
	}
994
	
995
}
(8-8/9)