Browse Source

Added BasicAclExtendedDao interface and JdbcExtendedDaoImpl for ACL CRUD.

Ben Alex 21 years ago
parent
commit
af5917b685

+ 1 - 0
changelog.txt

@@ -9,6 +9,7 @@ Changes in version 0.7 (2004-xx-xx)
 * Added AuthenticationProcessingFilter.setDetails for use by subclasses
 * Added 403-causing exception to HttpSession via SecurityEnforcementFilter
 * Added net.sf.acegisecurity.intercept.event package
+* Added BasicAclExtendedDao interface and JdbcExtendedDaoImpl for ACL CRUD
 * Improved BasicAclProvider to only respond to specified ACL object requests
 * Refactored MethodDefinitionSource to work with Method, not MethodInvocation
 * Refactored AbstractSecurityInterceptor to better support other AOP libraries

+ 64 - 0
core/src/main/java/org/acegisecurity/acl/basic/BasicAclExtendedDao.java

@@ -0,0 +1,64 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.acl.basic;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * Represents a more extensive data access object
+ * for {@link BasicAclEntry}s.
+ * 
+ * <P>
+ * <code>BasicAclExtendedDao</code> implementations are responsible for interpreting a
+ * a given {@link AclObjectIdentity}.
+ * </p>
+ * 
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface BasicAclExtendedDao extends BasicAclDao {
+    //~ Methods ================================================================
+
+	public void create(BasicAclEntry basicAclEntry)  throws DataAccessException;
+	
+	/**
+	 * Deletes <b>all</b> entries associated with the
+	 * specified <code>AclObjectIdentity</code>.
+	 * 
+	 * @param aclObjectIdentity to delete, including any <code>BasicAclEntry</code>s
+	 */
+	public void delete(AclObjectIdentity aclObjectIdentity) throws DataAccessException;
+	
+	/**
+	 * Deletes the <code>BasicAclEntry</code> associated with the specified
+	 * <code>AclObjectIdentity</code> and recipient <code>Object</code>.
+	 * 
+	 * @param aclObjectIdentity to delete
+	 * @param recipient to delete
+	 */
+	public void delete(AclObjectIdentity aclObjectIdentity, Object recipient) throws DataAccessException;
+	
+	/**
+	 * Changes the permission mask assigned to the <code>BasicAclEntry</code>
+	 * associated with the specified
+	 * <code>AclObjectIdentity</code> and recipient <code>Object</code>.
+	 * 
+	 * @param aclObjectIdentity to locate the relevant <code>BasicAclEntry</code>
+	 * @param recipient to locate the relevant <code>BasicAclEntry</code>
+	 * @param newMask indicating the new permission
+	 */
+	public void changeMask(AclObjectIdentity aclObjectIdentity, Object recipient, Integer newMask) throws DataAccessException;
+}

+ 4 - 4
core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcDaoImpl.java

@@ -61,12 +61,12 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao {
     public static final String RECIPIENT_USED_FOR_INHERITENCE_MARKER = "___INHERITENCE_MARKER_ONLY___";
     public static final String DEF_ACLS_BY_OBJECT_IDENTITY_QUERY = "SELECT RECIPIENT, MASK FROM acl_permission WHERE acl_object_identity = ?";
     public static final String DEF_OBJECT_PROPERTIES_QUERY = "SELECT ID, OBJECT_IDENTITY, ACL_CLASS, PARENT.OBJECT_IDENTITY as PARENT_OBJECT_IDENTITY FROM acl_object_identity LEFT OUTER JOIN acl_object_identity as PARENT ON acl_object_identity.parent_object=parent.id WHERE parent.id=acl_object_identity.parent_object and object_identity = ?";
-    private static final Log logger = LogFactory.getLog(JdbcDaoSupport.class);
+    private static final Log logger = LogFactory.getLog(JdbcDaoImpl.class);
 
     //~ Instance fields ========================================================
 
-    private MappingSqlQuery aclsByObjectIdentity;
-    private MappingSqlQuery objectProperties;
+    protected MappingSqlQuery aclsByObjectIdentity;
+    protected MappingSqlQuery objectProperties;
     private String aclsByObjectIdentityQuery;
     private String objectPropertiesQuery;
 
@@ -375,7 +375,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao {
      * preferably the backend RDBMS via schema constraints).
      * </p>
      */
-    private class AclDetailsHolder {
+    protected final class AclDetailsHolder {
         private AclObjectIdentity aclObjectIdentity;
         private AclObjectIdentity aclObjectParentIdentity;
         private Class aclClass;

+ 492 - 0
core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcExtendedDaoImpl.java

@@ -0,0 +1,492 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.acl.basic.jdbc;
+
+import net.sf.acegisecurity.acl.basic.AclObjectIdentity;
+import net.sf.acegisecurity.acl.basic.BasicAclEntry;
+import net.sf.acegisecurity.acl.basic.BasicAclExtendedDao;
+import net.sf.acegisecurity.acl.basic.NamedEntityObjectIdentity;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.context.ApplicationContextException;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.DataRetrievalFailureException;
+
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.object.MappingSqlQuery;
+import org.springframework.jdbc.object.SqlUpdate;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+
+/**
+ * <p>
+ * Extension of the base {@link JdbcDaoImpl}, which implements {@link
+ * BasicAclExtendedDao}.
+ * </p>
+ * 
+ * <p>
+ * A default database structure is assumed. This may be overridden by setting
+ * the default query strings to use.
+ * </p>
+ * 
+ * <p>
+ * This implementation works with <code>String</code> based recipients and
+ * {@link net.sf.acegisecurity.acl.basic.NamedEntityObjectIdentity} only. The
+ * latter can be changed by overriding {@link
+ * #convertAclObjectIdentityToString(AclObjectIdentity)}.
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class JdbcExtendedDaoImpl extends JdbcDaoImpl
+    implements BasicAclExtendedDao {
+    //~ Static fields/initializers =============================================
+
+    private static final Log logger = LogFactory.getLog(JdbcExtendedDaoImpl.class);
+    public static final String DEF_ACL_OBJECT_IDENTITY_DELETE_STATEMENT = "DELETE FROM acl_object_identity WHERE id = ?";
+    public static final String DEF_ACL_OBJECT_IDENTITY_INSERT_STATEMENT = "INSERT INTO acl_object_identity (id, object_identity, parent_object, acl_class) VALUES (?, ?, ?, ?)";
+    public static final String DEF_ACL_PERMISSION_DELETE_STATEMENT = "DELETE FROM acl_permission WHERE acl_object_identity = ? AND recipient = ?";
+    public static final String DEF_ACL_PERMISSION_INSERT_STATEMENT = "INSERT INTO acl_permission (id, acl_object_identity, recipient, mask) VALUES (?, ?, ?, ?)";
+    public static final String DEF_ACL_PERMISSION_UPDATE_STATEMENT = "UPDATE acl_permission SET mask = ? WHERE id = ?";
+    public static final String DEF_LOOKUP_PERMISSION_ID_QUERY = "SELECT id FROM acl_permission WHERE acl_object_identity = ? AND recipient = ?";
+
+    //~ Instance fields ========================================================
+
+    private AclObjectIdentityDelete aclObjectIdentityDelete;
+    private AclObjectIdentityInsert aclObjectIdentityInsert;
+    private AclPermissionDelete aclPermissionDelete;
+    private AclPermissionInsert aclPermissionInsert;
+    private AclPermissionUpdate aclPermissionUpdate;
+    private MappingSqlQuery lookupPermissionIdMapping;
+    private String aclObjectIdentityDeleteStatement;
+    private String aclObjectIdentityInsertStatement;
+    private String aclPermissionDeleteStatement;
+    private String aclPermissionInsertStatement;
+    private String aclPermissionUpdateStatement;
+    private String lookupPermissionIdQuery;
+
+    //~ Constructors ===========================================================
+
+    public JdbcExtendedDaoImpl() {
+        aclObjectIdentityDeleteStatement = DEF_ACL_OBJECT_IDENTITY_DELETE_STATEMENT;
+        aclObjectIdentityInsertStatement = DEF_ACL_OBJECT_IDENTITY_INSERT_STATEMENT;
+        aclPermissionDeleteStatement = DEF_ACL_PERMISSION_DELETE_STATEMENT;
+        aclPermissionInsertStatement = DEF_ACL_PERMISSION_INSERT_STATEMENT;
+        aclPermissionUpdateStatement = DEF_ACL_PERMISSION_UPDATE_STATEMENT;
+        lookupPermissionIdQuery = DEF_LOOKUP_PERMISSION_ID_QUERY;
+    }
+
+    //~ Methods ================================================================
+
+    public void setAclObjectIdentityDelete(
+        AclObjectIdentityDelete aclObjectIdentityDelete) {
+        this.aclObjectIdentityDelete = aclObjectIdentityDelete;
+    }
+
+    public AclObjectIdentityDelete getAclObjectIdentityDelete() {
+        return aclObjectIdentityDelete;
+    }
+
+    public void setAclObjectIdentityDeleteStatement(
+        String aclObjectIdentityDeleteStatement) {
+        this.aclObjectIdentityDeleteStatement = aclObjectIdentityDeleteStatement;
+    }
+
+    public String getAclObjectIdentityDeleteStatement() {
+        return aclObjectIdentityDeleteStatement;
+    }
+
+    public void setAclObjectIdentityInsert(
+        AclObjectIdentityInsert aclObjectIdentityInsert) {
+        this.aclObjectIdentityInsert = aclObjectIdentityInsert;
+    }
+
+    public AclObjectIdentityInsert getAclObjectIdentityInsert() {
+        return aclObjectIdentityInsert;
+    }
+
+    public void setAclObjectIdentityInsertStatement(
+        String aclObjectIdentityInsertStatement) {
+        this.aclObjectIdentityInsertStatement = aclObjectIdentityInsertStatement;
+    }
+
+    public String getAclObjectIdentityInsertStatement() {
+        return aclObjectIdentityInsertStatement;
+    }
+
+    public void setAclPermissionDelete(AclPermissionDelete aclPermissionDelete) {
+        this.aclPermissionDelete = aclPermissionDelete;
+    }
+
+    public AclPermissionDelete getAclPermissionDelete() {
+        return aclPermissionDelete;
+    }
+
+    public void setAclPermissionDeleteStatement(
+        String aclPermissionDeleteStatement) {
+        this.aclPermissionDeleteStatement = aclPermissionDeleteStatement;
+    }
+
+    public String getAclPermissionDeleteStatement() {
+        return aclPermissionDeleteStatement;
+    }
+
+    public void setAclPermissionInsert(AclPermissionInsert aclPermissionInsert) {
+        this.aclPermissionInsert = aclPermissionInsert;
+    }
+
+    public AclPermissionInsert getAclPermissionInsert() {
+        return aclPermissionInsert;
+    }
+
+    public void setAclPermissionInsertStatement(
+        String aclPermissionInsertStatement) {
+        this.aclPermissionInsertStatement = aclPermissionInsertStatement;
+    }
+
+    public String getAclPermissionInsertStatement() {
+        return aclPermissionInsertStatement;
+    }
+
+    public void setAclPermissionUpdate(AclPermissionUpdate aclPermissionUpdate) {
+        this.aclPermissionUpdate = aclPermissionUpdate;
+    }
+
+    public AclPermissionUpdate getAclPermissionUpdate() {
+        return aclPermissionUpdate;
+    }
+
+    public void setAclPermissionUpdateStatement(
+        String aclPermissionUpdateStatement) {
+        this.aclPermissionUpdateStatement = aclPermissionUpdateStatement;
+    }
+
+    public String getAclPermissionUpdateStatement() {
+        return aclPermissionUpdateStatement;
+    }
+
+    public void setLookupPermissionIdMapping(
+        MappingSqlQuery lookupPermissionIdMapping) {
+        this.lookupPermissionIdMapping = lookupPermissionIdMapping;
+    }
+
+    public MappingSqlQuery getLookupPermissionIdMapping() {
+        return lookupPermissionIdMapping;
+    }
+
+    public void setLookupPermissionIdQuery(String lookupPermissionIdQuery) {
+        this.lookupPermissionIdQuery = lookupPermissionIdQuery;
+    }
+
+    public String getLookupPermissionIdQuery() {
+        return lookupPermissionIdQuery;
+    }
+
+    public void changeMask(AclObjectIdentity aclObjectIdentity,
+        Object recipient, Integer newMask) throws DataAccessException {
+        // Retrieve acl_object_identity record details
+        AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
+
+        // Retrieve applicable acl_permission.id
+        int permissionId = lookupPermissionId(aclDetailsHolder.getForeignKeyId(),
+                recipient.toString());
+
+        if (permissionId == -1) {
+            throw new DataRetrievalFailureException(
+                "Could not locate existing acl_permission for aclObjectIdentity: "
+                + aclObjectIdentity + ", recipient: " + recipient.toString());
+        }
+
+        // Change permission
+        aclPermissionUpdate.update(new Integer(
+                aclDetailsHolder.getForeignKeyId()), newMask);
+    }
+
+    public void create(BasicAclEntry basicAclEntry) throws DataAccessException {
+        // Create acl_object_identity record if required
+        createAclObjectIdentityIfRequired(basicAclEntry);
+
+        // Retrieve acl_object_identity record details
+        AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(basicAclEntry
+                .getAclObjectIdentity());
+
+        // Ensure there isn't an existing record for this recipient
+        if (lookupPermissionId(aclDetailsHolder.getForeignKeyId(),
+                basicAclEntry.getRecipient()) != -1) {
+            throw new DataIntegrityViolationException(
+                "This recipient already exists for this aclObjectIdentity");
+        }
+
+        // Create acl_permission
+        aclPermissionInsert.insert(new Integer(
+                aclDetailsHolder.getForeignKeyId()),
+            basicAclEntry.getRecipient().toString(),
+            new Integer(basicAclEntry.getMask()));
+    }
+
+    public void delete(AclObjectIdentity aclObjectIdentity)
+        throws DataAccessException {
+        // Retrieve acl_object_identity record details
+        AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
+
+        // Retrieve all acl_permissions applying to this acl_object_identity
+        Iterator acls = aclsByObjectIdentity.execute(aclDetailsHolder
+                .getForeignKeyId()).iterator();
+
+        // Delete all existing acl_permissions applying to this acl_object_identity
+        while (acls.hasNext()) {
+            AclDetailsHolder permission = (AclDetailsHolder) acls.next();
+            delete(aclObjectIdentity, permission.getRecipient());
+        }
+
+        // Delete acl_object_identity
+        aclObjectIdentityDelete.delete(new Integer(
+                aclDetailsHolder.getForeignKeyId()));
+    }
+
+    public void delete(AclObjectIdentity aclObjectIdentity, Object recipient)
+        throws DataAccessException {
+        // Retrieve acl_object_identity record details
+        AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
+
+        // Delete acl_permission
+        aclPermissionDelete.delete(new Integer(
+                aclDetailsHolder.getForeignKeyId()), recipient.toString());
+    }
+
+    /**
+     * Responsible for covering a <code>AclObjectIdentity</code> to a
+     * <code>String</code> that can be located in the RDBMS.
+     *
+     * @param aclObjectIdentity to locate
+     *
+     * @return the object identity as a <code>String</code>
+     *
+     * @throws IllegalArgumentException DOCUMENT ME!
+     */
+    protected String convertAclObjectIdentityToString(
+        AclObjectIdentity aclObjectIdentity) {
+        // Ensure we can process this type of AclObjectIdentity
+        if (!(aclObjectIdentity instanceof NamedEntityObjectIdentity)) {
+            throw new IllegalArgumentException(
+                "Only aclObjectIdentity of type NamedEntityObjectIdentity supported (was passed: "
+                + aclObjectIdentity + ")");
+        }
+
+        NamedEntityObjectIdentity neoi = (NamedEntityObjectIdentity) aclObjectIdentity;
+
+        // Compose the String we expect to find in the RDBMS
+        return neoi.getClassname() + ":" + neoi.getId();
+    }
+
+    protected void initDao() throws ApplicationContextException {
+        super.initDao();
+        lookupPermissionIdMapping = new LookupPermissionIdMapping(getDataSource());
+        aclPermissionInsert = new AclPermissionInsert(getDataSource());
+        aclObjectIdentityInsert = new AclObjectIdentityInsert(getDataSource());
+        aclPermissionDelete = new AclPermissionDelete(getDataSource());
+        aclObjectIdentityDelete = new AclObjectIdentityDelete(getDataSource());
+        aclPermissionUpdate = new AclPermissionUpdate(getDataSource());
+    }
+
+    /**
+     * Convenience method that creates an acl_object_identity record if
+     * required.
+     *
+     * @param basicAclEntry containing the <code>AclObjectIdentity</code> to
+     *        create
+     *
+     * @throws DataAccessException
+     */
+    private void createAclObjectIdentityIfRequired(BasicAclEntry basicAclEntry)
+        throws DataAccessException {
+        String aclObjectIdentityString = convertAclObjectIdentityToString(basicAclEntry
+                .getAclObjectIdentity());
+
+        // Lookup the object's main properties from the RDBMS (guaranteed no nulls)
+        List objects = objectProperties.execute(aclObjectIdentityString);
+
+        if (objects.size() == 0) {
+            if (basicAclEntry.getAclObjectParentIdentity() != null) {
+                AclDetailsHolder parentDetails = lookupAclDetailsHolder(basicAclEntry
+                        .getAclObjectParentIdentity());
+
+                // Must create the acl_object_identity record
+                aclObjectIdentityInsert.insert(aclObjectIdentityString,
+                    new Integer(parentDetails.getForeignKeyId()),
+                    basicAclEntry.getClass().getName());
+            } else {
+                // Must create the acl_object_identity record
+                aclObjectIdentityInsert.insert(aclObjectIdentityString, null,
+                    basicAclEntry.getClass().getName());
+            }
+        }
+    }
+
+    /**
+     * Convenience method that obtains a given acl_object_identity record.
+     *
+     * @param aclObjectIdentity to lookup
+     *
+     * @return details of the record
+     *
+     * @throws DataRetrievalFailureException if record could not be found
+     */
+    private AclDetailsHolder lookupAclDetailsHolder(
+        AclObjectIdentity aclObjectIdentity)
+        throws DataRetrievalFailureException {
+        String aclObjectIdentityString = convertAclObjectIdentityToString(aclObjectIdentity);
+
+        // Lookup the object's main properties from the RDBMS (guaranteed no nulls)
+        List objects = objectProperties.execute(aclObjectIdentityString);
+
+        if (objects.size() == 0) {
+            throw new DataRetrievalFailureException(
+                "aclObjectIdentity not found: " + aclObjectIdentityString);
+        }
+
+        // Should only be one record
+        return (AclDetailsHolder) objects.get(0);
+    }
+
+    /**
+     * Convenience method to lookup the acl_permission applying to a given
+     * acl_object_identity.id and acl_permission.recipient.
+     *
+     * @param aclObjectIdentityId to locate
+     * @param recipient to locate
+     *
+     * @return the acl_permission.id of the record, or -1 if not found
+     *
+     * @throws DataAccessException DOCUMENT ME!
+     */
+    private int lookupPermissionId(int aclObjectIdentityId, Object recipient)
+        throws DataAccessException {
+        List list = lookupPermissionIdMapping.execute(new Object[] {new Integer(
+                        aclObjectIdentityId), recipient});
+
+        if (list.size() == 0) {
+            return -1;
+        }
+
+        return ((Integer) list.get(0)).intValue();
+    }
+
+    //~ Inner Classes ==========================================================
+
+    protected class AclObjectIdentityDelete extends SqlUpdate {
+        protected AclObjectIdentityDelete(DataSource ds) {
+            super(ds, aclObjectIdentityDeleteStatement);
+            declareParameter(new SqlParameter(Types.INTEGER));
+            compile();
+        }
+
+        protected void delete(Integer aclObjectIdentity)
+            throws DataAccessException {
+            super.update(aclObjectIdentity.intValue());
+        }
+    }
+
+    protected class AclObjectIdentityInsert extends SqlUpdate {
+        protected AclObjectIdentityInsert(DataSource ds) {
+            super(ds, aclObjectIdentityInsertStatement);
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.VARCHAR));
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.VARCHAR));
+            compile();
+        }
+
+        protected void insert(String objectIdentity,
+            Integer parentAclObjectIdentity, String aclClass)
+            throws DataAccessException {
+            Object[] objs = new Object[] {null, objectIdentity, parentAclObjectIdentity, aclClass};
+            super.update(objs);
+        }
+    }
+
+    protected class AclPermissionDelete extends SqlUpdate {
+        protected AclPermissionDelete(DataSource ds) {
+            super(ds, aclPermissionDeleteStatement);
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.VARCHAR));
+            compile();
+        }
+
+        protected void delete(Integer aclObjectIdentity, String recipient)
+            throws DataAccessException {
+            super.update(new Object[] {aclObjectIdentity, recipient});
+        }
+    }
+
+    protected class AclPermissionInsert extends SqlUpdate {
+        protected AclPermissionInsert(DataSource ds) {
+            super(ds, aclPermissionInsertStatement);
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.VARCHAR));
+            declareParameter(new SqlParameter(Types.INTEGER));
+            compile();
+        }
+
+        protected void insert(Integer aclObjectIdentity, String recipient,
+            Integer mask) throws DataAccessException {
+            Object[] objs = new Object[] {null, aclObjectIdentity, recipient, mask};
+            super.update(objs);
+        }
+    }
+
+    protected class AclPermissionUpdate extends SqlUpdate {
+        protected AclPermissionUpdate(DataSource ds) {
+            super(ds, aclPermissionUpdateStatement);
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.INTEGER));
+            compile();
+        }
+
+        protected void update(Integer aclPermissionId, Integer newMask)
+            throws DataAccessException {
+            super.update(aclPermissionId.intValue(), newMask.intValue());
+        }
+    }
+
+    protected class LookupPermissionIdMapping extends MappingSqlQuery {
+        protected LookupPermissionIdMapping(DataSource ds) {
+            super(ds, lookupPermissionIdQuery);
+            declareParameter(new SqlParameter(Types.INTEGER));
+            declareParameter(new SqlParameter(Types.VARCHAR));
+            compile();
+        }
+
+        protected Object mapRow(ResultSet rs, int rownum)
+            throws SQLException {
+            return new Integer(rs.getInt(1));
+        }
+    }
+}