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