View Javadoc
1   package org.apache.fulcrum.security.torque;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  import java.sql.Connection;
22  import java.util.List;
23  
24  import org.apache.avalon.framework.configuration.Configuration;
25  import org.apache.avalon.framework.configuration.ConfigurationException;
26  import org.apache.fulcrum.security.entity.User;
27  import org.apache.fulcrum.security.spi.AbstractUserManager;
28  import org.apache.fulcrum.security.torque.security.TorqueAbstractSecurityEntity;
29  import org.apache.fulcrum.security.util.DataBackendException;
30  import org.apache.fulcrum.security.util.UnknownEntityException;
31  import org.apache.fulcrum.security.util.UserSet;
32  import org.apache.torque.NoRowsException;
33  import org.apache.torque.TooManyRowsException;
34  import org.apache.torque.TorqueException;
35  import org.apache.torque.util.Transaction;
36  
37  /**
38   * This implementation persists to a database via Torque.
39   *
40   * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
41   * @version $Id:$
42   */
43  public abstract class TorqueAbstractUserManager extends AbstractUserManager {
44  
45  	/** Serial version */
46  	private static final long serialVersionUID = 2050218990148719292L;
47  
48  	/**
49  	 * Avalon Service lifecycle method
50  	 */
51  	@Override
52  	public void configure(Configuration conf) throws ConfigurationException {
53  		super.configure(conf);
54  	}
55  
56  	/**
57  	 * Get all specialized Users
58  	 *
59  	 * @param con a database connection
60  	 *
61  	 * @return a List of User instances
62  	 *
63  	 * @throws TorqueException if any database error occurs
64  	 */
65  	protected abstract <T extends User> List<T> doSelectAllUsers(Connection con) throws TorqueException;
66  
67  	/**
68  	 * Get a specialized User by name
69  	 *
70  	 * @param name the name of the group
71  	 * @param con  a database connection
72  	 *
73  	 * @return a User instance
74  	 *
75  	 * @throws NoRowsException      if no such group exists
76  	 * @throws TooManyRowsException if multiple groups with the given name exist
77  	 * @throws TorqueException      if any database error occurs if any other
78  	 *                              database error occurs
79  	 */
80  	protected abstract <T extends User> T doSelectByName(String name, Connection con)
81  			throws NoRowsException, TooManyRowsException, TorqueException;
82  
83  	/**
84  	 * Get a specialized User by id
85  	 *
86  	 * @param id  the id of the group
87  	 * @param con a database connection
88  	 *
89  	 * @return a User instance
90  	 *
91  	 * @throws NoRowsException      if no such group exists
92  	 * @throws TooManyRowsException if multiple groups with the given id exist
93  	 * @throws TorqueException      if any database error occurs if any other
94  	 *                              database error occurs
95  	 */
96  	protected abstract <T extends User> T doSelectById(Integer id, Connection con)
97  			throws NoRowsException, TooManyRowsException, TorqueException;
98  
99  	/**
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 }