Project

General

Profile

1 5091 daigle
/**
2
 *  '$RCSfile$'
3 5098 daigle
 *    Purpose: A Class that manages database access of xml access
4 5091 daigle
 *             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 6108 leinfelder
import java.util.List;
34 5091 daigle
import java.util.Vector;
35
36
import org.apache.log4j.Logger;
37
38 6422 leinfelder
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 5091 daigle
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 6122 leinfelder
	private static String DOCID = "docid";
52
53
	private static String GUID = "guid";
54
55
	private String idAttribute = DOCID;
56
57 5091 daigle
	// Constructor
58 5108 daigle
	public XMLAccessAccess() throws AccessException {}
59 5091 daigle
60 6122 leinfelder
	public XMLAccessAccess(boolean useGuid) {
61
		if (useGuid) {
62
			idAttribute = GUID;
63
		}
64
	}
65
66 5091 daigle
	/**
67
	 * Get all xml access for a document
68
	 *
69 6122 leinfelder
	 * @param id
70 5091 daigle
	 *            the id of the document
71
	 * @return an xml access DAO list
72
	 */
73 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForDoc(String id) throws AccessException {
74 5091 daigle
75
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
76
77 6122 leinfelder
		if (id == null) {
78 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - doc id " +
79
					"must be specified when selecting xml_access record");
80
		}
81
82 5115 daigle
		// first get the xml access from the db and put it into a DAO list
83 5091 daigle
		PreparedStatement pstmt = null;
84 5108 daigle
		DBConnection conn = null;
85
		int serialNumber = -1;
86
		try {
87
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForDoc");
88
    		serialNumber = conn.getCheckOutSerialNumber();
89
90 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ?";
91 5091 daigle
			pstmt = conn.prepareStatement(sql);
92
93 6122 leinfelder
			pstmt.setString(1, id);
94 5091 daigle
95
			String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
96 6122 leinfelder
			sqlReport += " [" + id + "]";
97 5091 daigle
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 5115 daigle
108
			// make sure permission orders do not conflict in the database
109 5091 daigle
			validateDocXMLAccessList(xmlAccessList);
110
111
			return xmlAccessList;
112
113
		} catch (SQLException sqle) {
114
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - SQL error when getting access " +
115 6122 leinfelder
					" for id: " + id  + " : "  + sqle.getMessage());
116 5091 daigle
		} catch (PermOrderException poe) {
117
			String errorStr = "XMLAccessAccess.getXMLAccessForDoc - Permission order error when getting " +
118 6122 leinfelder
				"access record for doc id: " + id + " : "  + poe.getMessage();
119 5091 daigle
			logMetacat.error(errorStr);
120
			throw new AccessException(errorStr);
121
		} finally {
122 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
123 5091 daigle
		}
124
	}
125
126
	/**
127
	 * Get all xml access for a principal for a certain document
128
	 *
129 6122 leinfelder
	 * @param id
130 5091 daigle
	 *            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 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName)
136 5091 daigle
			throws AccessException {
137
138
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
139
140 6122 leinfelder
		if (id == null) {
141 5091 daigle
			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 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
150 5091 daigle
		PreparedStatement pstmt = null;
151 5108 daigle
		DBConnection conn = null;
152
		int serialNumber = -1;
153 5091 daigle
		try {
154 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
155
    		serialNumber = conn.getCheckOutSerialNumber();
156
157 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
158 5091 daigle
			pstmt = conn.prepareStatement(sql);
159
160 6122 leinfelder
			pstmt.setString(1, id);
161 5091 daigle
			pstmt.setString(2, principalName);
162
163
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
164 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "]";
165 5091 daigle
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 5115 daigle
			// make sure permission orders do not conflict in the database
177 5091 daigle
			validatePrincipalXMLAccessList(xmlAccessList);
178
179
			return xmlAccessList;
180
181
		} catch (SQLException sqle) {
182
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " +
183 6122 leinfelder
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
184 5091 daigle
		} catch (PermOrderException poe) {
185
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
186 6122 leinfelder
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
187 5091 daigle
			logMetacat.error(errorStr);
188
			throw new AccessException(errorStr);
189
		} finally {
190 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
191 5091 daigle
		}
192
	}
193
194
	/**
195 5115 daigle
	 * Get all xml access for a principal/permType/permOrder for a certain document
196 5091 daigle
	 *
197 6122 leinfelder
	 * @param id
198 5091 daigle
	 *            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 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder)
204 5091 daigle
			throws AccessException {
205
206
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
207
208 6122 leinfelder
		if (id == null) {
209 5091 daigle
			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 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
226 5091 daigle
		PreparedStatement pstmt = null;
227 5108 daigle
		DBConnection conn = null;
228
		int serialNumber = -1;
229 5091 daigle
		try {
230 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
231
    		serialNumber = conn.getCheckOutSerialNumber();
232
233 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
234 5091 daigle
				"AND perm_type = ? AND perm_order = ?";
235
			pstmt = conn.prepareStatement(sql);
236
237 6122 leinfelder
			pstmt.setString(1, id);
238 5091 daigle
			pstmt.setString(2, principalName);
239
			pstmt.setString(3, permType);
240
			pstmt.setString(4, permOrder);
241
242
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
243 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "," +  permType + "," + permOrder + "]";
244 5091 daigle
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 6122 leinfelder
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
262 5091 daigle
		} catch (PermOrderException poe) {
263
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
264 6122 leinfelder
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
265 5091 daigle
			logMetacat.error(errorStr);
266
			throw new AccessException(errorStr);
267
		} finally {
268 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
269 5091 daigle
		}
270
	}
271
272
	/**
273 5098 daigle
	 * Add permissions for a given principal on a given document. If the
274
	 * principal already exists, bitwise OR the permission to the existing
275 5091 daigle
	 * permission and update.
276
	 *
277 6122 leinfelder
	 * @param id
278 5091 daigle
	 *            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 6122 leinfelder
	public void addXMLAccess(String id, String principalName, Long permission, String permType,
289 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException, PermOrderException {
290 5108 daigle
291 6122 leinfelder
		permOrderConflict(id, permOrder);
292 5108 daigle
293 5091 daigle
		Vector<XMLAccessDAO> xmlAccessList =
294 6122 leinfelder
			getXMLAccessForPrincipal(id, principalName, permType, permOrder);
295 5091 daigle
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 6122 leinfelder
			insertXMLAccess(id, principalName, permission, permType, permOrder, accessFileId, subTreeId);
301 5091 daigle
			return;
302
		}
303
304
		if (xmlAccessList.size() > 1) {
305
			cleanupXMLAccessForPrincipal(xmlAccessList);
306 6122 leinfelder
			xmlAccessList = getXMLAccessForPrincipal(id, principalName, permType, permOrder);
307 5091 daigle
		}
308
309
		if (xmlAccessList.size() == 0) {
310
			throw new AccessException("XMLAccessAccess.addXMLAccess - xml access list is empty when " +
311 6122 leinfelder
				"it shouldn't be for id: " + id + ", prinicpal name: " + principalName + ", perm type " +
312 5091 daigle
				permType + ", perm order: " + permOrder);
313
		}
314
315
		XMLAccessDAO xmlAccessDAO = xmlAccessList.get(0);
316 5108 daigle
317 5091 daigle
		// 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 6122 leinfelder
			updateXMLAccessPermission(id, principalName, xmlAccessDAO.getPermission() | permission);
322 5091 daigle
		}
323
	}
324
325
	/**
326 5098 daigle
	 * 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 6122 leinfelder
	 * @param id
330 5091 daigle
	 *            document id
331 5098 daigle
	 * @param xmlAccessList
332
	 *            list of xml access dao objects that hold new access for the document
333
	 */
334 6122 leinfelder
	public void replaceAccess(String id, List<XMLAccessDAO> xmlAccessList) throws AccessException {
335
		deleteXMLAccessForDoc(id);
336 5098 daigle
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 6122 leinfelder
			insertXMLAccess(id, xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(),
342 6017 leinfelder
					xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder(), xmlAccessDAO.getAccessFileId(), xmlAccessDAO.getSubTreeId());
343 5098 daigle
		}
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 6122 leinfelder
	 * @param id
352 5098 daigle
	 *            document id
353 5091 daigle
	 * @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 6122 leinfelder
	private void insertXMLAccess(String id, String principalName, Long permission, String permType,
363 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException {
364 5734 berkley
	    //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 6122 leinfelder
		if (id == null) {
379
			throw new AccessException("XMLAccessAccess.insertXMLAccess - id is required when " +
380 5091 daigle
					"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 5120 daigle
406 5091 daigle
			String sql = "INSERT INTO xml_access " +
407 6422 leinfelder
				"(docid, guid, principal_name, permission, perm_type, perm_order, accessfileid, subtreeid ) " +
408
				"VALUES (?,?,?,?,?,?,?,?)";
409 5091 daigle
			pstmt = conn.prepareStatement(sql);
410
411 6422 leinfelder
			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 5091 daigle
			// Bind the values to the query
433 6422 leinfelder
			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 5091 daigle
442
			String sqlReport = "XMLAccessAccess.insertXMLAccess - SQL: " + sql;
443 6422 leinfelder
			sqlReport += " [" + docid + "," + guid + "," + principalName + "," +  permission + "," +  permType + "," + permOrder + "]";
444 5091 daigle
445
			logMetacat.info(sqlReport);
446
447
			pstmt.execute();
448
		} catch (SQLException sqle) {
449
			throw new AccessException("XMLAccessAccess.insertXMLAccess - SQL error when inserting"
450 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
451 5091 daigle
					principalName + ":" + sqle.getMessage());
452
		} finally {
453 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
454 5091 daigle
		}
455
	}
456
457
	/**
458 5098 daigle
	 * 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 6122 leinfelder
	 * @param id
462 5091 daigle
	 *            document id
463
	 * @param principalName
464
	 *            principal credentials
465
	 * @param permission
466
	 *            permission bitmap
467
	 */
468 6122 leinfelder
	private void updateXMLAccessPermission(String id, String principalName, Long permission)
469 5091 daigle
			throws AccessException {
470 6122 leinfelder
		if (id == null) {
471
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - id is required when " +
472 5091 daigle
					"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 5120 daigle
491 5091 daigle
			String sql = "UPDATE xml_access SET permission = ?" +
492 6122 leinfelder
				"WHERE " + idAttribute + " = ? AND principal_name = ?";
493 5091 daigle
			pstmt = conn.prepareStatement(sql);
494
495
			// Bind the values to the query
496
			pstmt.setLong(1, permission);
497 6122 leinfelder
			pstmt.setString(2, id);
498 5091 daigle
			pstmt.setString(3, principalName);
499
500
			String sqlReport = "XMLAccessAccess.updateXMLAccessPermission - SQL: " + sql;
501 6122 leinfelder
			sqlReport += " [" + permission + "," + id + "," + principalName + "]";
502 5091 daigle
503
			logMetacat.info(sqlReport);
504
505
			pstmt.execute();
506
		} catch (SQLException sqle) {
507
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - SQL error when updating"
508 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
509 5091 daigle
					principalName + ":" + sqle.getMessage());
510
		} finally {
511 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
512 5091 daigle
		}
513
514
	}
515
516
	/**
517 5098 daigle
	 * Remove xml access.  This modifies the access in the database for a principal
518 5091 daigle
	 * for a given document.  If the provided permission is exactly the same as what
519 5098 daigle
	 * the principal has, the record is deleted from the database.
520
	 *
521 6122 leinfelder
	 * @param id
522 5091 daigle
	 *            document id
523
	 * @param principalName
524
	 *            principal credentials
525
	 */
526 6122 leinfelder
	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 5091 daigle
					"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 6122 leinfelder
		Vector<XMLAccessDAO> xmlAccessList = getXMLAccessForPrincipal(id, principalName);
541 5091 daigle
		if (xmlAccessList.size() == 0) {
542
			logMetacat.warn("XMLAccessAccess.removeXMLAccessForPrincipal - attempting to remove access when no " +
543 6122 leinfelder
				"access record exists for id: " + id + ", principal: " + principalName);
544 5091 daigle
		} 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 6122 leinfelder
				deleteXMLAccessForPrincipal(id, principalName);
555 5091 daigle
			}
556
557
			if (xmlAccessList.size() > 1) {
558
559
			} else {
560 6122 leinfelder
				updateXMLAccessPermission(id, principalName, permission);
561 5091 daigle
			}
562
		}
563
564
	}
565
566
	/**
567 5098 daigle
	 * Delete xml access.  This removes all access records from the database for a given document
568
	 *
569 6122 leinfelder
	 * @param id
570 5098 daigle
	 *            document id
571
	 */
572 6122 leinfelder
	public void deleteXMLAccessForDoc(String id) throws AccessException {
573
		if (id == null) {
574
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
575 5098 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
585
586 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ?";
587 5098 daigle
			pstmt = conn.prepareStatement(sql);
588
589
			// Bind the values to the query
590 6122 leinfelder
			pstmt.setString(1, id);
591 5098 daigle
592
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
593 6122 leinfelder
			sqlReport += " [" + id + "]";
594 5098 daigle
595
			logMetacat.info(sqlReport);
596
597
			pstmt.execute();
598
		} catch (SQLException sqle) {
599
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
600 6122 leinfelder
					+ "xml access permissions for id: " + id + ":" + sqle.getMessage());
601 5098 daigle
		} finally {
602 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
603 5098 daigle
		}
604
	}
605
606
	/**
607 5091 daigle
	 * Delete xml access.  This removes all access records from the database for a principal
608
	 * for a given document
609 5098 daigle
	 *
610 6122 leinfelder
	 * @param id
611 5091 daigle
	 *            document id
612
	 * @param principal
613
	 *            principal credentials
614
	 */
615 6122 leinfelder
	private void deleteXMLAccessForPrincipal(String id, String principalName) throws AccessException {
616
		if (id == null) {
617
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
618 5091 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
632
633 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
634 5091 daigle
			pstmt = conn.prepareStatement(sql);
635
636
			// Bind the values to the query
637 6122 leinfelder
			pstmt.setString(1, id);
638 5091 daigle
			pstmt.setString(2, principalName);
639
640
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
641 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "]";
642 5091 daigle
643
			logMetacat.info(sqlReport);
644
645
			pstmt.execute();
646
		} catch (SQLException sqle) {
647
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
648 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
649 5091 daigle
					principalName + ":" + sqle.getMessage());
650
		} finally {
651 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
652 5091 daigle
		}
653
	}
654
655
	/**
656 5115 daigle
	 * 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 6122 leinfelder
	 * @param id
660 5091 daigle
	 *            document id
661
	 * @param principal
662
	 *            principal credentials
663
	 */
664 6122 leinfelder
	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 5108 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
681
682 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND perm_order != ?";
683 5108 daigle
			pstmt = conn.prepareStatement(sql);
684
685
			// Bind the values to the query
686 6122 leinfelder
			pstmt.setString(1, id);
687 5108 daigle
			pstmt.setString(2, permOrder);
688
689
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
690 6122 leinfelder
			sqlReport += " [" + id + "," + permOrder + "]";
691 5108 daigle
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 6122 leinfelder
					"record for id: " + id + "with permOrder: " + permOrder + " due to permOrder conflict");
700 5108 daigle
			}
701
		} catch (SQLException sqle) {
702
			throw new AccessException("XMLAccessAccess.permOrderConflict - SQL error when checking"
703 6122 leinfelder
					+ "for perm order conflict on: " + id + ":" + sqle.getMessage());
704 5108 daigle
		} 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 5115 daigle
	 *
714 6122 leinfelder
	 * @param id
715 5108 daigle
	 *            document id
716
	 * @param principal
717
	 *            principal credentials
718
	 */
719 6122 leinfelder
	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 5091 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
746
747 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
748 5108 daigle
				"AND perm_type = ? AND perm_order = ?";
749 5091 daigle
			pstmt = conn.prepareStatement(sql);
750
751
			// Bind the values to the query
752 6122 leinfelder
			pstmt.setString(1, id);
753 5091 daigle
			pstmt.setString(2, principalName);
754
			pstmt.setString(3, permType);
755
			pstmt.setString(4, permOrder);
756
757
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
758 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "," + permType + "," + permOrder + "]";
759 5091 daigle
760
			logMetacat.info(sqlReport);
761
762
			pstmt.execute();
763
		} catch (SQLException sqle) {
764
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
765 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
766 5091 daigle
					principalName + ":" + sqle.getMessage());
767
		} finally {
768 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
769 5091 daigle
		}
770
771
	}
772 5098 daigle
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 5115 daigle
	 * @param xmlAccessList the access dao list
779 5098 daigle
	 */
780 5091 daigle
	private void cleanupXMLAccessForPrincipal(Vector<XMLAccessDAO> xmlAccessList) throws AccessException{
781
782 5098 daigle
		int numAllowRecords = 0;
783
		int numDenyRecords = 0;
784
		long allowPermissionMask = 0;
785
		long denyPermissionMask = 0;
786 6122 leinfelder
		String id = null;
787 5091 daigle
		String principalName = null;
788
		String permType = null;
789
		String permOrder = null;
790 6017 leinfelder
		// TODO: handle these fields
791
		String accessFileId = null;
792
		String subTreeId = null;
793 5091 daigle
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 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
799
			if (idAttribute.equals(GUID)) {
800
				daoId = xmlAccessDAO.getGuid();
801
			}
802
			if (id == null) {
803
				id = daoId;
804 5091 daigle
			} else {
805 6122 leinfelder
				if (!id.equals(daoId)) {
806 5091 daigle
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
807 6122 leinfelder
							" Conflicting ids " + daoId + " and " + id);
808 5091 daigle
				}
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 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
825 5091 daigle
							"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 6122 leinfelder
							" Conflicting permission types for document " + daoId +
834 5091 daigle
							"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 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
843 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
844
				}
845
			}
846 5098 daigle
			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 6017 leinfelder
			if (accessFileId == null) {
854
				accessFileId = xmlAccessDAO.getAccessFileId();
855
			}
856
			if (subTreeId == null) {
857
				subTreeId = xmlAccessDAO.getSubTreeId();
858
			}
859 5091 daigle
		}
860
861 5098 daigle
		// 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 6122 leinfelder
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.ALLOW, permOrder);
865
			insertXMLAccess(id, principalName, allowPermissionMask, AccessControlInterface.ALLOW, permOrder, accessFileId, subTreeId);
866 5098 daigle
		}
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 6122 leinfelder
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.DENY, permOrder);
871
			insertXMLAccess(id, principalName, denyPermissionMask, AccessControlInterface.DENY, permOrder, accessFileId, subTreeId);
872 5098 daigle
		}
873 5091 daigle
	}
874
875 5098 daigle
	/**
876 5115 daigle
	 * 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 5098 daigle
	 *
879
	 * @param xmlAccessList
880 5115 daigle
	 *            the access dao list
881 5098 daigle
	 */
882 5091 daigle
	private void validateDocXMLAccessList(Vector<XMLAccessDAO> xmlAccessList) throws PermOrderException {
883
		String permOrder = null;
884
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
885 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
886
			if (idAttribute.equals(GUID)) {
887
				daoId = xmlAccessDAO.getGuid();
888
			}
889 5091 daigle
			if (permOrder == null) {
890
				permOrder = xmlAccessDAO.getPermOrder();
891
			} else {
892
				if(!permOrder.equals(xmlAccessDAO.getPermOrder())) {
893
					throw new PermOrderException("XMLAccessAccess.validateXMLAccessList - " +
894 6122 leinfelder
						" Conflicting permission orders for document " + daoId +
895 5091 daigle
						". Database intervention required ");
896
				}
897
			}
898
		}
899
	}
900
901 5115 daigle
	/**
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 5091 daigle
	private void validatePrincipalXMLAccessList(Vector<XMLAccessDAO> xmlAccessList)
909
			throws PermOrderException {
910
911
		boolean allowFirst = false;
912
		boolean denyFirst = false;
913 6122 leinfelder
		String id = null;
914 5091 daigle
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 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
925
			if (idAttribute.equals(GUID)) {
926
				daoId = xmlAccessDAO.getGuid();
927 5091 daigle
			}
928 6122 leinfelder
			if (id == null) {
929
				id = daoId;
930
			}
931 5091 daigle
			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 6122 leinfelder
							daoId + ". Database intervention required ");
941 5091 daigle
				}
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 6122 leinfelder
							daoId + ". Database intervention required ");
952 5091 daigle
				}
953
			} else {
954
				throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
955
						" Invalid permission order: " + xmlAccessDAO.getPermOrder() + " for document " +
956 6122 leinfelder
						daoId + ". Database intervention required ");
957 5091 daigle
			}
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 6122 leinfelder
					" Conflicting permission orders for document " + id +
965 5091 daigle
					". 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 6122 leinfelder
		xmlAccessDAO.setDocId(resultSet.getString(idAttribute));
980 5091 daigle
		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
}