001 /****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one *
003 * or more contributor license agreements. See the NOTICE file *
004 * distributed with this work for additional information *
005 * regarding copyright ownership. The ASF licenses this file *
006 * to you under the Apache License, Version 2.0 (the *
007 * "License"); you may not use this file except in compliance *
008 * with the License. You may obtain a copy of the License at *
009 * *
010 * http://www.apache.org/licenses/LICENSE-2.0 *
011 * *
012 * Unless required by applicable law or agreed to in writing, *
013 * software distributed under the License is distributed on an *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015 * KIND, either express or implied. See the License for the *
016 * specific language governing permissions and limitations *
017 * under the License. *
018 ****************************************************************/
019
020 package org.apache.james.user.jpa;
021
022 import java.util.Collections;
023 import java.util.Iterator;
024
025 import javax.annotation.PostConstruct;
026 import javax.persistence.EntityManager;
027 import javax.persistence.EntityManagerFactory;
028 import javax.persistence.EntityTransaction;
029 import javax.persistence.NoResultException;
030 import javax.persistence.PersistenceException;
031 import javax.persistence.PersistenceUnit;
032
033 import org.apache.commons.configuration.ConfigurationException;
034 import org.apache.commons.configuration.HierarchicalConfiguration;
035 import org.apache.james.user.api.UsersRepositoryException;
036 import org.apache.james.user.api.model.User;
037 import org.apache.james.user.jpa.model.JPAUser;
038 import org.apache.james.user.lib.AbstractUsersRepository;
039
040 /**
041 * JPA based UserRepository
042 */
043 public class JPAUsersRepository extends AbstractUsersRepository {
044
045 private EntityManagerFactory entityManagerFactory;
046
047 private String algo;
048
049 /**
050 * Sets entity manager.
051 *
052 * @param entityManagerFactory
053 * the entityManager to set
054 */
055 @PersistenceUnit
056 public final void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
057 this.entityManagerFactory = entityManagerFactory;
058 }
059
060 @PostConstruct
061 public void init() {
062 createEntityManager().close();
063 }
064
065 /**
066 * Get the user object with the specified user name. Return null if no such
067 * user.
068 *
069 * @param name
070 * the name of the user to retrieve
071 * @return the user being retrieved, null if the user doesn't exist
072 *
073 * @since James 1.2.2
074 */
075 public User getUserByName(String name) throws UsersRepositoryException {
076 EntityManager entityManager = entityManagerFactory.createEntityManager();
077
078 try {
079 return (JPAUser) entityManager.createNamedQuery("findUserByName").setParameter("name", name).getSingleResult();
080 } catch (NoResultException e) {
081 return null;
082 } catch (PersistenceException e) {
083 getLogger().debug("Failed to find user", e);
084 throw new UsersRepositoryException("Unable to search user", e);
085 } finally {
086 entityManager.close();
087 }
088 }
089
090 /**
091 * Returns the user name of the user matching name on an equalsIgnoreCase
092 * basis. Returns null if no match.
093 *
094 * @param name
095 * the name to case-correct
096 * @return the case-correct name of the user, null if the user doesn't exist
097 * @throws UsersRepositoryException
098 */
099 public String getRealName(String name) throws UsersRepositoryException {
100 User u = getUserByName(name);
101 if (u != null) {
102 u.getUserName();
103 }
104 return null;
105 }
106
107 /**
108 * Update the repository with the specified user object. A user object with
109 * this username must already exist.
110 *
111 * @throws UsersRepositoryException
112 */
113 public void updateUser(User user) throws UsersRepositoryException {
114 EntityManager entityManager = entityManagerFactory.createEntityManager();
115
116 final EntityTransaction transaction = entityManager.getTransaction();
117 try {
118 if (contains(user.getUserName())) {
119 transaction.begin();
120 entityManager.merge(user);
121 transaction.commit();
122 } else {
123 getLogger().debug("User not found");
124 throw new UsersRepositoryException("User " + user.getUserName() + " not found");
125 }
126 } catch (PersistenceException e) {
127 getLogger().debug("Failed to update user", e);
128 if (transaction.isActive()) {
129 transaction.rollback();
130 }
131 throw new UsersRepositoryException("Failed to update user " + user.getUserName(), e);
132 } finally {
133 entityManager.close();
134 }
135 }
136
137 /**
138 * Removes a user from the repository
139 *
140 * @param name
141 * the user to remove from the repository
142 * @throws UsersRepositoryException
143 */
144 public void removeUser(String name) throws UsersRepositoryException {
145 EntityManager entityManager = entityManagerFactory.createEntityManager();
146
147 final EntityTransaction transaction = entityManager.getTransaction();
148 try {
149 transaction.begin();
150 if (entityManager.createNamedQuery("deleteUserByName").setParameter("name", name).executeUpdate() < 1) {
151 transaction.commit();
152 throw new UsersRepositoryException("User " + name + " does not exist");
153 } else {
154 transaction.commit();
155 }
156 } catch (PersistenceException e) {
157 getLogger().debug("Failed to remove user", e);
158 if (transaction.isActive()) {
159 transaction.rollback();
160 }
161 throw new UsersRepositoryException("Failed to remove user " + name, e);
162 } finally {
163 entityManager.close();
164 }
165 }
166
167 /**
168 * Returns whether or not this user is in the repository
169 *
170 * @param name
171 * the name to check in the repository
172 * @return whether the user is in the repository
173 * @throws UsersRepositoryException
174 */
175 public boolean contains(String name) throws UsersRepositoryException {
176 EntityManager entityManager = entityManagerFactory.createEntityManager();
177
178 try {
179 return ((Long) entityManager.createNamedQuery("containsUser").setParameter("name", name.toLowerCase()).getSingleResult()).longValue() > 0;
180 } catch (PersistenceException e) {
181 getLogger().debug("Failed to find user", e);
182 throw new UsersRepositoryException("Failed to find user" + name, e);
183 } finally {
184 entityManager.close();
185 }
186 }
187
188 /**
189 * Test if user with name 'name' has password 'password'.
190 *
191 * @param name
192 * the name of the user to be tested
193 * @param password
194 * the password to be tested
195 *
196 * @return true if the test is successful, false if the user doesn't exist
197 * or if the password is incorrect
198 *
199 * @since James 1.2.2
200 */
201 public boolean test(String name, String password) throws UsersRepositoryException {
202 final User user = getUserByName(name);
203 final boolean result;
204 if (user == null) {
205 result = false;
206 } else {
207 result = user.verifyPassword(password);
208 }
209 return result;
210 }
211
212 /**
213 * Returns a count of the users in the repository.
214 *
215 * @return the number of users in the repository
216 * @throws UsersRepositoryException
217 */
218 public int countUsers() throws UsersRepositoryException {
219 EntityManager entityManager = entityManagerFactory.createEntityManager();
220
221 try {
222 return ((Long) entityManager.createNamedQuery("countUsers").getSingleResult()).intValue();
223 } catch (PersistenceException e) {
224 getLogger().debug("Failed to find user", e);
225 throw new UsersRepositoryException("Failed to count users", e);
226 } finally {
227 entityManager.close();
228 }
229 }
230
231 /**
232 * List users in repository.
233 *
234 * @return Iterator over a collection of Strings, each being one user in the
235 * repository.
236 * @throws UsersRepositoryException
237 */
238 @SuppressWarnings("unchecked")
239 public Iterator<String> list() throws UsersRepositoryException {
240 EntityManager entityManager = entityManagerFactory.createEntityManager();
241
242 try {
243 return Collections.unmodifiableList(entityManager.createNamedQuery("listUserNames").getResultList()).iterator();
244
245 } catch (PersistenceException e) {
246 getLogger().debug("Failed to find user", e);
247 throw new UsersRepositoryException("Failed to list users", e);
248 } finally {
249 entityManager.close();
250 }
251 }
252
253 /**
254 * @see
255 * org.apache.james.user.lib.AbstractUsersRepository#doConfigure(org.apache.commons.configuration.HierarchicalConfiguration)
256 */
257 public void doConfigure(HierarchicalConfiguration config) throws ConfigurationException {
258 algo = config.getString("algorithm", "MD5");
259 super.doConfigure(config);
260 }
261
262 /**
263 * Return a new {@link EntityManager} instance
264 *
265 * @return manager
266 */
267 private EntityManager createEntityManager() {
268 return entityManagerFactory.createEntityManager();
269 }
270
271 /**
272 * @see
273 * org.apache.james.user.lib.AbstractUsersRepository#doAddUser(java.lang.String, java.lang.String)
274 */
275 protected void doAddUser(String username, String password) throws UsersRepositoryException {
276 String lowerCasedUsername = username.toLowerCase();
277 if (contains(lowerCasedUsername)) {
278 throw new UsersRepositoryException(lowerCasedUsername + " already exists.");
279 }
280 EntityManager entityManager = entityManagerFactory.createEntityManager();
281 final EntityTransaction transaction = entityManager.getTransaction();
282 try {
283 transaction.begin();
284 JPAUser user = new JPAUser(lowerCasedUsername, password, algo);
285 entityManager.persist(user);
286 transaction.commit();
287 } catch (PersistenceException e) {
288 getLogger().debug("Failed to save user", e);
289 if (transaction.isActive()) {
290 transaction.rollback();
291 }
292 throw new UsersRepositoryException("Failed to add user" + username, e);
293 } finally {
294 entityManager.close();
295 }
296 }
297
298 }