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 6527 jones
import edu.ucsb.nceas.metacat.AccessionNumberException;
40 6422 leinfelder
import edu.ucsb.nceas.metacat.DBUtil;
41
import edu.ucsb.nceas.metacat.IdentifierManager;
42
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
43 5091 daigle
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 6122 leinfelder
	private static String DOCID = "docid";
53
54
	private static String GUID = "guid";
55
56
	private String idAttribute = DOCID;
57
58 5091 daigle
	// Constructor
59 5108 daigle
	public XMLAccessAccess() throws AccessException {}
60 5091 daigle
61 6122 leinfelder
	public XMLAccessAccess(boolean useGuid) {
62
		if (useGuid) {
63
			idAttribute = GUID;
64
		}
65
	}
66
67 5091 daigle
	/**
68
	 * Get all xml access for a document
69
	 *
70 6122 leinfelder
	 * @param id
71 5091 daigle
	 *            the id of the document
72
	 * @return an xml access DAO list
73
	 */
74 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForDoc(String id) throws AccessException {
75 5091 daigle
76
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
77
78 6122 leinfelder
		if (id == null) {
79 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - doc id " +
80
					"must be specified when selecting xml_access record");
81
		}
82
83 5115 daigle
		// first get the xml access from the db and put it into a DAO list
84 5091 daigle
		PreparedStatement pstmt = null;
85 5108 daigle
		DBConnection conn = null;
86
		int serialNumber = -1;
87
		try {
88
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForDoc");
89
    		serialNumber = conn.getCheckOutSerialNumber();
90
91 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ?";
92 5091 daigle
			pstmt = conn.prepareStatement(sql);
93
94 6122 leinfelder
			pstmt.setString(1, id);
95 5091 daigle
96
			String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
97 6122 leinfelder
			sqlReport += " [" + id + "]";
98 5091 daigle
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 5115 daigle
109
			// make sure permission orders do not conflict in the database
110 5091 daigle
			validateDocXMLAccessList(xmlAccessList);
111
112
			return xmlAccessList;
113
114
		} catch (SQLException sqle) {
115
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - SQL error when getting access " +
116 6122 leinfelder
					" for id: " + id  + " : "  + sqle.getMessage());
117 5091 daigle
		} catch (PermOrderException poe) {
118
			String errorStr = "XMLAccessAccess.getXMLAccessForDoc - Permission order error when getting " +
119 6122 leinfelder
				"access record for doc id: " + id + " : "  + poe.getMessage();
120 5091 daigle
			logMetacat.error(errorStr);
121
			throw new AccessException(errorStr);
122
		} finally {
123 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
124 5091 daigle
		}
125
	}
126
127
	/**
128
	 * Get all xml access for a principal for a certain document
129
	 *
130 6122 leinfelder
	 * @param id
131 5091 daigle
	 *            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 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName)
137 5091 daigle
			throws AccessException {
138
139
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
140
141 6122 leinfelder
		if (id == null) {
142 5091 daigle
			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 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
151 5091 daigle
		PreparedStatement pstmt = null;
152 5108 daigle
		DBConnection conn = null;
153
		int serialNumber = -1;
154 5091 daigle
		try {
155 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
156
    		serialNumber = conn.getCheckOutSerialNumber();
157
158 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
159 5091 daigle
			pstmt = conn.prepareStatement(sql);
160
161 6122 leinfelder
			pstmt.setString(1, id);
162 5091 daigle
			pstmt.setString(2, principalName);
163
164
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
165 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "]";
166 5091 daigle
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 5115 daigle
			// make sure permission orders do not conflict in the database
178 5091 daigle
			validatePrincipalXMLAccessList(xmlAccessList);
179
180
			return xmlAccessList;
181
182
		} catch (SQLException sqle) {
183
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " +
184 6122 leinfelder
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
185 5091 daigle
		} catch (PermOrderException poe) {
186
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
187 6122 leinfelder
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
188 5091 daigle
			logMetacat.error(errorStr);
189
			throw new AccessException(errorStr);
190
		} finally {
191 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
192 5091 daigle
		}
193
	}
194
195
	/**
196 5115 daigle
	 * Get all xml access for a principal/permType/permOrder for a certain document
197 5091 daigle
	 *
198 6122 leinfelder
	 * @param id
199 5091 daigle
	 *            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 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder)
205 5091 daigle
			throws AccessException {
206
207
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
208
209 6122 leinfelder
		if (id == null) {
210 5091 daigle
			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 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
227 5091 daigle
		PreparedStatement pstmt = null;
228 5108 daigle
		DBConnection conn = null;
229
		int serialNumber = -1;
230 5091 daigle
		try {
231 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
232
    		serialNumber = conn.getCheckOutSerialNumber();
233
234 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
235 5091 daigle
				"AND perm_type = ? AND perm_order = ?";
236
			pstmt = conn.prepareStatement(sql);
237
238 6122 leinfelder
			pstmt.setString(1, id);
239 5091 daigle
			pstmt.setString(2, principalName);
240
			pstmt.setString(3, permType);
241
			pstmt.setString(4, permOrder);
242
243
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
244 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "," +  permType + "," + permOrder + "]";
245 5091 daigle
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 6122 leinfelder
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
263 5091 daigle
		} catch (PermOrderException poe) {
264
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
265 6122 leinfelder
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
266 5091 daigle
			logMetacat.error(errorStr);
267
			throw new AccessException(errorStr);
268
		} finally {
269 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
270 5091 daigle
		}
271
	}
272
273
	/**
274 5098 daigle
	 * Add permissions for a given principal on a given document. If the
275
	 * principal already exists, bitwise OR the permission to the existing
276 5091 daigle
	 * permission and update.
277
	 *
278 6122 leinfelder
	 * @param id
279 5091 daigle
	 *            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 6122 leinfelder
	public void addXMLAccess(String id, String principalName, Long permission, String permType,
290 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException, PermOrderException {
291 5108 daigle
292 6122 leinfelder
		permOrderConflict(id, permOrder);
293 5108 daigle
294 5091 daigle
		Vector<XMLAccessDAO> xmlAccessList =
295 6122 leinfelder
			getXMLAccessForPrincipal(id, principalName, permType, permOrder);
296 5091 daigle
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 6122 leinfelder
			insertXMLAccess(id, principalName, permission, permType, permOrder, accessFileId, subTreeId);
302 5091 daigle
			return;
303
		}
304
305
		if (xmlAccessList.size() > 1) {
306
			cleanupXMLAccessForPrincipal(xmlAccessList);
307 6122 leinfelder
			xmlAccessList = getXMLAccessForPrincipal(id, principalName, permType, permOrder);
308 5091 daigle
		}
309
310
		if (xmlAccessList.size() == 0) {
311
			throw new AccessException("XMLAccessAccess.addXMLAccess - xml access list is empty when " +
312 6122 leinfelder
				"it shouldn't be for id: " + id + ", prinicpal name: " + principalName + ", perm type " +
313 5091 daigle
				permType + ", perm order: " + permOrder);
314
		}
315
316
		XMLAccessDAO xmlAccessDAO = xmlAccessList.get(0);
317 5108 daigle
318 5091 daigle
		// 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 6122 leinfelder
			updateXMLAccessPermission(id, principalName, xmlAccessDAO.getPermission() | permission);
323 5091 daigle
		}
324
	}
325
326
	/**
327 5098 daigle
	 * 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 6122 leinfelder
	 * @param id
331 5091 daigle
	 *            document id
332 5098 daigle
	 * @param xmlAccessList
333
	 *            list of xml access dao objects that hold new access for the document
334
	 */
335 6122 leinfelder
	public void replaceAccess(String id, List<XMLAccessDAO> xmlAccessList) throws AccessException {
336
		deleteXMLAccessForDoc(id);
337 5098 daigle
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 6122 leinfelder
			insertXMLAccess(id, xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(),
343 6017 leinfelder
					xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder(), xmlAccessDAO.getAccessFileId(), xmlAccessDAO.getSubTreeId());
344 5098 daigle
		}
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 6122 leinfelder
	 * @param id
353 5098 daigle
	 *            document id
354 5091 daigle
	 * @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 6122 leinfelder
	private void insertXMLAccess(String id, String principalName, Long permission, String permType,
364 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException {
365 5734 berkley
	    //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 6122 leinfelder
		if (id == null) {
380
			throw new AccessException("XMLAccessAccess.insertXMLAccess - id is required when " +
381 5091 daigle
					"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 5120 daigle
407 5091 daigle
			String sql = "INSERT INTO xml_access " +
408 6422 leinfelder
				"(docid, guid, principal_name, permission, perm_type, perm_order, accessfileid, subtreeid ) " +
409
				"VALUES (?,?,?,?,?,?,?,?)";
410 5091 daigle
			pstmt = conn.prepareStatement(sql);
411
412 6422 leinfelder
			String guid = null;
413
			String docid = null;
414
			if (idAttribute.equals(GUID)) {
415
				guid = id;
416
				try {
417 6527 jones
					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 6422 leinfelder
				} catch (McdbDocNotFoundException e) {
422
					//ignore
423
					logMetacat.warn("No local id mapping found for guid: " + id);
424 6527 jones
				} 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 6422 leinfelder
			} 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 5091 daigle
			// Bind the values to the query
441 6422 leinfelder
			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 5091 daigle
450
			String sqlReport = "XMLAccessAccess.insertXMLAccess - SQL: " + sql;
451 6422 leinfelder
			sqlReport += " [" + docid + "," + guid + "," + principalName + "," +  permission + "," +  permType + "," + permOrder + "]";
452 5091 daigle
453
			logMetacat.info(sqlReport);
454
455
			pstmt.execute();
456
		} catch (SQLException sqle) {
457
			throw new AccessException("XMLAccessAccess.insertXMLAccess - SQL error when inserting"
458 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
459 5091 daigle
					principalName + ":" + sqle.getMessage());
460
		} finally {
461 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
462 5091 daigle
		}
463
	}
464
465
	/**
466 5098 daigle
	 * 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 6122 leinfelder
	 * @param id
470 5091 daigle
	 *            document id
471
	 * @param principalName
472
	 *            principal credentials
473
	 * @param permission
474
	 *            permission bitmap
475
	 */
476 6122 leinfelder
	private void updateXMLAccessPermission(String id, String principalName, Long permission)
477 5091 daigle
			throws AccessException {
478 6122 leinfelder
		if (id == null) {
479
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - id is required when " +
480 5091 daigle
					"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 5120 daigle
499 5091 daigle
			String sql = "UPDATE xml_access SET permission = ?" +
500 6122 leinfelder
				"WHERE " + idAttribute + " = ? AND principal_name = ?";
501 5091 daigle
			pstmt = conn.prepareStatement(sql);
502
503
			// Bind the values to the query
504
			pstmt.setLong(1, permission);
505 6122 leinfelder
			pstmt.setString(2, id);
506 5091 daigle
			pstmt.setString(3, principalName);
507
508
			String sqlReport = "XMLAccessAccess.updateXMLAccessPermission - SQL: " + sql;
509 6122 leinfelder
			sqlReport += " [" + permission + "," + id + "," + principalName + "]";
510 5091 daigle
511
			logMetacat.info(sqlReport);
512
513
			pstmt.execute();
514
		} catch (SQLException sqle) {
515
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - SQL error when updating"
516 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
517 5091 daigle
					principalName + ":" + sqle.getMessage());
518
		} finally {
519 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
520 5091 daigle
		}
521
522
	}
523
524
	/**
525 5098 daigle
	 * Remove xml access.  This modifies the access in the database for a principal
526 5091 daigle
	 * for a given document.  If the provided permission is exactly the same as what
527 5098 daigle
	 * the principal has, the record is deleted from the database.
528
	 *
529 6122 leinfelder
	 * @param id
530 5091 daigle
	 *            document id
531
	 * @param principalName
532
	 *            principal credentials
533
	 */
534 6122 leinfelder
	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 5091 daigle
					"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 6122 leinfelder
		Vector<XMLAccessDAO> xmlAccessList = getXMLAccessForPrincipal(id, principalName);
549 5091 daigle
		if (xmlAccessList.size() == 0) {
550
			logMetacat.warn("XMLAccessAccess.removeXMLAccessForPrincipal - attempting to remove access when no " +
551 6122 leinfelder
				"access record exists for id: " + id + ", principal: " + principalName);
552 5091 daigle
		} 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 6122 leinfelder
				deleteXMLAccessForPrincipal(id, principalName);
563 5091 daigle
			}
564
565
			if (xmlAccessList.size() > 1) {
566
567
			} else {
568 6122 leinfelder
				updateXMLAccessPermission(id, principalName, permission);
569 5091 daigle
			}
570
		}
571
572
	}
573
574
	/**
575 5098 daigle
	 * Delete xml access.  This removes all access records from the database for a given document
576
	 *
577 6122 leinfelder
	 * @param id
578 5098 daigle
	 *            document id
579
	 */
580 6122 leinfelder
	public void deleteXMLAccessForDoc(String id) throws AccessException {
581
		if (id == null) {
582
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
583 5098 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
593
594 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ?";
595 5098 daigle
			pstmt = conn.prepareStatement(sql);
596
597
			// Bind the values to the query
598 6122 leinfelder
			pstmt.setString(1, id);
599 5098 daigle
600
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
601 6122 leinfelder
			sqlReport += " [" + id + "]";
602 5098 daigle
603
			logMetacat.info(sqlReport);
604
605
			pstmt.execute();
606
		} catch (SQLException sqle) {
607
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
608 6122 leinfelder
					+ "xml access permissions for id: " + id + ":" + sqle.getMessage());
609 5098 daigle
		} finally {
610 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
611 5098 daigle
		}
612
	}
613
614
	/**
615 5091 daigle
	 * Delete xml access.  This removes all access records from the database for a principal
616
	 * for a given document
617 5098 daigle
	 *
618 6122 leinfelder
	 * @param id
619 5091 daigle
	 *            document id
620
	 * @param principal
621
	 *            principal credentials
622
	 */
623 6122 leinfelder
	private void deleteXMLAccessForPrincipal(String id, String principalName) throws AccessException {
624
		if (id == null) {
625
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
626 5091 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
640
641 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
642 5091 daigle
			pstmt = conn.prepareStatement(sql);
643
644
			// Bind the values to the query
645 6122 leinfelder
			pstmt.setString(1, id);
646 5091 daigle
			pstmt.setString(2, principalName);
647
648
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
649 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "]";
650 5091 daigle
651
			logMetacat.info(sqlReport);
652
653
			pstmt.execute();
654
		} catch (SQLException sqle) {
655
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
656 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
657 5091 daigle
					principalName + ":" + sqle.getMessage());
658
		} finally {
659 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
660 5091 daigle
		}
661
	}
662
663
	/**
664 5115 daigle
	 * 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 6122 leinfelder
	 * @param id
668 5091 daigle
	 *            document id
669
	 * @param principal
670
	 *            principal credentials
671
	 */
672 6122 leinfelder
	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 5108 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
689
690 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND perm_order != ?";
691 5108 daigle
			pstmt = conn.prepareStatement(sql);
692
693
			// Bind the values to the query
694 6122 leinfelder
			pstmt.setString(1, id);
695 5108 daigle
			pstmt.setString(2, permOrder);
696
697
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
698 6122 leinfelder
			sqlReport += " [" + id + "," + permOrder + "]";
699 5108 daigle
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 6122 leinfelder
					"record for id: " + id + "with permOrder: " + permOrder + " due to permOrder conflict");
708 5108 daigle
			}
709
		} catch (SQLException sqle) {
710
			throw new AccessException("XMLAccessAccess.permOrderConflict - SQL error when checking"
711 6122 leinfelder
					+ "for perm order conflict on: " + id + ":" + sqle.getMessage());
712 5108 daigle
		} 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 5115 daigle
	 *
722 6122 leinfelder
	 * @param id
723 5108 daigle
	 *            document id
724
	 * @param principal
725
	 *            principal credentials
726
	 */
727 6122 leinfelder
	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 5091 daigle
					"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 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
754
755 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
756 5108 daigle
				"AND perm_type = ? AND perm_order = ?";
757 5091 daigle
			pstmt = conn.prepareStatement(sql);
758
759
			// Bind the values to the query
760 6122 leinfelder
			pstmt.setString(1, id);
761 5091 daigle
			pstmt.setString(2, principalName);
762
			pstmt.setString(3, permType);
763
			pstmt.setString(4, permOrder);
764
765
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
766 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "," + permType + "," + permOrder + "]";
767 5091 daigle
768
			logMetacat.info(sqlReport);
769
770
			pstmt.execute();
771
		} catch (SQLException sqle) {
772
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
773 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
774 5091 daigle
					principalName + ":" + sqle.getMessage());
775
		} finally {
776 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
777 5091 daigle
		}
778
779
	}
780 5098 daigle
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 5115 daigle
	 * @param xmlAccessList the access dao list
787 5098 daigle
	 */
788 5091 daigle
	private void cleanupXMLAccessForPrincipal(Vector<XMLAccessDAO> xmlAccessList) throws AccessException{
789
790 5098 daigle
		int numAllowRecords = 0;
791
		int numDenyRecords = 0;
792
		long allowPermissionMask = 0;
793
		long denyPermissionMask = 0;
794 6122 leinfelder
		String id = null;
795 5091 daigle
		String principalName = null;
796
		String permType = null;
797
		String permOrder = null;
798 6017 leinfelder
		// TODO: handle these fields
799
		String accessFileId = null;
800
		String subTreeId = null;
801 5091 daigle
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 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
807
			if (idAttribute.equals(GUID)) {
808
				daoId = xmlAccessDAO.getGuid();
809
			}
810
			if (id == null) {
811
				id = daoId;
812 5091 daigle
			} else {
813 6122 leinfelder
				if (!id.equals(daoId)) {
814 5091 daigle
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
815 6122 leinfelder
							" Conflicting ids " + daoId + " and " + id);
816 5091 daigle
				}
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 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
833 5091 daigle
							"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 6122 leinfelder
							" Conflicting permission types for document " + daoId +
842 5091 daigle
							"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 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
851 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
852
				}
853
			}
854 5098 daigle
			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 6017 leinfelder
			if (accessFileId == null) {
862
				accessFileId = xmlAccessDAO.getAccessFileId();
863
			}
864
			if (subTreeId == null) {
865
				subTreeId = xmlAccessDAO.getSubTreeId();
866
			}
867 5091 daigle
		}
868
869 5098 daigle
		// 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 6122 leinfelder
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.ALLOW, permOrder);
873
			insertXMLAccess(id, principalName, allowPermissionMask, AccessControlInterface.ALLOW, permOrder, accessFileId, subTreeId);
874 5098 daigle
		}
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 6122 leinfelder
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.DENY, permOrder);
879
			insertXMLAccess(id, principalName, denyPermissionMask, AccessControlInterface.DENY, permOrder, accessFileId, subTreeId);
880 5098 daigle
		}
881 5091 daigle
	}
882
883 5098 daigle
	/**
884 5115 daigle
	 * 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 5098 daigle
	 *
887
	 * @param xmlAccessList
888 5115 daigle
	 *            the access dao list
889 5098 daigle
	 */
890 5091 daigle
	private void validateDocXMLAccessList(Vector<XMLAccessDAO> xmlAccessList) throws PermOrderException {
891
		String permOrder = null;
892
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
893 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
894
			if (idAttribute.equals(GUID)) {
895
				daoId = xmlAccessDAO.getGuid();
896
			}
897 5091 daigle
			if (permOrder == null) {
898
				permOrder = xmlAccessDAO.getPermOrder();
899
			} else {
900
				if(!permOrder.equals(xmlAccessDAO.getPermOrder())) {
901
					throw new PermOrderException("XMLAccessAccess.validateXMLAccessList - " +
902 6122 leinfelder
						" Conflicting permission orders for document " + daoId +
903 5091 daigle
						". Database intervention required ");
904
				}
905
			}
906
		}
907
	}
908
909 5115 daigle
	/**
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 5091 daigle
	private void validatePrincipalXMLAccessList(Vector<XMLAccessDAO> xmlAccessList)
917
			throws PermOrderException {
918
919
		boolean allowFirst = false;
920
		boolean denyFirst = false;
921 6122 leinfelder
		String id = null;
922 5091 daigle
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 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
933
			if (idAttribute.equals(GUID)) {
934
				daoId = xmlAccessDAO.getGuid();
935 5091 daigle
			}
936 6122 leinfelder
			if (id == null) {
937
				id = daoId;
938
			}
939 5091 daigle
			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 6122 leinfelder
							daoId + ". Database intervention required ");
949 5091 daigle
				}
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 6122 leinfelder
							daoId + ". Database intervention required ");
960 5091 daigle
				}
961
			} else {
962
				throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
963
						" Invalid permission order: " + xmlAccessDAO.getPermOrder() + " for document " +
964 6122 leinfelder
						daoId + ". Database intervention required ");
965 5091 daigle
			}
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 6122 leinfelder
					" Conflicting permission orders for document " + id +
973 5091 daigle
					". 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 6122 leinfelder
		xmlAccessDAO.setDocId(resultSet.getString(idAttribute));
988 5091 daigle
		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
}