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 package org.apache.james.user.hbase;
020
021 import java.io.IOException;
022 import java.util.ArrayList;
023 import java.util.Iterator;
024 import java.util.List;
025
026 import org.apache.commons.configuration.ConfigurationException;
027 import org.apache.commons.configuration.HierarchicalConfiguration;
028 import org.apache.hadoop.hbase.KeyValue;
029 import org.apache.hadoop.hbase.client.Delete;
030 import org.apache.hadoop.hbase.client.Get;
031 import org.apache.hadoop.hbase.client.HTable;
032 import org.apache.hadoop.hbase.client.Put;
033 import org.apache.hadoop.hbase.client.Result;
034 import org.apache.hadoop.hbase.client.ResultScanner;
035 import org.apache.hadoop.hbase.client.Scan;
036 import org.apache.hadoop.hbase.util.Bytes;
037 import org.apache.james.system.hbase.TablePool;
038 import org.apache.james.user.api.UsersRepositoryException;
039 import org.apache.james.user.api.model.User;
040 import org.apache.james.user.hbase.def.HUsersRepository;
041 import org.apache.james.user.lib.AbstractUsersRepository;
042 import org.apache.james.user.lib.model.DefaultUser;
043 import org.slf4j.Logger;
044 import org.slf4j.LoggerFactory;
045
046 /**
047 * Implementation of the UserRepository for a HBase persistence.
048 */
049 public class HBaseUsersRepository extends AbstractUsersRepository {
050
051 /**
052 * The Logger.
053 */
054 private static Logger log = LoggerFactory.getLogger(HBaseUsersRepository.class.getName());
055
056 /**
057 * Hashing algorithm for the password.
058 */
059 private String algo;
060
061 /**
062 * @see org.apache.james.user.lib.AbstractUsersRepository#doConfigure(HierarchicalConfiguration)
063 */
064 public void doConfigure(HierarchicalConfiguration config) throws ConfigurationException {
065 algo = config.getString("algorithm", "MD5");
066 super.doConfigure(config);
067 }
068
069 /**
070 * @see org.apache.james.user.api.UsersRepository#getUserByName(String)
071 */
072 @Override
073 public User getUserByName(String name) throws UsersRepositoryException {
074 KeyValue keyValue = getKeyValue(name);
075 User user = null;
076 if (keyValue != null) {
077 user = new DefaultUser(Bytes.toString(keyValue.getRow()), Bytes.toString(keyValue.getValue()), algo);
078 }
079 return user;
080 }
081
082 /**
083 * @see org.apache.james.user.api.UsersRepository#updateUser(User)
084 */
085 @Override
086 public void updateUser(User user) throws UsersRepositoryException {
087 if (user == null) {
088 throw new UsersRepositoryException("Please provide a non null user");
089 }
090 if (! (user instanceof DefaultUser)) {
091 throw new UsersRepositoryException("Please provide a user instanceof DefaultUser");
092 }
093 User existingUser = getUserByName(user.getUserName());
094 if (existingUser == null) {
095 throw new UsersRepositoryException("Please provide an existing user to update");
096 }
097 putUser((DefaultUser) user, false);
098 }
099
100 /**
101 * @see org.apache.james.user.api.UsersRepository#removeUser(String)
102 */
103 @Override
104 public void removeUser(String name) throws UsersRepositoryException {
105 HTable table = null;
106 try {
107 table = TablePool.getInstance().getUsersRepositoryTable();
108 Delete delete = new Delete(Bytes.toBytes(name));
109 table.delete(delete);
110 table.flushCommits();
111 } catch (IOException e) {
112 log.error("Error while deleting user from HBase", e);
113 throw new UsersRepositoryException("Error while deleting user from HBase", e);
114 } finally {
115 if (table != null) {
116 try {
117 TablePool.getInstance().putTable(table);
118 } catch (IOException e) {
119 // Do nothing, we can't get access to the HBaseSchema.
120 }
121 }
122 }
123 }
124
125 /**
126 * @see org.apache.james.user.api.UsersRepository#contains(String)
127 */
128 @Override
129 public boolean contains(String name) throws UsersRepositoryException {
130 KeyValue keyValue = getKeyValue(name.toLowerCase());
131 return (keyValue != null);
132 }
133
134 /**
135 * @see org.apache.james.user.api.UsersRepository#test(String, String)
136 */
137 @Override
138 public boolean test(String name, String password) throws UsersRepositoryException {
139 KeyValue keyValue = getKeyValue(name);
140 if (keyValue != null) {
141 DefaultUser user = new DefaultUser(name, algo);
142 user.setPassword(password);
143 return Bytes.toString(keyValue.getValue()).equals(user.getHashedPassword());
144 }
145 return false;
146 }
147
148 /**
149 * @see org.apache.james.user.api.UsersRepository#countUsers()
150 */
151 @Override
152 public int countUsers() throws UsersRepositoryException {
153 HTable table = null;
154 ResultScanner resultScanner = null;
155 try {
156 table = TablePool.getInstance().getUsersRepositoryTable();
157 Scan scan = new Scan();
158 scan.addFamily(HUsersRepository.COLUMN_FAMILY_NAME);
159 scan.setCaching(table.getScannerCaching() * 2);
160 resultScanner = table.getScanner(scan);
161 int resultCount = 0;
162 Result result = null;
163 while ((result = resultScanner.next()) != null) {
164 resultCount++;
165 }
166 return resultCount;
167 } catch (IOException e) {
168 log.error("Error while counting users from HBase", e);
169 throw new UsersRepositoryException("Error while counting users from HBase", e);
170 } finally {
171 if (resultScanner != null) {
172 resultScanner.close();
173 }
174 if (table != null) {
175 try {
176 TablePool.getInstance().putTable(table);
177 } catch (IOException e) {
178 // Do nothing, we can't get access to the HBaseSchema.
179 }
180 }
181 }
182 }
183
184 /**
185 * @see org.apache.james.user.api.UsersRepository#list()
186 */
187 @Override
188 public Iterator<String> list() throws UsersRepositoryException {
189 List<String> list = new ArrayList<String>();
190 HTable table = null;
191 ResultScanner resultScanner = null;
192 try {
193 table = TablePool.getInstance().getUsersRepositoryTable();
194 Scan scan = new Scan();
195 scan.addFamily(HUsersRepository.COLUMN_FAMILY_NAME);
196 scan.setCaching(table.getScannerCaching() * 2);
197 resultScanner = table.getScanner(scan);
198 Result result = null;
199 while ((result = resultScanner.next()) != null) {
200 list.add(Bytes.toString(result.getRow()));
201 }
202 } catch (IOException e) {
203 log.error("Error while scanning users from HBase", e);
204 throw new UsersRepositoryException("Error while scanning users from HBase", e);
205 } finally {
206 if (resultScanner != null) {
207 resultScanner.close();
208 }
209 if (table != null) {
210 try {
211 TablePool.getInstance().putTable(table);
212 } catch (IOException e) {
213 // Do nothing, we can't get access to the HBaseSchema.
214 }
215 }
216 }
217 return list.iterator();
218 }
219
220 /**
221 * @see org.apache.james.user.lib.AbstractUsersRepository#doAddUser(String, String)
222 */
223 @Override
224 protected void doAddUser(String username, String password) throws UsersRepositoryException {
225 DefaultUser user = new DefaultUser(username, algo);
226 user.setPassword(password);
227 putUser(user, true);
228 }
229
230 /**
231 * Utility method to retrieve a HBase KeyValue for a given username.
232 *
233 * @param username
234 * @return
235 * @throws UsersRepositoryException
236 */
237 private KeyValue getKeyValue(String username) throws UsersRepositoryException {
238 HTable table = null;
239 try {
240 table = TablePool.getInstance().getUsersRepositoryTable();
241 Get get = new Get(Bytes.toBytes(username));
242 Result result = table.get(get);
243 KeyValue keyValue = result.getColumnLatest(HUsersRepository.COLUMN_FAMILY_NAME, HUsersRepository.COLUMN.PWD);
244 return keyValue;
245 } catch (IOException e) {
246 log.error("Error while counting users from HBase", e);
247 throw new UsersRepositoryException("Error while counting users from HBase", e);
248 } finally {
249 if (table != null) {
250 try {
251 TablePool.getInstance().putTable(table);
252 } catch (IOException e) {
253 // Do nothing, we can't get access to the HBaseSchema.
254 }
255 }
256 }
257 }
258
259 /**
260 * Utility method to put a User in HBase.
261 *
262 * @param user
263 * @throws UsersRepositoryException
264 */
265 private void putUser(DefaultUser user, boolean isAdd) throws UsersRepositoryException {
266 String username = user.getUserName();
267 if (isAdd) {
268 username = user.getUserName().toLowerCase();
269 if (contains(username)) {
270 throw new UsersRepositoryException(username + " already exists.");
271 }
272 }
273 HTable table = null;
274 try {
275 table = TablePool.getInstance().getUsersRepositoryTable();
276 Put put = new Put(Bytes.toBytes(username));
277 put.add(HUsersRepository.COLUMN_FAMILY_NAME, HUsersRepository.COLUMN.PWD, Bytes.toBytes(user.getHashedPassword()));
278 table.put(put);
279 table.flushCommits();
280 } catch (IOException e) {
281 log.error("Error while adding user in HBase", e);
282 throw new UsersRepositoryException("Error while adding user in HBase", e);
283 } finally {
284 if (table != null) {
285 try {
286 TablePool.getInstance().putTable(table);
287 } catch (IOException e) {
288 // Do nothing, we can't get access to the HBaseSchema.
289 }
290 }
291 }
292 }
293
294 }