1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.acl.basic.jdbc;
17
18 import org.acegisecurity.acl.basic.AclObjectIdentity;
19 import org.acegisecurity.acl.basic.BasicAclEntry;
20 import org.acegisecurity.acl.basic.BasicAclExtendedDao;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 import org.springframework.context.ApplicationContextException;
26
27 import org.springframework.dao.DataAccessException;
28 import org.springframework.dao.DataIntegrityViolationException;
29 import org.springframework.dao.DataRetrievalFailureException;
30
31 import org.springframework.jdbc.core.SqlParameter;
32 import org.springframework.jdbc.object.MappingSqlQuery;
33 import org.springframework.jdbc.object.SqlUpdate;
34
35 import java.sql.ResultSet;
36 import java.sql.SQLException;
37 import java.sql.Types;
38
39 import java.util.Iterator;
40 import java.util.List;
41
42 import javax.sql.DataSource;
43
44
45 /***
46 * <p>
47 * Extension of the base {@link JdbcDaoImpl}, which implements {@link
48 * BasicAclExtendedDao}.
49 * </p>
50 *
51 * <p>
52 * A default database structure is assumed. This may be overridden by setting
53 * the default query strings to use.
54 * </p>
55 *
56 * <p>
57 * This implementation works with <code>String</code> based recipients and
58 * {@link org.acegisecurity.acl.basic.NamedEntityObjectIdentity} only. The
59 * latter can be changed by overriding {@link
60 * #convertAclObjectIdentityToString(AclObjectIdentity)}.
61 * </p>
62 *
63 * @author Ben Alex
64 * @version $Id: JdbcExtendedDaoImpl.java,v 1.7 2005/11/17 00:56:10 benalex Exp $
65 */
66 public class JdbcExtendedDaoImpl extends JdbcDaoImpl
67 implements BasicAclExtendedDao {
68
69
70 private static final Log logger = LogFactory.getLog(JdbcExtendedDaoImpl.class);
71 public static final String DEF_ACL_OBJECT_IDENTITY_DELETE_STATEMENT = "DELETE FROM acl_object_identity WHERE id = ?";
72 public static final String DEF_ACL_OBJECT_IDENTITY_INSERT_STATEMENT = "INSERT INTO acl_object_identity (object_identity, parent_object, acl_class) VALUES (?, ?, ?)";
73 public static final String DEF_ACL_PERMISSION_DELETE_STATEMENT = "DELETE FROM acl_permission WHERE acl_object_identity = ? AND recipient = ?";
74 public static final String DEF_ACL_PERMISSION_INSERT_STATEMENT = "INSERT INTO acl_permission (acl_object_identity, recipient, mask) VALUES (?, ?, ?)";
75 public static final String DEF_ACL_PERMISSION_UPDATE_STATEMENT = "UPDATE acl_permission SET mask = ? WHERE id = ?";
76 public static final String DEF_LOOKUP_PERMISSION_ID_QUERY = "SELECT id FROM acl_permission WHERE acl_object_identity = ? AND recipient = ?";
77
78
79
80 private AclObjectIdentityDelete aclObjectIdentityDelete;
81 private AclObjectIdentityInsert aclObjectIdentityInsert;
82 private AclPermissionDelete aclPermissionDelete;
83 private AclPermissionInsert aclPermissionInsert;
84 private AclPermissionUpdate aclPermissionUpdate;
85 private MappingSqlQuery lookupPermissionIdMapping;
86 private String aclObjectIdentityDeleteStatement;
87 private String aclObjectIdentityInsertStatement;
88 private String aclPermissionDeleteStatement;
89 private String aclPermissionInsertStatement;
90 private String aclPermissionUpdateStatement;
91 private String lookupPermissionIdQuery;
92
93
94
95 public JdbcExtendedDaoImpl() {
96 aclObjectIdentityDeleteStatement = DEF_ACL_OBJECT_IDENTITY_DELETE_STATEMENT;
97 aclObjectIdentityInsertStatement = DEF_ACL_OBJECT_IDENTITY_INSERT_STATEMENT;
98 aclPermissionDeleteStatement = DEF_ACL_PERMISSION_DELETE_STATEMENT;
99 aclPermissionInsertStatement = DEF_ACL_PERMISSION_INSERT_STATEMENT;
100 aclPermissionUpdateStatement = DEF_ACL_PERMISSION_UPDATE_STATEMENT;
101 lookupPermissionIdQuery = DEF_LOOKUP_PERMISSION_ID_QUERY;
102 }
103
104
105
106 public void setAclObjectIdentityDelete(
107 AclObjectIdentityDelete aclObjectIdentityDelete) {
108 this.aclObjectIdentityDelete = aclObjectIdentityDelete;
109 }
110
111 public AclObjectIdentityDelete getAclObjectIdentityDelete() {
112 return aclObjectIdentityDelete;
113 }
114
115 public void setAclObjectIdentityDeleteStatement(
116 String aclObjectIdentityDeleteStatement) {
117 this.aclObjectIdentityDeleteStatement = aclObjectIdentityDeleteStatement;
118 }
119
120 public String getAclObjectIdentityDeleteStatement() {
121 return aclObjectIdentityDeleteStatement;
122 }
123
124 public void setAclObjectIdentityInsert(
125 AclObjectIdentityInsert aclObjectIdentityInsert) {
126 this.aclObjectIdentityInsert = aclObjectIdentityInsert;
127 }
128
129 public AclObjectIdentityInsert getAclObjectIdentityInsert() {
130 return aclObjectIdentityInsert;
131 }
132
133 public void setAclObjectIdentityInsertStatement(
134 String aclObjectIdentityInsertStatement) {
135 this.aclObjectIdentityInsertStatement = aclObjectIdentityInsertStatement;
136 }
137
138 public String getAclObjectIdentityInsertStatement() {
139 return aclObjectIdentityInsertStatement;
140 }
141
142 public void setAclPermissionDelete(AclPermissionDelete aclPermissionDelete) {
143 this.aclPermissionDelete = aclPermissionDelete;
144 }
145
146 public AclPermissionDelete getAclPermissionDelete() {
147 return aclPermissionDelete;
148 }
149
150 public void setAclPermissionDeleteStatement(
151 String aclPermissionDeleteStatement) {
152 this.aclPermissionDeleteStatement = aclPermissionDeleteStatement;
153 }
154
155 public String getAclPermissionDeleteStatement() {
156 return aclPermissionDeleteStatement;
157 }
158
159 public void setAclPermissionInsert(AclPermissionInsert aclPermissionInsert) {
160 this.aclPermissionInsert = aclPermissionInsert;
161 }
162
163 public AclPermissionInsert getAclPermissionInsert() {
164 return aclPermissionInsert;
165 }
166
167 public void setAclPermissionInsertStatement(
168 String aclPermissionInsertStatement) {
169 this.aclPermissionInsertStatement = aclPermissionInsertStatement;
170 }
171
172 public String getAclPermissionInsertStatement() {
173 return aclPermissionInsertStatement;
174 }
175
176 public void setAclPermissionUpdate(AclPermissionUpdate aclPermissionUpdate) {
177 this.aclPermissionUpdate = aclPermissionUpdate;
178 }
179
180 public AclPermissionUpdate getAclPermissionUpdate() {
181 return aclPermissionUpdate;
182 }
183
184 public void setAclPermissionUpdateStatement(
185 String aclPermissionUpdateStatement) {
186 this.aclPermissionUpdateStatement = aclPermissionUpdateStatement;
187 }
188
189 public String getAclPermissionUpdateStatement() {
190 return aclPermissionUpdateStatement;
191 }
192
193 public void setLookupPermissionIdMapping(
194 MappingSqlQuery lookupPermissionIdMapping) {
195 this.lookupPermissionIdMapping = lookupPermissionIdMapping;
196 }
197
198 public MappingSqlQuery getLookupPermissionIdMapping() {
199 return lookupPermissionIdMapping;
200 }
201
202 public void setLookupPermissionIdQuery(String lookupPermissionIdQuery) {
203 this.lookupPermissionIdQuery = lookupPermissionIdQuery;
204 }
205
206 public String getLookupPermissionIdQuery() {
207 return lookupPermissionIdQuery;
208 }
209
210 public void changeMask(AclObjectIdentity aclObjectIdentity,
211 Object recipient, Integer newMask) throws DataAccessException {
212
213 AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
214
215
216 long permissionId = lookupPermissionId(aclDetailsHolder.getForeignKeyId(),
217 recipient.toString());
218
219 if (permissionId == -1) {
220 throw new DataRetrievalFailureException(
221 "Could not locate existing acl_permission for aclObjectIdentity: "
222 + aclObjectIdentity + ", recipient: " + recipient.toString());
223 }
224
225
226 aclPermissionUpdate.update(new Long(permissionId), newMask);
227 }
228
229 public void create(BasicAclEntry basicAclEntry) throws DataAccessException {
230
231 createAclObjectIdentityIfRequired(basicAclEntry);
232
233
234
235 if (basicAclEntry.getRecipient() == null) {
236 return;
237 }
238
239
240 AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(basicAclEntry
241 .getAclObjectIdentity());
242
243
244 if (lookupPermissionId(aclDetailsHolder.getForeignKeyId(),
245 basicAclEntry.getRecipient()) != -1) {
246 throw new DataIntegrityViolationException(
247 "This recipient already exists for this aclObjectIdentity");
248 }
249
250
251 aclPermissionInsert.insert(new Long(aclDetailsHolder.getForeignKeyId()),
252 basicAclEntry.getRecipient().toString(),
253 new Integer(basicAclEntry.getMask()));
254 }
255
256 public void delete(AclObjectIdentity aclObjectIdentity)
257 throws DataAccessException {
258
259 AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
260
261
262 Iterator acls = aclsByObjectIdentity.execute(aclDetailsHolder
263 .getForeignKeyId()).iterator();
264
265
266 while (acls.hasNext()) {
267 AclDetailsHolder permission = (AclDetailsHolder) acls.next();
268 delete(aclObjectIdentity, permission.getRecipient());
269 }
270
271
272 aclObjectIdentityDelete.delete(new Long(
273 aclDetailsHolder.getForeignKeyId()));
274 }
275
276 public void delete(AclObjectIdentity aclObjectIdentity, Object recipient)
277 throws DataAccessException {
278
279 AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
280
281
282 aclPermissionDelete.delete(new Long(aclDetailsHolder.getForeignKeyId()),
283 recipient.toString());
284 }
285
286 protected void initDao() throws ApplicationContextException {
287 super.initDao();
288 lookupPermissionIdMapping = new LookupPermissionIdMapping(getDataSource());
289 aclPermissionInsert = new AclPermissionInsert(getDataSource());
290 aclObjectIdentityInsert = new AclObjectIdentityInsert(getDataSource());
291 aclPermissionDelete = new AclPermissionDelete(getDataSource());
292 aclObjectIdentityDelete = new AclObjectIdentityDelete(getDataSource());
293 aclPermissionUpdate = new AclPermissionUpdate(getDataSource());
294 }
295
296 /***
297 * Convenience method that creates an acl_object_identity record if
298 * required.
299 *
300 * @param basicAclEntry containing the <code>AclObjectIdentity</code> to
301 * create
302 *
303 * @throws DataAccessException
304 */
305 private void createAclObjectIdentityIfRequired(BasicAclEntry basicAclEntry)
306 throws DataAccessException {
307 String aclObjectIdentityString = convertAclObjectIdentityToString(basicAclEntry
308 .getAclObjectIdentity());
309
310
311 List objects = objectProperties.execute(aclObjectIdentityString);
312
313 if (objects.size() == 0) {
314 if (basicAclEntry.getAclObjectParentIdentity() != null) {
315 AclDetailsHolder parentDetails = lookupAclDetailsHolder(basicAclEntry
316 .getAclObjectParentIdentity());
317
318
319 aclObjectIdentityInsert.insert(aclObjectIdentityString,
320 new Long(parentDetails.getForeignKeyId()),
321 basicAclEntry.getClass().getName());
322 } else {
323
324 aclObjectIdentityInsert.insert(aclObjectIdentityString, null,
325 basicAclEntry.getClass().getName());
326 }
327 }
328 }
329
330 /***
331 * Convenience method that obtains a given acl_object_identity record.
332 *
333 * @param aclObjectIdentity to lookup
334 *
335 * @return details of the record
336 *
337 * @throws DataRetrievalFailureException if record could not be found
338 */
339 private AclDetailsHolder lookupAclDetailsHolder(
340 AclObjectIdentity aclObjectIdentity)
341 throws DataRetrievalFailureException {
342 String aclObjectIdentityString = convertAclObjectIdentityToString(aclObjectIdentity);
343
344
345 List objects = objectProperties.execute(aclObjectIdentityString);
346
347 if (objects.size() == 0) {
348 throw new DataRetrievalFailureException(
349 "aclObjectIdentity not found: " + aclObjectIdentityString);
350 }
351
352
353 return (AclDetailsHolder) objects.get(0);
354 }
355
356 /***
357 * Convenience method to lookup the acl_permission applying to a given
358 * acl_object_identity.id and acl_permission.recipient.
359 *
360 * @param aclObjectIdentityId to locate
361 * @param recipient to locate
362 *
363 * @return the acl_permission.id of the record, or -1 if not found
364 *
365 * @throws DataAccessException DOCUMENT ME!
366 */
367 private long lookupPermissionId(long aclObjectIdentityId, Object recipient)
368 throws DataAccessException {
369 List list = lookupPermissionIdMapping.execute(new Object[] {new Long(
370 aclObjectIdentityId), recipient});
371
372 if (list.size() == 0) {
373 return -1;
374 }
375
376 return ((Long) list.get(0)).longValue();
377 }
378
379
380
381 protected class AclObjectIdentityDelete extends SqlUpdate {
382 protected AclObjectIdentityDelete(DataSource ds) {
383 super(ds, aclObjectIdentityDeleteStatement);
384 declareParameter(new SqlParameter(Types.BIGINT));
385 compile();
386 }
387
388 protected void delete(Long aclObjectIdentity)
389 throws DataAccessException {
390 super.update(aclObjectIdentity.intValue());
391 }
392 }
393
394 protected class AclObjectIdentityInsert extends SqlUpdate {
395 protected AclObjectIdentityInsert(DataSource ds) {
396 super(ds, aclObjectIdentityInsertStatement);
397 declareParameter(new SqlParameter(Types.VARCHAR));
398 declareParameter(new SqlParameter(Types.BIGINT));
399 declareParameter(new SqlParameter(Types.VARCHAR));
400 compile();
401 }
402
403 protected void insert(String objectIdentity,
404 Long parentAclObjectIdentity, String aclClass)
405 throws DataAccessException {
406 Object[] objs = new Object[] {objectIdentity, parentAclObjectIdentity, aclClass};
407 super.update(objs);
408 }
409 }
410
411 protected class AclPermissionDelete extends SqlUpdate {
412 protected AclPermissionDelete(DataSource ds) {
413 super(ds, aclPermissionDeleteStatement);
414 declareParameter(new SqlParameter(Types.BIGINT));
415 declareParameter(new SqlParameter(Types.VARCHAR));
416 compile();
417 }
418
419 protected void delete(Long aclObjectIdentity, String recipient)
420 throws DataAccessException {
421 super.update(new Object[] {aclObjectIdentity, recipient});
422 }
423 }
424
425 protected class AclPermissionInsert extends SqlUpdate {
426 protected AclPermissionInsert(DataSource ds) {
427 super(ds, aclPermissionInsertStatement);
428 declareParameter(new SqlParameter(Types.BIGINT));
429 declareParameter(new SqlParameter(Types.VARCHAR));
430 declareParameter(new SqlParameter(Types.INTEGER));
431 compile();
432 }
433
434 protected void insert(Long aclObjectIdentity, String recipient,
435 Integer mask) throws DataAccessException {
436 Object[] objs = new Object[] {aclObjectIdentity, recipient, mask};
437 super.update(objs);
438 }
439 }
440
441 protected class AclPermissionUpdate extends SqlUpdate {
442 protected AclPermissionUpdate(DataSource ds) {
443 super(ds, aclPermissionUpdateStatement);
444 declareParameter(new SqlParameter(Types.BIGINT));
445 declareParameter(new SqlParameter(Types.INTEGER));
446 compile();
447 }
448
449 protected void update(Long aclPermissionId, Integer newMask)
450 throws DataAccessException {
451 super.update(newMask.intValue(), aclPermissionId.intValue());
452 }
453 }
454
455 protected class LookupPermissionIdMapping extends MappingSqlQuery {
456 protected LookupPermissionIdMapping(DataSource ds) {
457 super(ds, lookupPermissionIdQuery);
458 declareParameter(new SqlParameter(Types.BIGINT));
459 declareParameter(new SqlParameter(Types.VARCHAR));
460 compile();
461 }
462
463 protected Object mapRow(ResultSet rs, int rownum)
464 throws SQLException {
465 return new Long(rs.getLong(1));
466 }
467 }
468 }