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