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
import edu.ucsb.nceas.metacat.database.DBConnection;
39
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
40
import edu.ucsb.nceas.metacat.shared.AccessException;
41
import edu.ucsb.nceas.metacat.shared.BaseAccess;
42 7475 leinfelder
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
43
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
44 5091 daigle
45
public class XMLAccessAccess extends BaseAccess {
46
47
	private Logger logMetacat = Logger.getLogger(XMLAccessAccess.class);
48 6744 leinfelder
49 5091 daigle
	// Constructor
50 5108 daigle
	public XMLAccessAccess() throws AccessException {}
51 5091 daigle
52 6122 leinfelder
53 5091 daigle
	/**
54
	 * Get all xml access for a document
55
	 *
56 6122 leinfelder
	 * @param id
57 5091 daigle
	 *            the id of the document
58
	 * @return an xml access DAO list
59
	 */
60 6744 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForDoc(String guid) throws AccessException {
61 5091 daigle
62
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
63
64 6744 leinfelder
		if (guid == null) {
65 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - doc id " +
66
					"must be specified when selecting xml_access record");
67
		}
68
69 5115 daigle
		// first get the xml access from the db and put it into a DAO list
70 5091 daigle
		PreparedStatement pstmt = null;
71 5108 daigle
		DBConnection conn = null;
72
		int serialNumber = -1;
73
		try {
74
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForDoc");
75
    		serialNumber = conn.getCheckOutSerialNumber();
76
77 6744 leinfelder
			String sql = "SELECT * FROM xml_access WHERE guid = ?";
78 5091 daigle
			pstmt = conn.prepareStatement(sql);
79
80 6744 leinfelder
			pstmt.setString(1, guid);
81 5091 daigle
82
			String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
83 6744 leinfelder
			sqlReport += " [" + guid + "]";
84 5091 daigle
85
			logMetacat.info(sqlReport);
86
87
			pstmt.execute();
88
89
			ResultSet resultSet = pstmt.getResultSet();
90
			while (resultSet.next()) {
91
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
92
				xmlAccessList.add(xmlAccessDAO);
93
			}
94 5115 daigle
95
			// make sure permission orders do not conflict in the database
96 5091 daigle
			validateDocXMLAccessList(xmlAccessList);
97
98
			return xmlAccessList;
99
100
		} catch (SQLException sqle) {
101
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - SQL error when getting access " +
102 6744 leinfelder
					" for id: " + guid  + " : "  + sqle.getMessage());
103 5091 daigle
		} catch (PermOrderException poe) {
104
			String errorStr = "XMLAccessAccess.getXMLAccessForDoc - Permission order error when getting " +
105 6744 leinfelder
				"access record for doc id: " + guid + " : "  + poe.getMessage();
106 5091 daigle
			logMetacat.error(errorStr);
107
			throw new AccessException(errorStr);
108
		} finally {
109 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
110 5091 daigle
		}
111
	}
112
113
	/**
114
	 * Get all xml access for a principal for a certain document
115
	 *
116 6122 leinfelder
	 * @param id
117 5091 daigle
	 *            the id of the document
118
	 * @param principalName
119
	 *            the credentials of the principal in the database
120
	 * @return an xml access DAO list
121
	 */
122 6744 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String guid, String principalName)
123 5091 daigle
			throws AccessException {
124
125
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
126
127 6744 leinfelder
		if (guid == null) {
128 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
129
					"must be specified when selecting xml_access record");
130
		}
131
		if (principalName == null) {
132
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
133
					"must be specified when selecting xml_access record");
134
		}
135
136 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
137 5091 daigle
		PreparedStatement pstmt = null;
138 5108 daigle
		DBConnection conn = null;
139
		int serialNumber = -1;
140 5091 daigle
		try {
141 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
142
    		serialNumber = conn.getCheckOutSerialNumber();
143
144 6744 leinfelder
			String sql = "SELECT * FROM xml_access WHERE guid = ? AND principal_name = ?";
145 5091 daigle
			pstmt = conn.prepareStatement(sql);
146
147 6744 leinfelder
			pstmt.setString(1, guid);
148 5091 daigle
			pstmt.setString(2, principalName);
149
150
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
151 6744 leinfelder
			sqlReport += " [" + guid + "," + principalName + "]";
152 5091 daigle
153
			logMetacat.info(sqlReport);
154
155
			pstmt.execute();
156
157
			ResultSet resultSet = pstmt.getResultSet();
158
			while (resultSet.next()) {
159
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
160
				xmlAccessList.add(xmlAccessDAO);
161
			}
162
163 5115 daigle
			// make sure permission orders do not conflict in the database
164 5091 daigle
			validatePrincipalXMLAccessList(xmlAccessList);
165
166
			return xmlAccessList;
167
168
		} catch (SQLException sqle) {
169
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " +
170 6744 leinfelder
					" for id: " + guid + ", principal: " + principalName  + " : "  + sqle.getMessage());
171 5091 daigle
		} catch (PermOrderException poe) {
172
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
173 6744 leinfelder
				"access record for id: " + guid + ", principal: " + principalName + " : "  + poe.getMessage();
174 5091 daigle
			logMetacat.error(errorStr);
175
			throw new AccessException(errorStr);
176
		} finally {
177 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
178 5091 daigle
		}
179
	}
180
181
	/**
182 5115 daigle
	 * Get all xml access for a principal/permType/permOrder for a certain document
183 5091 daigle
	 *
184 6744 leinfelder
	 * @param guid
185 5091 daigle
	 *            the id of the document
186
	 * @param principalName
187
	 *            the credentials of the principal in the database
188
	 * @return an xml access DAO list
189
	 */
190 6744 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String guid, String principalName, String permType, String permOrder)
191 5091 daigle
			throws AccessException {
192
193
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
194
195 6744 leinfelder
		if (guid == null) {
196 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
197
					"must be specified when selecting xml_access record");
198
		}
199
		if (principalName == null) {
200
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
201
					"must be specified when selecting xml_access record");
202
		}
203
		if (permType == null) {
204
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - permission type " +
205
					"must be specified when selecting xml_access record");
206
		}
207
		if (permOrder == null) {
208
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - permission order " +
209
					"must be specified when selecting xml_access record");
210
		}
211
212 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
213 5091 daigle
		PreparedStatement pstmt = null;
214 5108 daigle
		DBConnection conn = null;
215
		int serialNumber = -1;
216 5091 daigle
		try {
217 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
218
    		serialNumber = conn.getCheckOutSerialNumber();
219
220 6744 leinfelder
			String sql = "SELECT * FROM xml_access WHERE guid = ? AND principal_name = ? " +
221 5091 daigle
				"AND perm_type = ? AND perm_order = ?";
222
			pstmt = conn.prepareStatement(sql);
223
224 6744 leinfelder
			pstmt.setString(1, guid);
225 5091 daigle
			pstmt.setString(2, principalName);
226
			pstmt.setString(3, permType);
227
			pstmt.setString(4, permOrder);
228
229
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
230 6744 leinfelder
			sqlReport += " [" + guid + "," + principalName + "," +  permType + "," + permOrder + "]";
231 5091 daigle
232
			logMetacat.info(sqlReport);
233
234
			pstmt.execute();
235
236
			ResultSet resultSet = pstmt.getResultSet();
237
			while (resultSet.next()) {
238
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
239
				xmlAccessList.add(xmlAccessDAO);
240
			}
241
242
			validatePrincipalXMLAccessList(xmlAccessList);
243
244
			return xmlAccessList;
245
246
		} catch (SQLException sqle) {
247
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " +
248 6744 leinfelder
					" for id: " + guid + ", principal: " + principalName  + " : "  + sqle.getMessage());
249 5091 daigle
		} catch (PermOrderException poe) {
250
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
251 6744 leinfelder
				"access record for id: " + guid + ", principal: " + principalName + " : "  + poe.getMessage();
252 5091 daigle
			logMetacat.error(errorStr);
253
			throw new AccessException(errorStr);
254
		} finally {
255 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
256 5091 daigle
		}
257
	}
258
259
	/**
260 5098 daigle
	 * Add permissions for a given principal on a given document. If the
261
	 * principal already exists, bitwise OR the permission to the existing
262 5091 daigle
	 * permission and update.
263
	 *
264 6744 leinfelder
	 * @param guid
265 5091 daigle
	 *            document id
266
	 * @param principalName
267
	 *            principal credentials
268
	 * @param permission
269
	 *            permission bitmap
270
	 * @param permType
271
	 *            permission type
272
	 * @param permOrder
273
	 *            permission order
274
	 */
275 6744 leinfelder
	public void addXMLAccess(String guid, String principalName, Long permission, String permType,
276 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException, PermOrderException {
277 5108 daigle
278 6744 leinfelder
		permOrderConflict(guid, permOrder);
279 5108 daigle
280 5091 daigle
		Vector<XMLAccessDAO> xmlAccessList =
281 6744 leinfelder
			getXMLAccessForPrincipal(guid, principalName, permType, permOrder);
282 5091 daigle
283
		// if more than one record exists for this principal on this document with the same
284
		// access type / access order combination, call cleanup to combine common access and then
285
		// re-retrieve the access list.
286
		if (xmlAccessList.size() == 0) {
287 6744 leinfelder
			insertXMLAccess(guid, principalName, permission, permType, permOrder, accessFileId, subTreeId);
288 5091 daigle
			return;
289
		}
290
291
		if (xmlAccessList.size() > 1) {
292
			cleanupXMLAccessForPrincipal(xmlAccessList);
293 6744 leinfelder
			xmlAccessList = getXMLAccessForPrincipal(guid, principalName, permType, permOrder);
294 5091 daigle
		}
295
296
		if (xmlAccessList.size() == 0) {
297
			throw new AccessException("XMLAccessAccess.addXMLAccess - xml access list is empty when " +
298 6744 leinfelder
				"it shouldn't be for id: " + guid + ", prinicpal name: " + principalName + ", perm type " +
299 5091 daigle
				permType + ", perm order: " + permOrder);
300
		}
301
302
		XMLAccessDAO xmlAccessDAO = xmlAccessList.get(0);
303 5108 daigle
304 5091 daigle
		// if the permission on the xml access dao does not already contain the permission we are
305
		//trying to add, update the access record with the existing permission bitwis OR-ed with our
306
		// new permission
307
		if ((xmlAccessDAO.getPermission() & permission) != permission) {
308 6744 leinfelder
			updateXMLAccessPermission(guid, principalName, xmlAccessDAO.getPermission() | permission);
309 5091 daigle
		}
310
	}
311
312
	/**
313 5098 daigle
	 * Set permissions for a given document. This means first removing all access control for the
314
	 * document and then adding the given rules.
315
	 *
316 6122 leinfelder
	 * @param id
317 5091 daigle
	 *            document id
318 5098 daigle
	 * @param xmlAccessList
319
	 *            list of xml access dao objects that hold new access for the document
320
	 */
321 6744 leinfelder
	public void replaceAccess(String guid, List<XMLAccessDAO> xmlAccessList) throws AccessException {
322
		deleteXMLAccessForDoc(guid);
323 5098 daigle
324 6744 leinfelder
		insertAccess(guid, xmlAccessList);
325
	}
326
327
	/**
328
	 * Set permissions for a given document. This means first removing all access control for the
329
	 * document and then adding the given rules.
330
	 *
331
	 * @param id
332
	 *            document id
333
	 * @param xmlAccessList
334
	 *            list of xml access dao objects that hold new access for the document
335
	 */
336
	public void insertAccess(String guid, List<XMLAccessDAO> xmlAccessList) throws AccessException {
337
338 5098 daigle
		// 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 6744 leinfelder
			insertXMLAccess(guid, 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 6744 leinfelder
	private void insertXMLAccess(String guid, 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 6744 leinfelder
		if (guid == null) {
380 6122 leinfelder
			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 6744 leinfelder
				"(guid, principal_name, permission, perm_type, perm_order, accessfileid, subtreeid ) " +
409
				"VALUES (?,?,?,?,?,?,?)";
410 5091 daigle
			pstmt = conn.prepareStatement(sql);
411
412 6422 leinfelder
413 5091 daigle
			// Bind the values to the query
414 6744 leinfelder
			pstmt.setString(1, guid);
415
			pstmt.setString(2, principalName);
416
			pstmt.setLong(3, permission);
417
			pstmt.setString(4, permType);
418
			pstmt.setString(5, permOrder);
419
			pstmt.setString(6, accessFileId);
420
			pstmt.setString(7, subTreeId);
421 5091 daigle
422
			String sqlReport = "XMLAccessAccess.insertXMLAccess - SQL: " + sql;
423 6744 leinfelder
			sqlReport += " [" + guid + "," + principalName + "," +  permission + "," +  permType + "," + permOrder + "]";
424 5091 daigle
425
			logMetacat.info(sqlReport);
426
427
			pstmt.execute();
428
		} catch (SQLException sqle) {
429
			throw new AccessException("XMLAccessAccess.insertXMLAccess - SQL error when inserting"
430 6744 leinfelder
					+ "xml access permissions for id: " + guid + ", principal: " +
431 5091 daigle
					principalName + ":" + sqle.getMessage());
432
		} finally {
433 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
434 5091 daigle
		}
435
	}
436
437
	/**
438 5098 daigle
	 * Update existing xml access permissions in the db.  The permission value should be the combined
439
	 * value of pre-existing permissions plus new permissions.
440
	 *
441 6744 leinfelder
	 * @param guid
442 5091 daigle
	 *            document id
443
	 * @param principalName
444
	 *            principal credentials
445
	 * @param permission
446
	 *            permission bitmap
447
	 */
448 6744 leinfelder
	private void updateXMLAccessPermission(String guid, String principalName, Long permission)
449 5091 daigle
			throws AccessException {
450 6744 leinfelder
		if (guid == null) {
451 6122 leinfelder
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - id is required when " +
452 5091 daigle
					"updating XML access record");
453
		}
454
		if (principalName == null) {
455
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - principal is required when " +
456
					"updating XML access record");
457
		}
458
		if (permission == null) {
459
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - permission is required when " +
460
					"updating XML access record");
461
		}
462
463
	    PreparedStatement pstmt = null;
464
		DBConnection conn = null;
465
		int serialNumber = -1;
466
		try {
467
			// check out DBConnection
468
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.updateXMLAccessPermission");
469
			serialNumber = conn.getCheckOutSerialNumber();
470 5120 daigle
471 5091 daigle
			String sql = "UPDATE xml_access SET permission = ?" +
472 6744 leinfelder
				"WHERE guid = ? AND principal_name = ?";
473 5091 daigle
			pstmt = conn.prepareStatement(sql);
474
475
			// Bind the values to the query
476
			pstmt.setLong(1, permission);
477 6744 leinfelder
			pstmt.setString(2, guid);
478 5091 daigle
			pstmt.setString(3, principalName);
479
480
			String sqlReport = "XMLAccessAccess.updateXMLAccessPermission - SQL: " + sql;
481 6744 leinfelder
			sqlReport += " [" + permission + "," + guid + "," + principalName + "]";
482 5091 daigle
483
			logMetacat.info(sqlReport);
484
485
			pstmt.execute();
486
		} catch (SQLException sqle) {
487
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - SQL error when updating"
488 6744 leinfelder
					+ "xml access permissions for id: " + guid + ", principal: " +
489 5091 daigle
					principalName + ":" + sqle.getMessage());
490
		} finally {
491 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
492 5091 daigle
		}
493
494
	}
495
496
	/**
497 5098 daigle
	 * Remove xml access.  This modifies the access in the database for a principal
498 5091 daigle
	 * for a given document.  If the provided permission is exactly the same as what
499 5098 daigle
	 * the principal has, the record is deleted from the database.
500
	 *
501 6744 leinfelder
	 * @param guid
502 5091 daigle
	 *            document id
503
	 * @param principalName
504
	 *            principal credentials
505
	 */
506 6744 leinfelder
	public void removeXMLAccessForPrincipal(String guid, String principalName, Long permission) throws AccessException {
507
		if (guid == null) {
508 6122 leinfelder
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - id is required when " +
509 5091 daigle
					"removing XML access");
510
		}
511
		if (principalName == null) {
512
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - principal is required when " +
513
					"deleting XML access");
514
		}
515
		if (permission == null) {
516
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - permission is required when " +
517
					"updating XML access");
518
		}
519
520 6744 leinfelder
		Vector<XMLAccessDAO> xmlAccessList = getXMLAccessForPrincipal(guid, principalName);
521 5091 daigle
		if (xmlAccessList.size() == 0) {
522
			logMetacat.warn("XMLAccessAccess.removeXMLAccessForPrincipal - attempting to remove access when no " +
523 6744 leinfelder
				"access record exists for id: " + guid + ", principal: " + principalName);
524 5091 daigle
		} else {
525
			long permissionMask = 0;
526
			for (XMLAccessDAO xmlAccessDAO : xmlAccessList) {
527
				permissionMask |= xmlAccessDAO.getPermission();
528
			}
529
			permissionMask |= permission;
530
531
			// in this case, the only existing permissions are the ones we want to remove, so
532
			// delete the record(s) for this principal on this document
533
			if ((permissionMask & permission) == permission) {
534 6744 leinfelder
				deleteXMLAccessForPrincipal(guid, principalName);
535 5091 daigle
			}
536
537
			if (xmlAccessList.size() > 1) {
538
539
			} else {
540 6744 leinfelder
				updateXMLAccessPermission(guid, principalName, permission);
541 5091 daigle
			}
542
		}
543
544
	}
545
546
	/**
547 5098 daigle
	 * Delete xml access.  This removes all access records from the database for a given document
548
	 *
549 6122 leinfelder
	 * @param id
550 5098 daigle
	 *            document id
551
	 */
552 6744 leinfelder
	public void deleteXMLAccessForDoc(String guid) throws AccessException {
553
		if (guid == null) {
554 6122 leinfelder
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
555 5098 daigle
					"deleting XML access record");
556
		}
557
558
	    PreparedStatement pstmt = null;
559
		DBConnection conn = null;
560
		int serialNumber = -1;
561
		try {
562 6536 leinfelder
563 5098 daigle
			// check out DBConnection
564
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForDoc");
565 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
566
567 6744 leinfelder
			String sql = "DELETE FROM xml_access WHERE guid = ?";
568 5098 daigle
			pstmt = conn.prepareStatement(sql);
569
570
			// Bind the values to the query
571 6744 leinfelder
			pstmt.setString(1, guid);
572 5098 daigle
573
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
574 6744 leinfelder
			sqlReport += " [" + guid + "]";
575 5098 daigle
576
			logMetacat.info(sqlReport);
577
578
			pstmt.execute();
579
		} catch (SQLException sqle) {
580
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
581 6744 leinfelder
					+ "xml access permissions for id: " + guid + ":" + sqle.getMessage());
582 5098 daigle
		} finally {
583 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
584 5098 daigle
		}
585
	}
586
587
	/**
588 5091 daigle
	 * Delete xml access.  This removes all access records from the database for a principal
589
	 * for a given document
590 5098 daigle
	 *
591 6744 leinfelder
	 * @param guid
592 5091 daigle
	 *            document id
593
	 * @param principal
594
	 *            principal credentials
595
	 */
596 6744 leinfelder
	private void deleteXMLAccessForPrincipal(String guid, String principalName) throws AccessException {
597
		if (guid == null) {
598 6122 leinfelder
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
599 5091 daigle
					"deleting XML access record");
600
		}
601
		if (principalName == null) {
602
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " +
603
					"deleting XML access record");
604
		}
605
606
	    PreparedStatement pstmt = null;
607
		DBConnection conn = null;
608
		int serialNumber = -1;
609
		try {
610
			// check out DBConnection
611
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
612 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
613
614 6744 leinfelder
			String sql = "DELETE FROM xml_access WHERE guid = ? AND principal_name = ?";
615 5091 daigle
			pstmt = conn.prepareStatement(sql);
616
617
			// Bind the values to the query
618 6744 leinfelder
			pstmt.setString(1, guid);
619 5091 daigle
			pstmt.setString(2, principalName);
620
621
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
622 6744 leinfelder
			sqlReport += " [" + guid + "," + principalName + "]";
623 5091 daigle
624
			logMetacat.info(sqlReport);
625
626
			pstmt.execute();
627
		} catch (SQLException sqle) {
628
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
629 6744 leinfelder
					+ "xml access permissions for id: " + guid + ", principal: " +
630 5091 daigle
					principalName + ":" + sqle.getMessage());
631
		} finally {
632 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
633 5091 daigle
		}
634
	}
635
636
	/**
637 6744 leinfelder
	 * Delete xml access.  This removes all access records from the database for a principal
638
	 * for a given document
639
	 *
640
	 * @param guid
641
	 *            document id
642
	 * @param principal
643
	 *            principal credentials
644
	 */
645
	public void deleteXMLAccessForDoc(String guid, String permType) throws AccessException {
646
		if (guid == null) {
647
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - id is required when " +
648
					"deleting XML access record");
649
		}
650
		if (permType == null) {
651
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - permType is required when " +
652
					"deleting XML access record");
653
		}
654
655
	    PreparedStatement pstmt = null;
656
		DBConnection conn = null;
657
		int serialNumber = -1;
658
		try {
659
			// check out DBConnection
660
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForDoc");
661
    		serialNumber = conn.getCheckOutSerialNumber();
662
663
			String sql = "DELETE FROM xml_access WHERE guid = ? AND perm_type = ?";
664
			pstmt = conn.prepareStatement(sql);
665
666
			// Bind the values to the query
667
			pstmt.setString(1, guid);
668
			pstmt.setString(2, permType);
669
670
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
671
			sqlReport += " [" + guid + "," + permType + "]";
672
673
			logMetacat.info(sqlReport);
674
675
			pstmt.execute();
676
		} catch (SQLException sqle) {
677
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
678
					+ "xml access permissions for id: " + guid + ", permType: " +
679
					permType + ":" + sqle.getMessage());
680
		} finally {
681
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
682
		}
683
	}
684
685
	/**
686 5115 daigle
	 * Checks to see if there is a permission order conflict for a given document.  Each
687
	 * document is only allowed to have a single permission order
688
	 *
689 6744 leinfelder
	 * @param guid
690 5091 daigle
	 *            document id
691
	 * @param principal
692
	 *            principal credentials
693
	 */
694 6744 leinfelder
	private void permOrderConflict(String guid, String permOrder) throws AccessException, PermOrderException {
695
		if (guid == null) {
696 6122 leinfelder
			throw new AccessException("XMLAccessAccess.permOrderConflict - id is required when " +
697 5108 daigle
					"determining perm order conflict");
698
		}
699
		if (permOrder == null) {
700
			throw new AccessException("XMLAccessAccess.permOrderConflict - perm order is required when " +
701
					"determining perm order conflict");
702
		}
703
704
	    PreparedStatement pstmt = null;
705
		DBConnection conn = null;
706
		int serialNumber = -1;
707
		try {
708
			// check out DBConnection
709
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.permOrderConflict");
710 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
711
712 6744 leinfelder
			String sql = "SELECT * FROM xml_access WHERE guid = ? AND perm_order != ?";
713 5108 daigle
			pstmt = conn.prepareStatement(sql);
714
715
			// Bind the values to the query
716 6744 leinfelder
			pstmt.setString(1, guid);
717 5108 daigle
			pstmt.setString(2, permOrder);
718
719
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
720 6744 leinfelder
			sqlReport += " [" + guid + "," + permOrder + "]";
721 5108 daigle
722
			logMetacat.info(sqlReport);
723
724
			pstmt.execute();
725
726
			ResultSet resultSet = pstmt.getResultSet();
727
			if (resultSet.next()) {
728
				throw new PermOrderException("XMLAccessAccess.addXMLAccess - cannot add permission " +
729 6744 leinfelder
					"record for id: " + guid + "with permOrder: " + permOrder + " due to permOrder conflict");
730 5108 daigle
			}
731
		} catch (SQLException sqle) {
732
			throw new AccessException("XMLAccessAccess.permOrderConflict - SQL error when checking"
733 6744 leinfelder
					+ "for perm order conflict on: " + guid + ":" + sqle.getMessage());
734 5108 daigle
		} finally {
735
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
736
		}
737
738
	}
739
740
	/**
741
	 * Delete xml access.  This removes all access records from the database for a principal
742
	 * for a given document, perm type and perm order
743 5115 daigle
	 *
744 6744 leinfelder
	 * @param guid
745 5108 daigle
	 *            document id
746
	 * @param principal
747
	 *            principal credentials
748
	 */
749 6744 leinfelder
	private void deleteXMLAccessForPrincipal(String guid, String principalName, String permType, String permOrder) throws AccessException {
750
		if (guid == null) {
751 6122 leinfelder
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
752 5091 daigle
					"deleting XML access record");
753
		}
754
		if (principalName == null) {
755
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " +
756
					"deleting XML access record");
757
		}
758
		if (permType == null) {
759
			throw new AccessException(
760
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm type is required when "
761
							+ "deleting XML access record");
762
		}
763
		if (permOrder == null) {
764
			throw new AccessException(
765
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm order is required when "
766
							+ "deleting XML access record");
767
		}
768
769
	    PreparedStatement pstmt = null;
770
		DBConnection conn = null;
771
		int serialNumber = -1;
772
		try {
773
			// check out DBConnection
774
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
775 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
776
777 6744 leinfelder
			String sql = "DELETE FROM xml_access WHERE guid = ? AND principal_name = ? " +
778 5108 daigle
				"AND perm_type = ? AND perm_order = ?";
779 5091 daigle
			pstmt = conn.prepareStatement(sql);
780
781
			// Bind the values to the query
782 6744 leinfelder
			pstmt.setString(1, guid);
783 5091 daigle
			pstmt.setString(2, principalName);
784
			pstmt.setString(3, permType);
785
			pstmt.setString(4, permOrder);
786
787
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
788 6744 leinfelder
			sqlReport += " [" + guid + "," + principalName + "," + permType + "," + permOrder + "]";
789 5091 daigle
790
			logMetacat.info(sqlReport);
791
792
			pstmt.execute();
793
		} catch (SQLException sqle) {
794
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
795 6744 leinfelder
					+ "xml access permissions for id: " + guid + ", principal: " +
796 5091 daigle
					principalName + ":" + sqle.getMessage());
797
		} finally {
798 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
799 5091 daigle
		}
800
801
	}
802 5098 daigle
803
	/**
804
	 * Make sure that only one record exists per principal/permType/document. If
805
	 * more than one record exists, delete the existing records, consolidate the
806
	 * permissions insert the new record.
807
	 *
808 5115 daigle
	 * @param xmlAccessList the access dao list
809 5098 daigle
	 */
810 5091 daigle
	private void cleanupXMLAccessForPrincipal(Vector<XMLAccessDAO> xmlAccessList) throws AccessException{
811
812 5098 daigle
		int numAllowRecords = 0;
813
		int numDenyRecords = 0;
814
		long allowPermissionMask = 0;
815
		long denyPermissionMask = 0;
816 6744 leinfelder
		String guid = null;
817 5091 daigle
		String principalName = null;
818
		String permType = null;
819
		String permOrder = null;
820 6017 leinfelder
		// TODO: handle these fields
821
		String accessFileId = null;
822
		String subTreeId = null;
823 5091 daigle
824
825
		// iterate through the list of access dao objects and bttwise or the permissions.  Most
826
		// of this is just doing some error checking to make sure each record is valid.
827
		for (XMLAccessDAO xmlAccessDAO : xmlAccessList) {
828 6744 leinfelder
			String daoId = xmlAccessDAO.getGuid();
829
			if (guid == null) {
830
				guid = daoId;
831 5091 daigle
			} else {
832 6744 leinfelder
				if (!guid.equals(daoId)) {
833 5091 daigle
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
834 6744 leinfelder
							" Conflicting ids " + daoId + " and " + guid);
835 5091 daigle
				}
836
			}
837
			if (principalName == null) {
838
				principalName = xmlAccessDAO.getPrincipalName();
839
			} else {
840
				if (!principalName.equals(xmlAccessDAO.getPrincipalName())) {
841
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
842
							" Conflicting prinicpal names " + xmlAccessDAO.getPrincipalName() +
843
							" and principalName " + principalName);
844
				}
845
			}
846
			if (permType == null) {
847
				permType = xmlAccessDAO.getPermType();
848
			} else {
849
				if (!permType.equals(xmlAccessDAO.getPermType())) {
850
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
851 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
852 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
853
				}
854
			}
855
			if (permOrder == null) {
856
				permOrder = xmlAccessDAO.getPermOrder();
857
			} else {
858
				if (!permOrder.equals(xmlAccessDAO.getPermOrder())) {
859
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
860 6122 leinfelder
							" Conflicting permission types for document " + daoId +
861 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
862
				}
863
			}
864
			if (permType == null) {
865
				permType = xmlAccessDAO.getPermType();
866
			} else {
867
				if (!permType.equals(xmlAccessDAO.getPermType())) {
868
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
869 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
870 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
871
				}
872
			}
873 5098 daigle
			if (permType.equals(AccessControlInterface.ALLOW)) {
874
				numAllowRecords++;
875
				allowPermissionMask |= xmlAccessDAO.getPermission();
876
			} else if (permType.equals(AccessControlInterface.DENY)) {
877
				numDenyRecords++;
878
				denyPermissionMask |= xmlAccessDAO.getPermission();
879
			}
880 6017 leinfelder
			if (accessFileId == null) {
881
				accessFileId = xmlAccessDAO.getAccessFileId();
882
			}
883
			if (subTreeId == null) {
884
				subTreeId = xmlAccessDAO.getSubTreeId();
885
			}
886 5091 daigle
		}
887
888 5098 daigle
		// if there was more than one allow record, remove all allow records for this user on this doc
889
		// with this perm type and perm order then insert a single record
890
		if (numAllowRecords > 1) {
891 6744 leinfelder
			deleteXMLAccessForPrincipal(guid, principalName, AccessControlInterface.ALLOW, permOrder);
892
			insertXMLAccess(guid, principalName, allowPermissionMask, AccessControlInterface.ALLOW, permOrder, accessFileId, subTreeId);
893 5098 daigle
		}
894
		// if there was more than one deny record, remove all deny records for this user on this doc
895
		// with this perm type and perm order then insert a single record
896
		if (numDenyRecords > 1) {
897 6744 leinfelder
			deleteXMLAccessForPrincipal(guid, principalName, AccessControlInterface.DENY, permOrder);
898
			insertXMLAccess(guid, principalName, denyPermissionMask, AccessControlInterface.DENY, permOrder, accessFileId, subTreeId);
899 5098 daigle
		}
900 5091 daigle
	}
901
902 5098 daigle
	/**
903 5115 daigle
	 * Make sure for a given list of access DAOs that only one perm order
904
	 * exists. It is assumed that all the DAOs are for the same doc
905 5098 daigle
	 *
906
	 * @param xmlAccessList
907 5115 daigle
	 *            the access dao list
908 5098 daigle
	 */
909 5091 daigle
	private void validateDocXMLAccessList(Vector<XMLAccessDAO> xmlAccessList) throws PermOrderException {
910
		String permOrder = null;
911
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
912 6744 leinfelder
			String daoId = xmlAccessDAO.getGuid();
913 5091 daigle
			if (permOrder == null) {
914
				permOrder = xmlAccessDAO.getPermOrder();
915
			} else {
916
				if(!permOrder.equals(xmlAccessDAO.getPermOrder())) {
917
					throw new PermOrderException("XMLAccessAccess.validateXMLAccessList - " +
918 6122 leinfelder
						" Conflicting permission orders for document " + daoId +
919 5091 daigle
						". Database intervention required ");
920
				}
921
			}
922
		}
923
	}
924
925 5115 daigle
	/**
926
	 * Check that only one permOrder exists for each principal.
927
	 * TODO add check that one of each permType exists as well
928
	 *
929
	 * @param xmlAccessList
930
	 *            the access dao list
931
	 */
932 5091 daigle
	private void validatePrincipalXMLAccessList(Vector<XMLAccessDAO> xmlAccessList)
933
			throws PermOrderException {
934
935
		boolean allowFirst = false;
936
		boolean denyFirst = false;
937 6744 leinfelder
		String guid = null;
938 5091 daigle
939
		// These vectors will hold all combinations of access DAOs with different permission
940
		// orders and permission types.
941
		Vector<XMLAccessDAO> allowFirstAllows = new Vector<XMLAccessDAO>();
942
		Vector<XMLAccessDAO> allowFirstDenys = new Vector<XMLAccessDAO>();
943
		Vector<XMLAccessDAO> denyFirstAllows = new Vector<XMLAccessDAO>();
944
		Vector<XMLAccessDAO> denyFirstDenys = new Vector<XMLAccessDAO>();
945
946
		// sort the access dao records into the appropriate vector
947
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
948 6744 leinfelder
			String daoId = xmlAccessDAO.getGuid();
949
			if (guid == null) {
950
				guid = daoId;
951 5091 daigle
			}
952
			if (xmlAccessDAO.getPermOrder().equals(AccessControlInterface.ALLOWFIRST)) {
953
				allowFirst = true;
954
				if (xmlAccessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
955
					allowFirstAllows.add(xmlAccessDAO);
956
				} else if (xmlAccessDAO.getPermType().equals(AccessControlInterface.DENY)) {
957
					allowFirstDenys.add(xmlAccessDAO);
958
				} else {
959
					throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
960
							" Invalid permission type: " + xmlAccessDAO.getPermType() + " for document " +
961 6122 leinfelder
							daoId + ". Database intervention required ");
962 5091 daigle
				}
963
			} else if (xmlAccessDAO.getPermOrder().equals(AccessControlInterface.DENYFIRST)) {
964
				denyFirst = true;
965
				if (xmlAccessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
966
					denyFirstAllows.add(xmlAccessDAO);
967
				} else if (xmlAccessDAO.getPermType().equals(AccessControlInterface.DENY)) {
968
					denyFirstDenys.add(xmlAccessDAO);
969
				} else {
970
					throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
971
							" Invalid permission type: " + xmlAccessDAO.getPermType() + " for document " +
972 6122 leinfelder
							daoId + ". Database intervention required ");
973 5091 daigle
				}
974
			} else {
975
				throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
976
						" Invalid permission order: " + xmlAccessDAO.getPermOrder() + " for document " +
977 6122 leinfelder
						daoId + ". Database intervention required ");
978 5091 daigle
			}
979
		}
980
981
		// for a given user, there cannot be allowfirst and denyfirst records on the same
982
		// document
983
		if(allowFirst && denyFirst) {
984
			throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
985 6744 leinfelder
					" Conflicting permission orders for document " + guid +
986 5091 daigle
					". Database intervention required ");
987
		}
988
	}
989
990
	/**
991
	 * Populate a job data object with the current row in a resultset
992
	 *
993
	 * @param resultSet
994
	 *            the result set which is already pointing to the desired row.
995
	 * @return a scheduled job data object
996
	 */
997
	protected XMLAccessDAO populateDAO(ResultSet resultSet) throws SQLException {
998
999
		XMLAccessDAO xmlAccessDAO = new XMLAccessDAO();
1000 6744 leinfelder
		xmlAccessDAO.setGuid(resultSet.getString("guid"));
1001 5091 daigle
		xmlAccessDAO.setAccessFileId(resultSet.getString("accessfileid"));
1002
		xmlAccessDAO.setPrincipalName(resultSet.getString("principal_name"));
1003
		xmlAccessDAO.setPermission(resultSet.getLong("permission"));
1004
		xmlAccessDAO.setPermType(resultSet.getString("perm_type"));
1005
		xmlAccessDAO.setPermOrder(resultSet.getString("perm_order"));
1006
		xmlAccessDAO.setBeginTime(resultSet.getDate("begin_time"));
1007
		xmlAccessDAO.setEndTime(resultSet.getDate("end_time"));
1008
		xmlAccessDAO.setTicketCount(resultSet.getLong("ticket_count"));
1009
		xmlAccessDAO.setSubTreeId(resultSet.getString("subtreeid"));
1010
		xmlAccessDAO.setStartNodeId(resultSet.getString("startnodeid"));
1011
		xmlAccessDAO.setEndNodeId(resultSet.getString("endnodeid"));
1012
1013
		return xmlAccessDAO;
1014
	}
1015
1016
}