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
			
591
			String guid = null;
592
			String docid = null;
593
			if (idAttribute.equals(GUID)) {
594
				guid = id;
595
				try {
596
					String localId = IdentifierManager.getInstance().getLocalId(id);
597
					// Parse the localId into scope and rev parts, strip off the rev
598
		            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
599
		            docid = acc.getDocid();
600
				} catch (McdbDocNotFoundException e) {
601
					//ignore
602
					logMetacat.warn("No local id mapping found for guid: " + id);
603
				} catch (NumberFormatException e) {
604
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
605
                } catch (AccessionNumberException e) {
606
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
607
                }
608
			} else {
609
				int rev = DBUtil.getLatestRevisionInDocumentTable(id);
610
				try {
611
					guid = IdentifierManager.getInstance().getGUID(id, rev);
612
				} catch (McdbDocNotFoundException e) {
613
					//ignore
614
					logMetacat.warn("No guid mapping found for docid: " + id + "." + rev);
615
				}
616
				docid = id;
617
			}
618
			
619
			// check out DBConnection
620
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForDoc");
621
    		serialNumber = conn.getCheckOutSerialNumber();
622
    		
623
			String sql = "DELETE FROM xml_access WHERE docid = ? OR guid = ?";
624
			pstmt = conn.prepareStatement(sql);
625

    
626
			// Bind the values to the query
627
			pstmt.setString(1, docid);
628
			pstmt.setString(2, guid);
629

    
630

    
631
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
632
			sqlReport += " [" + id + "]";
633
			
634
			logMetacat.info(sqlReport);
635

    
636
			pstmt.execute();
637
		} catch (SQLException sqle) {
638
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
639
					+ "xml access permissions for id: " + id + ":" + sqle.getMessage());
640
		} finally {
641
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
642
		}	   
643
	}
644
	
645
	/**
646
	 * Delete xml access.  This removes all access records from the database for a principal 
647
	 * for a given document
648
	 * 
649
	 * @param id
650
	 *            document id
651
	 * @param principal
652
	 *            principal credentials
653
	 */
654
	private void deleteXMLAccessForPrincipal(String id, String principalName) throws AccessException {
655
		if (id == null) {
656
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " + 
657
					"deleting XML access record");
658
		}
659
		if (principalName == null) {
660
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " + 
661
					"deleting XML access record");
662
		}
663
		
664
	    PreparedStatement pstmt = null;
665
		DBConnection conn = null;
666
		int serialNumber = -1;
667
		try {
668
			// check out DBConnection
669
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
670
    		serialNumber = conn.getCheckOutSerialNumber();
671
    		
672
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
673
			pstmt = conn.prepareStatement(sql);
674

    
675
			// Bind the values to the query
676
			pstmt.setString(1, id);
677
			pstmt.setString(2, principalName);
678

    
679
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
680
			sqlReport += " [" + id + "," + principalName + "]";
681
			
682
			logMetacat.info(sqlReport);
683

    
684
			pstmt.execute();
685
		} catch (SQLException sqle) {
686
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
687
					+ "xml access permissions for id: " + id + ", principal: " + 
688
					principalName + ":" + sqle.getMessage());
689
		} finally {
690
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
691
		}	   
692
	}
693
	
694
	/**
695
	 * Checks to see if there is a permission order conflict for a given document.  Each 
696
	 * document is only allowed to have a single permission order
697
	 * 
698
	 * @param id
699
	 *            document id
700
	 * @param principal
701
	 *            principal credentials
702
	 */
703
	private void permOrderConflict(String id, String permOrder) throws AccessException, PermOrderException {
704
		if (id == null) {
705
			throw new AccessException("XMLAccessAccess.permOrderConflict - id is required when " + 
706
					"determining perm order conflict");
707
		}
708
		if (permOrder == null) {
709
			throw new AccessException("XMLAccessAccess.permOrderConflict - perm order is required when " + 
710
					"determining perm order conflict");
711
		}
712
		
713
	    PreparedStatement pstmt = null;
714
		DBConnection conn = null;
715
		int serialNumber = -1;
716
		try {
717
			// check out DBConnection
718
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.permOrderConflict");
719
    		serialNumber = conn.getCheckOutSerialNumber();
720
    		
721
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND perm_order != ?";
722
			pstmt = conn.prepareStatement(sql);
723

    
724
			// Bind the values to the query
725
			pstmt.setString(1, id);
726
			pstmt.setString(2, permOrder);
727
			
728
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
729
			sqlReport += " [" + id + "," + permOrder + "]";
730
			
731
			logMetacat.info(sqlReport);
732

    
733
			pstmt.execute();
734
			
735
			ResultSet resultSet = pstmt.getResultSet();
736
			if (resultSet.next()) {			
737
				throw new PermOrderException("XMLAccessAccess.addXMLAccess - cannot add permission " + 
738
					"record for id: " + id + "with permOrder: " + permOrder + " due to permOrder conflict");
739
			}
740
		} catch (SQLException sqle) {
741
			throw new AccessException("XMLAccessAccess.permOrderConflict - SQL error when checking"
742
					+ "for perm order conflict on: " + id + ":" + sqle.getMessage());
743
		} finally {
744
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
745
		}
746
	   
747
	}
748
	
749
	/**
750
	 * Delete xml access.  This removes all access records from the database for a principal 
751
	 * for a given document, perm type and perm order
752
	 * 
753
	 * @param id
754
	 *            document id
755
	 * @param principal
756
	 *            principal credentials
757
	 */
758
	private void deleteXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder) throws AccessException {
759
		if (id == null) {
760
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " + 
761
					"deleting XML access record");
762
		}
763
		if (principalName == null) {
764
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " + 
765
					"deleting XML access record");
766
		}
767
		if (permType == null) {
768
			throw new AccessException(
769
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm type is required when "
770
							+ "deleting XML access record");
771
		}
772
		if (permOrder == null) {
773
			throw new AccessException(
774
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm order is required when "
775
							+ "deleting XML access record");
776
		}
777
		
778
	    PreparedStatement pstmt = null;
779
		DBConnection conn = null;
780
		int serialNumber = -1;
781
		try {
782
			// check out DBConnection
783
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
784
    		serialNumber = conn.getCheckOutSerialNumber();
785
    		
786
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
787
				"AND perm_type = ? AND perm_order = ?";
788
			pstmt = conn.prepareStatement(sql);
789

    
790
			// Bind the values to the query
791
			pstmt.setString(1, id);
792
			pstmt.setString(2, principalName);
793
			pstmt.setString(3, permType);
794
			pstmt.setString(4, permOrder);
795
			
796
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
797
			sqlReport += " [" + id + "," + principalName + "," + permType + "," + permOrder + "]";
798
			
799
			logMetacat.info(sqlReport);
800

    
801
			pstmt.execute();
802
		} catch (SQLException sqle) {
803
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
804
					+ "xml access permissions for id: " + id + ", principal: " + 
805
					principalName + ":" + sqle.getMessage());
806
		} finally {
807
			closeDBObjects(pstmt, conn, serialNumber, logMetacat); 
808
		}
809
	   
810
	}
811

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

    
1017
		XMLAccessDAO xmlAccessDAO = new XMLAccessDAO();
1018
		xmlAccessDAO.setDocId(resultSet.getString(idAttribute));
1019
		xmlAccessDAO.setAccessFileId(resultSet.getString("accessfileid"));
1020
		xmlAccessDAO.setPrincipalName(resultSet.getString("principal_name"));
1021
		xmlAccessDAO.setPermission(resultSet.getLong("permission"));
1022
		xmlAccessDAO.setPermType(resultSet.getString("perm_type"));
1023
		xmlAccessDAO.setPermOrder(resultSet.getString("perm_order"));
1024
		xmlAccessDAO.setBeginTime(resultSet.getDate("begin_time"));
1025
		xmlAccessDAO.setEndTime(resultSet.getDate("end_time"));
1026
		xmlAccessDAO.setTicketCount(resultSet.getLong("ticket_count"));
1027
		xmlAccessDAO.setSubTreeId(resultSet.getString("subtreeid"));
1028
		xmlAccessDAO.setStartNodeId(resultSet.getString("startnodeid"));
1029
		xmlAccessDAO.setEndNodeId(resultSet.getString("endnodeid"));
1030

    
1031
		return xmlAccessDAO;
1032
	}
1033
	
1034
}
(8-8/9)