001package org.apache.fulcrum.security.torque;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021import java.sql.Connection;
022import java.util.List;
023
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.fulcrum.security.entity.Permission;
027import org.apache.fulcrum.security.spi.AbstractPermissionManager;
028import org.apache.fulcrum.security.torque.security.TorqueAbstractSecurityEntity;
029import org.apache.fulcrum.security.util.DataBackendException;
030import org.apache.fulcrum.security.util.EntityExistsException;
031import org.apache.fulcrum.security.util.PermissionSet;
032import org.apache.fulcrum.security.util.UnknownEntityException;
033import org.apache.torque.NoRowsException;
034import org.apache.torque.TooManyRowsException;
035import org.apache.torque.TorqueException;
036import org.apache.torque.util.Transaction;
037
038/**
039 * This implementation persists to a database via Torque.
040 *
041 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
042 * @version $Id:$
043 */
044public abstract class TorqueAbstractPermissionManager extends AbstractPermissionManager {
045
046        /** Serial version */
047        private static final long serialVersionUID = 194503017446833485L;
048
049        // no lazyLoading
050
051        /**
052         * Avalon Service lifecycle method
053         */
054        @Override
055        public void configure(Configuration conf) throws ConfigurationException {
056                super.configure(conf);
057
058        }
059
060        /**
061         * Get all specialized Permissions
062         *
063         * @param con a database connection
064         * @return a List of Permission instances
065         * @throws TorqueException if any database error occurs
066         */
067        protected abstract <T extends Permission> List<T> doSelectAllPermissions(Connection con) throws TorqueException;
068
069        /**
070         * Get a specialized Permission by name
071         *
072         * @param name the name of the group
073         * @param con  a database connection
074         *
075         * @return a Permission instance
076         *
077         * @throws NoRowsException      if no such group exists
078         * @throws TooManyRowsException if multiple groups with the given name exist
079         * @throws TorqueException      if any database error occurs if any other
080         *                              database error occurs
081         */
082        protected abstract <T extends Permission> T doSelectByName(String name, Connection con)
083                        throws NoRowsException, TooManyRowsException, TorqueException;
084
085        /**
086         * Get a specialized Permission by id
087         *
088         * @param id  the id of the group
089         * @param con a database connection
090         *
091         * @return a Permission instance
092         *
093         * @throws NoRowsException      if no such group exists
094         * @throws TooManyRowsException if multiple groups with the given id exist
095         * @throws TorqueException      if any database error occurs if any other
096         *                              database error occurs
097         */
098        protected abstract <T extends Permission> T doSelectById(Integer id, Connection con)
099                        throws NoRowsException, TooManyRowsException, TorqueException;
100
101        /**
102         * Renames an existing Permission.
103         *
104         * @param permission The object describing the permission to be renamed.
105         * @param name       the new name for the permission.
106         * @throws DataBackendException   if there was an error accessing the data
107         *                                backend.
108         * @throws UnknownEntityException if the permission does not exist.
109         */
110        @Override
111        public synchronized void renamePermission(Permission permission, String name)
112                        throws DataBackendException, UnknownEntityException {
113                if (checkExists(permission)) {
114                        permission.setName(name);
115
116                        try {
117                                TorqueAbstractSecurityEntity p = (TorqueAbstractSecurityEntity) permission;
118                                p.setNew(false);
119                                p.save();
120                        } catch (Exception e) {
121                                throw new DataBackendException("Renaming Permission '" + permission.getName() + "' failed", e);
122                        }
123                } else {
124                        throw new UnknownEntityException("Unknown permission '" + permission.getName() + "'");
125                }
126        }
127
128        /**
129         * Removes a Permission from the system.
130         *
131         * @param permission The object describing the permission to be removed.
132         * @throws DataBackendException   if there was an error accessing the data
133         *                                backend.
134         * @throws UnknownEntityException if the permission does not exist.
135         */
136        @Override
137        public synchronized void removePermission(Permission permission)
138                        throws DataBackendException, UnknownEntityException {
139                if (checkExists(permission)) {
140                        try {
141
142                                ((TorqueAbstractSecurityEntity) permission).delete();
143                        } catch (TorqueException e) {
144                                throw new DataBackendException("Removing Permission '" + permission.getName() + "' failed", e);
145                        }
146                } else {
147                        throw new UnknownEntityException("Unknown permission '" + permission.getName() + "'");
148                }
149        }
150
151        /**
152         * Creates a new permission with specified attributes.
153         *
154         * @param permission the object describing the permission to be created.
155         * @return a new Permission object that has id set up properly.
156         * @throws DataBackendException  if there was an error accessing the data
157         *                               backend.
158         */
159        @Override
160        protected synchronized <T extends Permission> T persistNewPermission(T permission) throws DataBackendException {
161                try {
162                        ((TorqueAbstractSecurityEntity) permission).save();
163                } catch (Exception e) {
164                        throw new DataBackendException("Adding Permission '" + permission.getName() + "' failed", e);
165                }
166
167                return permission;
168        }
169
170        /**
171         * Retrieves all permissions defined in the system.
172         *
173         * @return the names of all roles defined in the system.
174         * @throws DataBackendException if there was an error accessing the data
175         *                              backend.
176         */
177        @Override
178        public PermissionSet getAllPermissions() throws DataBackendException {
179                PermissionSet permissionSet = new PermissionSet();
180                Connection con = null;
181
182                try {
183                        con = Transaction.begin();
184
185                        List<Permission> permissions = doSelectAllPermissions(con);
186
187                        for (Permission p : permissions) {
188                                // Add attached objects if they exist
189                                ((TorqueAbstractSecurityEntity) p).retrieveAttachedObjects(con, false);
190                                permissionSet.add(p);
191                        }
192
193                        Transaction.commit(con);
194                        con = null;
195                } catch (TorqueException e) {
196                        throw new DataBackendException("Error retrieving permission information", e);
197                } finally {
198                        if (con != null) {
199                                Transaction.safeRollback(con);
200                        }
201                }
202
203                return permissionSet;
204        }
205
206        /**
207         * Determines if the <code>Permission</code> exists in the security system.
208         *
209         * @param permissionName a <code>Permission</code> value
210         * @return true if the permission name exists in the system, false otherwise
211         * @throws DataBackendException when more than one Permission with the same name
212         *                              exists.
213         */
214        @Override
215        public boolean checkExists(String permissionName) throws DataBackendException {
216                boolean exists = false;
217
218                Connection con = null;
219
220                try {
221                        con = Transaction.begin();
222
223                        doSelectByName(permissionName, con);
224
225                        Transaction.commit(con);
226                        con = null;
227
228                        exists = true;
229                } catch (NoRowsException e) {
230                        exists = false;
231                } catch (TooManyRowsException e) {
232                        throw new DataBackendException("Multiple permissions with same name '" + permissionName + "'");
233                } catch (TorqueException e) {
234                        throw new DataBackendException("Error retrieving permission information", e);
235                } finally {
236                        if (con != null) {
237                                Transaction.safeRollback(con);
238                        }
239                }
240
241                return exists;
242        }
243
244        /**
245         * Retrieve a Permission object with specified id.
246         *
247         * @param id the id of the Permission.
248         * @return an object representing the Permission with specified id.
249         * @throws DataBackendException   if there was an error accessing the data
250         *                                backend.
251         * @throws UnknownEntityException if the permission does not exist.
252         */
253        @Override
254        public <T extends Permission> T getPermissionById(Object id) throws DataBackendException, UnknownEntityException {
255                T permission;
256
257                if (id != null && id instanceof Integer) {
258                        Connection con = null;
259
260                        try {
261                                con = Transaction.begin();
262
263                                permission = doSelectById((Integer) id, con);
264
265                                // Add attached objects if they exist
266                                ((TorqueAbstractSecurityEntity) permission).retrieveAttachedObjects(con, false);
267
268                                Transaction.commit(con);
269                                con = null;
270                        } catch (NoRowsException e) {
271                                throw new UnknownEntityException("Permission with id '" + id + "' does not exist.", e);
272                        } catch (TorqueException e) {
273                                throw new DataBackendException("Error retrieving permission information", e);
274                        } finally {
275                                if (con != null) {
276                                        Transaction.safeRollback(con);
277                                }
278                        }
279                } else {
280                        throw new UnknownEntityException("Invalid permission id '" + id + "'");
281                }
282
283                return permission;
284        }
285
286        /**
287         * Retrieve a Permission object with specified name.
288         *
289         * @param name the name of the Group.
290         * @return an object representing the Group with specified name.
291         * @throws DataBackendException   if there was an error accessing the data
292         *                                backend.
293         * @throws UnknownEntityException if the group does not exist.
294         */
295        @Override
296        public <T extends Permission> T getPermissionByName(String name)
297                        throws DataBackendException, UnknownEntityException {
298                T permission = null;
299                Connection con = null;
300
301                try {
302                        con = Transaction.begin();
303
304                        permission = doSelectByName(name, con);
305
306                        // Add attached objects if they exist
307                        ((TorqueAbstractSecurityEntity) permission).retrieveAttachedObjects(con, false);
308
309                        Transaction.commit(con);
310                        con = null;
311                } catch (NoRowsException e) {
312                        throw new UnknownEntityException("Could not find permission " + name);
313                } catch (TooManyRowsException e) {
314                        throw new DataBackendException("Multiple Permissions with same name '" + name + "'");
315                } catch (TorqueException e) {
316                        throw new DataBackendException("Error retrieving permission information", e);
317                } finally {
318                        if (con != null) {
319                                Transaction.safeRollback(con);
320                        }
321                }
322
323                return permission;
324        }
325}