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.User; 027import org.apache.fulcrum.security.spi.AbstractUserManager; 028import org.apache.fulcrum.security.torque.security.TorqueAbstractSecurityEntity; 029import org.apache.fulcrum.security.util.DataBackendException; 030import org.apache.fulcrum.security.util.UnknownEntityException; 031import org.apache.fulcrum.security.util.UserSet; 032import org.apache.torque.NoRowsException; 033import org.apache.torque.TooManyRowsException; 034import org.apache.torque.TorqueException; 035import org.apache.torque.util.Transaction; 036 037/** 038 * This implementation persists to a database via Torque. 039 * 040 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a> 041 * @version $Id:$ 042 */ 043public abstract class TorqueAbstractUserManager extends AbstractUserManager { 044 045 /** Serial version */ 046 private static final long serialVersionUID = 2050218990148719292L; 047 048 /** 049 * Avalon Service lifecycle method 050 */ 051 @Override 052 public void configure(Configuration conf) throws ConfigurationException { 053 super.configure(conf); 054 } 055 056 /** 057 * Get all specialized Users 058 * 059 * @param con a database connection 060 * 061 * @return a List of User instances 062 * 063 * @throws TorqueException if any database error occurs 064 */ 065 protected abstract <T extends User> List<T> doSelectAllUsers(Connection con) throws TorqueException; 066 067 /** 068 * Get a specialized User by name 069 * 070 * @param name the name of the group 071 * @param con a database connection 072 * 073 * @return a User instance 074 * 075 * @throws NoRowsException if no such group exists 076 * @throws TooManyRowsException if multiple groups with the given name exist 077 * @throws TorqueException if any database error occurs if any other 078 * database error occurs 079 */ 080 protected abstract <T extends User> T doSelectByName(String name, Connection con) 081 throws NoRowsException, TooManyRowsException, TorqueException; 082 083 /** 084 * Get a specialized User by id 085 * 086 * @param id the id of the group 087 * @param con a database connection 088 * 089 * @return a User instance 090 * 091 * @throws NoRowsException if no such group exists 092 * @throws TooManyRowsException if multiple groups with the given id exist 093 * @throws TorqueException if any database error occurs if any other 094 * database error occurs 095 */ 096 protected abstract <T extends User> T doSelectById(Integer id, Connection con) 097 throws NoRowsException, TooManyRowsException, TorqueException; 098 099 /** 100 * Removes an user account from the system. 101 * 102 * @param user the object describing the account to be removed. 103 * @throws DataBackendException if there was an error accessing the data 104 * backend. 105 * @throws UnknownEntityException if the user account is not present. 106 */ 107 @Override 108 public synchronized void removeUser(User user) throws DataBackendException, UnknownEntityException { 109 try { 110 ((TorqueAbstractSecurityEntity) user).delete(); 111 } catch (TorqueException e) { 112 throw new DataBackendException("Removing User '" + user.getName() + "' failed", e); 113 } 114 } 115 116 /** 117 * Creates new user account with specified attributes. 118 * 119 * @param user the object describing account to be created. 120 * 121 * @throws DataBackendException if there was an error accessing the data 122 * backend. 123 */ 124 @Override 125 protected synchronized <T extends User> T persistNewUser(T user) throws DataBackendException { 126 try { 127 TorqueAbstractSecurityEntity u = (TorqueAbstractSecurityEntity) user; 128 u.save(); 129 } catch (Exception e) { 130 throw new DataBackendException("Adding User '" + user.getName() + "' failed", e); 131 } 132 133 return user; 134 } 135 136 /** 137 * Stores User attributes. The User is required to exist in the system. 138 * 139 * @param user The User to be stored. 140 * @throws DataBackendException if there was an error accessing the data 141 * backend. 142 * @throws UnknownEntityException if the role does not exist. 143 */ 144 @Override 145 public synchronized void saveUser(User user) throws DataBackendException, UnknownEntityException { 146 if (checkExists(user)) { 147 try { 148 TorqueAbstractSecurityEntity u = (TorqueAbstractSecurityEntity) user; 149 u.setNew(false); 150 u.save(); 151 } catch (Exception e) { 152 throw new DataBackendException("Saving User '" + user.getName() + "' failed", e); 153 } 154 } else { 155 throw new UnknownEntityException("Unknown user '" + user + "'"); 156 } 157 } 158 159 /** 160 * Check whether a specified user's account exists. 161 * 162 * The login name is used for looking up the account. 163 * 164 * @param userName The name of the user to be checked. 165 * @return true if the specified account exists 166 * @throws DataBackendException if there was an error accessing the data 167 * backend. 168 */ 169 @Override 170 public boolean checkExists(String userName) throws DataBackendException { 171 boolean exists = false; 172 173 Connection con = null; 174 175 try { 176 con = Transaction.begin(); 177 178 doSelectByName(userName, con); 179 180 Transaction.commit(con); 181 con = null; 182 183 exists = true; 184 } catch (NoRowsException e) { 185 exists = false; 186 } catch (TooManyRowsException e) { 187 throw new DataBackendException("Multiple Users with same username '" + userName + "'"); 188 } catch (TorqueException e) { 189 throw new DataBackendException("Error retrieving user information", e); 190 } finally { 191 if (con != null) { 192 Transaction.safeRollback(con); 193 } 194 } 195 196 return exists; 197 } 198 199 /** 200 * Retrieve a user from persistent storage using username as the key. 201 * 202 * Additionally retrieves all attached objects from {@link TorqueAbstractSecurityEntity#retrieveAttachedObjects(Connection, Boolean)} 203 * 204 * @param userName the name of the user. 205 * @return an User object. 206 * @exception UnknownEntityException if the user's account does not exist in the 207 * database. 208 * @exception DataBackendException if there is a problem accessing the 209 * storage. 210 */ 211 @Override 212 public <T extends User> T getUser(String userName) throws UnknownEntityException, DataBackendException { 213 T user = null; 214 Connection con = null; 215 216 try { 217 con = Transaction.begin(); 218 219 user = doSelectByName(userName.toLowerCase(), con); 220 221 // Add attached objects if they exist 222 ((TorqueAbstractSecurityEntity) user).retrieveAttachedObjects(con, false); 223 224 Transaction.commit(con); 225 con = null; 226 } catch (NoRowsException e) { 227 throw new UnknownEntityException("Unknown user '" + userName + "'"); 228 } catch (TooManyRowsException e) { 229 throw new DataBackendException("Multiple Users with same username '" + userName + "'"); 230 } catch (TorqueException e) { 231 throw new DataBackendException("Error retrieving user information", e); 232 } finally { 233 if (con != null) { 234 Transaction.safeRollback(con); 235 } 236 } 237 238 return user; 239 } 240 241 /** 242 * Retrieves all users defined in the system. 243 * 244 * @return the names of all users defined in the system. 245 * @throws DataBackendException if there was an error accessing the data 246 * backend. 247 */ 248 @Override 249 public <T extends User> UserSet<T> getAllUsers() throws DataBackendException { 250 UserSet<T> userSet = new UserSet<T>(); 251 Connection con = null; 252 253 try { 254 con = Transaction.begin(); 255 256 List<User> users = doSelectAllUsers(con); 257 258 for (User user : users) { 259 // Add attached objects if they exist 260 ((TorqueAbstractSecurityEntity) user).retrieveAttachedObjects(con, false); 261 262 userSet.add(user); 263 } 264 265 Transaction.commit(con); 266 con = null; 267 } catch (TorqueException e) { 268 throw new DataBackendException("Error retrieving all users", e); 269 } finally { 270 if (con != null) { 271 Transaction.safeRollback(con); 272 } 273 } 274 275 return userSet; 276 } 277 278 /** 279 * Retrieve a User object with specified id. 280 * 281 * @param id the id of the User. 282 * @return an object representing the User with specified id. 283 * @throws DataBackendException if there was an error accessing the data 284 * backend. 285 * @throws UnknownEntityException if the user does not exist. 286 */ 287 @Override 288 public <T extends User> T getUserById(Object id) throws DataBackendException, UnknownEntityException { 289 T user; 290 291 if (id != null && id instanceof Integer) { 292 Connection con = null; 293 294 try { 295 con = Transaction.begin(); 296 297 user = doSelectById((Integer) id, con); 298 299 // Add attached objects if they exist 300 ((TorqueAbstractSecurityEntity) user).retrieveAttachedObjects(con, false); // 301 302 Transaction.commit(con); 303 con = null; 304 } catch (NoRowsException e) { 305 throw new UnknownEntityException("User with id '" + id + "' does not exist.", e); 306 } catch (TorqueException e) { 307 throw new DataBackendException("Error retrieving user information", e); 308 } finally { 309 if (con != null) { 310 Transaction.safeRollback(con); 311 } 312 } 313 } else { 314 throw new UnknownEntityException("Invalid user id '" + id + "'"); 315 } 316 317 return user; 318 } 319 320}