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.AccessionNumberException;
40
import edu.ucsb.nceas.metacat.DBUtil;
41
import edu.ucsb.nceas.metacat.IdentifierManager;
42
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
43
import edu.ucsb.nceas.metacat.database.DBConnection;
44
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
45
import edu.ucsb.nceas.metacat.shared.AccessException;
46
import edu.ucsb.nceas.metacat.shared.BaseAccess;
47

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

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

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

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

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

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

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

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

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

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

    
412
			String guid = null;
413
			String docid = null;
414
			if (idAttribute.equals(GUID)) {
415
				guid = id;
416
				try {
417
					String localId = IdentifierManager.getInstance().getLocalId(id);
418
					// Parse the localId into scope and rev parts, strip off the rev
419
		            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
420
		            docid = acc.getDocid();
421
				} catch (McdbDocNotFoundException e) {
422
					//ignore
423
					logMetacat.warn("No local id mapping found for guid: " + id);
424
				} catch (NumberFormatException e) {
425
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
426
                } catch (AccessionNumberException e) {
427
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
428
                }
429
			} else {
430
				int rev = DBUtil.getLatestRevisionInDocumentTable(id);
431
				try {
432
					guid = IdentifierManager.getInstance().getGUID(id, rev);
433
				} catch (McdbDocNotFoundException e) {
434
					//ignore
435
					logMetacat.warn("No guid mapping found for docid: " + id + "." + rev);
436
				}
437
				docid = id;
438
			}
439
			
440
			// Bind the values to the query
441
			pstmt.setString(1, docid);
442
			pstmt.setString(2, guid);
443
			pstmt.setString(3, principalName);
444
			pstmt.setLong(4, permission);
445
			pstmt.setString(5, permType);
446
			pstmt.setString(6, permOrder);
447
			pstmt.setString(7, accessFileId);
448
			pstmt.setString(8, subTreeId);
449
			
450
			String sqlReport = "XMLAccessAccess.insertXMLAccess - SQL: " + sql;
451
			sqlReport += " [" + docid + "," + guid + "," + principalName + "," +  permission + "," +  permType + "," + permOrder + "]";
452
			
453
			logMetacat.info(sqlReport);
454

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

    
503
			// Bind the values to the query
504
			pstmt.setLong(1, permission);
505
			pstmt.setString(2, id);
506
			pstmt.setString(3, principalName);
507
			
508
			String sqlReport = "XMLAccessAccess.updateXMLAccessPermission - SQL: " + sql;
509
			sqlReport += " [" + permission + "," + id + "," + principalName + "]";
510
			
511
			logMetacat.info(sqlReport);
512

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

    
597
			// Bind the values to the query
598
			pstmt.setString(1, id);
599

    
600
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
601
			sqlReport += " [" + id + "]";
602
			
603
			logMetacat.info(sqlReport);
604

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

    
644
			// Bind the values to the query
645
			pstmt.setString(1, id);
646
			pstmt.setString(2, principalName);
647

    
648
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
649
			sqlReport += " [" + id + "," + principalName + "]";
650
			
651
			logMetacat.info(sqlReport);
652

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

    
693
			// Bind the values to the query
694
			pstmt.setString(1, id);
695
			pstmt.setString(2, permOrder);
696
			
697
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
698
			sqlReport += " [" + id + "," + permOrder + "]";
699
			
700
			logMetacat.info(sqlReport);
701

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

    
759
			// Bind the values to the query
760
			pstmt.setString(1, id);
761
			pstmt.setString(2, principalName);
762
			pstmt.setString(3, permType);
763
			pstmt.setString(4, permOrder);
764
			
765
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
766
			sqlReport += " [" + id + "," + principalName + "," + permType + "," + permOrder + "]";
767
			
768
			logMetacat.info(sqlReport);
769

    
770
			pstmt.execute();
771
		} catch (SQLException sqle) {
772
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
773
					+ "xml access permissions for id: " + id + ", principal: " + 
774
					principalName + ":" + sqle.getMessage());
775
		} finally {
776
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
777
		}
778
	   
779
	}
780

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

    
986
		XMLAccessDAO xmlAccessDAO = new XMLAccessDAO();
987
		xmlAccessDAO.setDocId(resultSet.getString(idAttribute));
988
		xmlAccessDAO.setAccessFileId(resultSet.getString("accessfileid"));
989
		xmlAccessDAO.setPrincipalName(resultSet.getString("principal_name"));
990
		xmlAccessDAO.setPermission(resultSet.getLong("permission"));
991
		xmlAccessDAO.setPermType(resultSet.getString("perm_type"));
992
		xmlAccessDAO.setPermOrder(resultSet.getString("perm_order"));
993
		xmlAccessDAO.setBeginTime(resultSet.getDate("begin_time"));
994
		xmlAccessDAO.setEndTime(resultSet.getDate("end_time"));
995
		xmlAccessDAO.setTicketCount(resultSet.getLong("ticket_count"));
996
		xmlAccessDAO.setSubTreeId(resultSet.getString("subtreeid"));
997
		xmlAccessDAO.setStartNodeId(resultSet.getString("startnodeid"));
998
		xmlAccessDAO.setEndNodeId(resultSet.getString("endnodeid"));
999

    
1000
		return xmlAccessDAO;
1001
	}
1002
	
1003
}
(8-8/9)