001: /*
002: * NEMESIS-FORUM.
003: * Copyright (C) 2002 David Laurent(lithium2@free.fr). All rights reserved.
004: *
005: * Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
006: *
007: * Copyright (C) 2001 Yasna.com. All rights reserved.
008: *
009: * Copyright (C) 2000 CoolServlets.com. All rights reserved.
010: *
011: * NEMESIS-FORUM. is free software; you can redistribute it and/or
012: * modify it under the terms of the Apache Software License, Version 1.1,
013: * or (at your option) any later version.
014: *
015: * NEMESIS-FORUM core framework, NEMESIS-FORUM backoffice, NEMESIS-FORUM frontoffice
016: * application are parts of NEMESIS-FORUM and are distributed under
017: * same terms of licence.
018: *
019: *
020: * NEMESIS-FORUM includes software developed by the Apache Software Foundation (http://www.apache.org/)
021: * and software developed by CoolServlets.com (http://www.coolservlets.com).
022: * and software developed by Yasna.com (http://www.yasna.com).
023: *
024: */
025: package org.nemesis.forum.impl;
026:
027: import java.sql.Connection;
028: import java.sql.PreparedStatement;
029: import java.sql.ResultSet;
030: import java.sql.SQLException;
031: import java.util.Enumeration;
032: import java.util.Properties;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.nemesis.forum.Authorization;
037: import org.nemesis.forum.ForumPermissions;
038: import org.nemesis.forum.Group;
039: import org.nemesis.forum.User;
040: import org.nemesis.forum.exception.UnauthorizedException;
041: import org.nemesis.forum.exception.UserNotFoundException;
042: import org.nemesis.forum.util.StringUtils;
043: import org.nemesis.forum.util.cache.CacheSizes;
044: import org.nemesis.forum.util.cache.Cacheable;
045: import org.nemesis.forum.util.jdbc.DbConnectionManager;
046:
047: /**
048: * Database implementation of the User interface. Additionally, it filters all
049: * HTML tags from fields before returning them for security purposes.<p>
050: *
051: * Use of the user system is optional. There a number of different ways
052: * to create your own user system or to integrate into an existing user
053: * system:<ul>
054: * <li> Edit the source of this class and modify the database queries to match
055: * your user system.
056: * <li> Implement a set of custom classes and tell the ForumFactory to load
057: * them. In this case, it is still recommended to use the user API
058: * since that will mean much less reimplementation work in the other
059: * classes.</ul>
060: *
061: * If you can follow the API for your own user data, but need access
062: * within to extended user properties, such as addresses or other
063: * personal data, and easy solution is to adapt the user properties facility
064: * to load and access this data.
065: */
066: class DbUser implements User, Cacheable {
067: static protected Log log = LogFactory.getLog(DbUser.class);
068: /** DATABASE QUERIES **/
069: private static final String LOAD_PROPERTIES = "SELECT name, propValue FROM yazdUserProp WHERE userID=?";
070: private static final String DELETE_PROPERTIES = "DELETE FROM yazdUserProp WHERE userID=?";
071: private static final String INSERT_PROPERTY = "INSERT INTO yazdUserProp(userID,name,propValue) VALUES(?,?,?)";
072: private static final String LOAD_USER_BY_USERNAME = "SELECT * FROM yazdUser WHERE username=?";
073: private static final String LOAD_USER_BY_ID = "SELECT * FROM yazdUser WHERE userID=?";
074: private static final String INSERT_USER = "INSERT INTO yazdUser(userID,username,passwordHash,email,emailVisible,"
075: + "nameVisible) VALUES(?,?,?,?,?,?)";
076: private static final String SAVE_USER = "UPDATE yazdUser SET passwordHash=?,email=?,emailVisible=?,name=?,"
077: + "nameVisible=? WHERE userID=?";
078: private static final String DELETE_PERMISSIONS = "DELETE FROM yazdUserPerm WHERE userID=?";
079: private static final String INSERT_PERMISSION = "INSERT INTO yazdUserPerm(userID,forumID,permission) VALUES(?,?,?)";
080:
081: //********ajout
082: private static final String ADMIN_TEST = "SELECT groupID FROM yazdGroupUser WHERE groupID=? AND userID=? AND "
083: + "administrator=1";
084: private static final String MEMBER_TEST = "SELECT groupID FROM yazdGroupUser WHERE groupID=? AND userID=?";
085: private static final String ADMIN_COUNT = "SELECT count(*) FROM yazdGroupUser WHERE userID=? "
086: + "AND administrator=1";
087: private static final String MEMBER_COUNT = "SELECT DISTINCT count(groupID) FROM yazdGroupUser "
088: + "WHERE userID=?";
089:
090: /**
091: * user id of -2 means no user id has been set yet. -1 is reserved for
092: * "anonymous user" and 0 is reserved for "all users".
093: */
094: private int id = -2;
095: private String username;
096: private String passwordHash;
097: private String name = "";
098: private boolean nameVisible = true;
099: private String email;
100: private boolean emailVisible = true;
101: private Properties properties;
102: private Object propertyLock = new Object();
103:
104: /**
105: * Create a new DbUser with all required fields.
106: *
107: * @param username the username for the user.
108: * @param password a password for the user.
109: * @param email the email address for the user.
110: */
111: protected DbUser(String username, String password, String email) {
112: this .id = DbSequenceManager.nextID("User");
113: this .username = username;
114: //Compute hash of password.
115: this .passwordHash = StringUtils.hash(password);
116: this .email = email;
117: properties = new Properties();
118: insertIntoDb();
119: }
120:
121: /**
122: * Load a DbUser object specified by userID.
123: *
124: * @param userID the userID of the user to load.
125: */
126: protected DbUser(int userID) throws UserNotFoundException {
127: this .id = userID;
128: loadFromDb();
129: loadProperties();
130: }
131:
132: /**
133: * Load a DbUser object specified by username.
134: *
135: * @param username the username of the user to load.
136: */
137: protected DbUser(String username) throws UserNotFoundException {
138: this .username = username;
139: loadFromDb();
140: loadProperties();
141: }
142:
143: //FROM THE USER INTERFACE//
144:
145: public int getID() {
146: return id;
147: }
148:
149: public boolean isAnonymous() {
150: return (id == -1);
151: }
152:
153: public String getUsername() {
154: return StringUtils.escapeHTMLTags(username);
155: }
156:
157: public String getName() {
158: return StringUtils.escapeHTMLTags(name);
159: }
160:
161: public void setName(String name) throws UnauthorizedException {
162: this .name = name;
163: saveToDb();
164: }
165:
166: public boolean isNameVisible() {
167: return nameVisible;
168: }
169:
170: public void setNameVisible(boolean visible)
171: throws UnauthorizedException {
172: this .nameVisible = visible;
173: saveToDb();
174: }
175:
176: public void setPassword(String password)
177: throws UnauthorizedException {
178: //Compute hash of password.
179: this .passwordHash = StringUtils.hash(password);
180: saveToDb();
181: }
182:
183: public String getPasswordHash() throws UnauthorizedException {
184: return passwordHash;
185: }
186:
187: public void setPasswordHash(String passwordHash) {
188: this .passwordHash = passwordHash;
189: saveToDb();
190: }
191:
192: public String getEmail() {
193: return StringUtils.escapeHTMLTags(email);
194: }
195:
196: public void setEmail(String email) throws UnauthorizedException {
197: this .email = email;
198: saveToDb();
199: }
200:
201: public boolean isEmailVisible() {
202: return emailVisible;
203: }
204:
205: public void setEmailVisible(boolean visible)
206: throws UnauthorizedException {
207: this .emailVisible = visible;
208: saveToDb();
209: }
210:
211: public String getProperty(String name) {
212: return StringUtils
213: .escapeHTMLTags((String) properties.get(name));
214: }
215:
216: public Enumeration propertyNames() {
217: return properties.propertyNames();
218: }
219:
220: public void setProperty(String name, String value) {
221: properties.put(name, value);
222: saveProperties();
223: }
224:
225: public ForumPermissions getPermissions(Authorization authorization) {
226: if (authorization.getUserID() == id || id == -1 || id == 0) {
227: return new ForumPermissions(false, false, false, true,
228: false, false, false, false);
229: } else {
230: return ForumPermissions.none();
231: }
232: }
233:
234: public boolean hasPermission(int type) {
235: return true;
236: }
237:
238: //FROM THE CACHEABLE INTERFACE//
239:
240: public int getSize() {
241: //Approximate the size of the object in bytes by calculating the size
242: //of each field.
243: int size = 0;
244: size += CacheSizes.sizeOfObject(); //overhead of object
245: size += CacheSizes.sizeOfInt(); //id
246: size += CacheSizes.sizeOfString(username); //username
247: size += CacheSizes.sizeOfString(passwordHash); //password
248: size += CacheSizes.sizeOfString(name); //name
249: size += CacheSizes.sizeOfString(email); //email
250: size += CacheSizes.sizeOfBoolean(); //nameVisible
251: size += CacheSizes.sizeOfBoolean(); //emailVisible
252: size += CacheSizes.sizeOfObject(); //property lock
253: size += CacheSizes.sizeOfProperties(properties); //properties object
254:
255: return size;
256: }
257:
258: //******AJOUT
259: public boolean isAdministratorInGroup(Group group) {
260: boolean answer = false;
261: Connection con = null;
262: PreparedStatement pstmt = null;
263: try {
264: con = DbConnectionManager.getConnection();
265: pstmt = con.prepareStatement(ADMIN_TEST);
266: pstmt.setInt(1, group.getID());
267: pstmt.setInt(2, id);
268: ResultSet rs = pstmt.executeQuery();
269: if (rs.next()) {
270: answer = true;
271: }
272: } catch (SQLException sqle) {
273: log.error("", sqle);
274: } finally {
275: try {
276: pstmt.close();
277: } catch (Exception e) {
278: log.error("", e);
279: }
280: try {
281: con.close();
282: } catch (Exception e) {
283: log.error("", e);
284: }
285: }
286: return answer;
287: }
288:
289: public boolean isMemberInGroup(Group group) {
290: boolean answer = false;
291: Connection con = null;
292: PreparedStatement pstmt = null;
293: try {
294: con = DbConnectionManager.getConnection();
295: pstmt = con.prepareStatement(MEMBER_TEST);
296: pstmt.setInt(1, group.getID());
297: pstmt.setInt(2, id);
298: ResultSet rs = pstmt.executeQuery();
299: if (rs.next()) {
300: answer = true;
301: }
302: } catch (SQLException sqle) {
303: log.error("", sqle);
304: } finally {
305: try {
306: pstmt.close();
307: } catch (Exception e) {
308: log.error("", e);
309: }
310: try {
311: con.close();
312: } catch (Exception e) {
313: log.error("", e);
314: }
315: }
316: return answer;
317: }
318:
319: public int getGroupAdministratorCount() {
320: int count = 0;
321: boolean answer = false;
322: Connection con = null;
323: PreparedStatement pstmt = null;
324: try {
325: con = DbConnectionManager.getConnection();
326: pstmt = con.prepareStatement(ADMIN_COUNT);
327: pstmt.setInt(1, id);
328: ResultSet rs = pstmt.executeQuery();
329: if (rs.next()) {
330: count = rs.getInt(1);
331: }
332: } catch (SQLException sqle) {
333: log.error("", sqle);
334: } finally {
335: try {
336: pstmt.close();
337: } catch (Exception e) {
338: log.error("", e);
339: }
340: try {
341: con.close();
342: } catch (Exception e) {
343: log.error("", e);
344: }
345: }
346: return count;
347: }
348:
349: public int getGroupCount() {
350: int count = 0;
351: boolean answer = false;
352: Connection con = null;
353: PreparedStatement pstmt = null;
354: try {
355: con = DbConnectionManager.getConnection();
356: pstmt = con.prepareStatement(MEMBER_COUNT);
357: pstmt.setInt(1, id);
358: ResultSet rs = pstmt.executeQuery();
359: if (rs.next()) {
360: count = rs.getInt(1);
361: }
362: } catch (SQLException sqle) {
363: log.error("", sqle);
364: } finally {
365: try {
366: pstmt.close();
367: } catch (Exception e) {
368: log.error("", e);
369: }
370: try {
371: con.close();
372: } catch (Exception e) {
373: log.error("", e);
374: }
375: }
376: return count;
377: }
378:
379: //-------
380:
381: //OTHER METHODS
382:
383: /**
384: * Returns a String representation of the User object using the username.
385: *
386: * @return a String representation of the User object.
387: */
388: public String toString() {
389: return username;
390: }
391:
392: public int hashCode() {
393: return id;
394: }
395:
396: public boolean equals(Object object) {
397: if (this == object) {
398: return true;
399: }
400: if (object != null && object instanceof DbUser) {
401: return id == ((DbUser) object).getID();
402: } else {
403: return false;
404: }
405: }
406:
407: /**
408: * Loads user properties from the database.
409: */
410: private void loadProperties() {
411: //If "anonymous" or "all users", do nothing.
412: if (id == -1 || id == 0) {
413: properties = new Properties();
414: return;
415: }
416: //Acquire a lock so that no other property loading or saving can be
417: //performed at the same time.
418: synchronized (propertyLock) {
419: Properties newProps = new Properties();
420: Connection con = null;
421: PreparedStatement pstmt = null;
422: try {
423: con = DbConnectionManager.getConnection();
424: pstmt = con.prepareStatement(LOAD_PROPERTIES);
425: pstmt.setInt(1, id);
426: ResultSet rs = pstmt.executeQuery();
427: while (rs.next()) {
428: String name = rs.getString("name");
429: String value = rs.getString("propValue");
430: newProps.put(name, value);
431: }
432: } catch (SQLException sqle) {
433: log.error("Error in DbUser:loadProperties():", sqle);
434:
435: } finally {
436: try {
437: pstmt.close();
438: } catch (Exception e) {
439: log.error("", e);
440: }
441: try {
442: con.close();
443: } catch (Exception e) {
444: log.error("", e);
445: }
446: }
447: this .properties = newProps;
448: }
449: }
450:
451: /**
452: * Saves user properties to the database.
453: */
454: private void saveProperties() {
455: //If "anonymous" or "all users", do nothing.
456: if (id == -1 || id == 0) {
457: return;
458: }
459: //Acquire a lock so that no other property loading or saving can be
460: //performed at the same time.
461: synchronized (propertyLock) {
462: Connection con = null;
463: PreparedStatement pstmt = null;
464: try {
465: con = DbConnectionManager.getConnection();
466: //Delete all old values.
467: pstmt = con.prepareStatement(DELETE_PROPERTIES);
468: pstmt.setInt(1, id);
469: pstmt.execute();
470: pstmt.close();
471: //Now insert new values.
472: pstmt = con.prepareStatement(INSERT_PROPERTY);
473: Enumeration e = properties.keys();
474: while (e.hasMoreElements()) {
475: String name = (String) e.nextElement();
476: String value = (String) properties.get(name);
477: pstmt.setInt(1, id);
478: pstmt.setString(2, name);
479: pstmt.setString(3, value);
480: pstmt.executeUpdate();
481: }
482: } catch (SQLException sqle) {
483: log.error("", sqle);
484: } finally {
485: try {
486: pstmt.close();
487: } catch (Exception e) {
488: log.error("", e);
489: }
490: try {
491: con.close();
492: } catch (Exception e) {
493: log.error("", e);
494: }
495: }
496: }
497: }
498:
499: /**
500: * Load the user data from the database.
501: */
502: private void loadFromDb() throws UserNotFoundException {
503: //If the user is anonymous or "all users", do nothing.
504: if (id == -1 || id == 0) {
505: return;
506: }
507: // Otherwise, select user data from User table and fill in relevant fields.
508: String query;
509: //We may want to do a username lookup.
510: if (username != null) {
511: query = LOAD_USER_BY_USERNAME;
512: }
513: //Otherwise, a lookup by id
514: else {
515: query = LOAD_USER_BY_ID;
516: }
517: Connection con = null;
518: PreparedStatement pstmt = null;
519: try {
520: con = DbConnectionManager.getConnection();
521: pstmt = con.prepareStatement(query);
522: if (username != null) {
523: pstmt.setString(1, username);
524: } else {
525: pstmt.setInt(1, id);
526: }
527:
528: ResultSet rs = pstmt.executeQuery();
529: if (!rs.next()) {
530: throw new UserNotFoundException("Failed to read user "
531: + id + " from database.");
532: }
533: this .id = rs.getInt("userID");
534: this .username = rs.getString("username");
535: this .passwordHash = rs.getString("passwordHash");
536: this .name = rs.getString("name");
537: this .nameVisible = (rs.getInt("nameVisible") == 1);
538: this .email = rs.getString("email");
539: this .emailVisible = (rs.getInt("emailVisible") == 1);
540: } catch (SQLException sqle) {
541: throw new UserNotFoundException("Failed to read user " + id
542: + " from database.", sqle);
543: } finally {
544: try {
545: pstmt.close();
546: } catch (Exception e) {
547: log.error("", e);
548: }
549: try {
550: con.close();
551: } catch (Exception e) {
552: log.error("", e);
553: }
554: }
555: }
556:
557: /**
558: * Inserts a new user record into the database.
559: */
560: private void insertIntoDb() {
561: Connection con = null;
562: PreparedStatement pstmt = null;
563: try {
564: con = DbConnectionManager.getConnection();
565: pstmt = con.prepareStatement(INSERT_USER);
566: pstmt.setInt(1, id);
567: pstmt.setString(2, username);
568: pstmt.setString(3, passwordHash);
569: pstmt.setString(4, email);
570: pstmt.setInt(5, emailVisible ? 1 : 0);
571: pstmt.setInt(6, nameVisible ? 1 : 0);
572: pstmt.executeUpdate();
573: } catch (SQLException sqle) {
574: log.error("Error in DbUser:insertIntoDb()-", sqle);
575:
576: } finally {
577: try {
578: pstmt.close();
579: } catch (Exception e) {
580: log.error("", e);
581: }
582: try {
583: con.close();
584: } catch (Exception e) {
585: log.error("", e);
586: }
587: }
588: }
589:
590: /**
591: * Save the user data to the database.
592: */
593: private void saveToDb() {
594: if (id == -1 || id == 0) {
595: //"anonymous" or "all users", do nothing
596: return;
597: }
598: Connection con = null;
599: PreparedStatement pstmt = null;
600: try {
601: con = DbConnectionManager.getConnection();
602: pstmt = con.prepareStatement(SAVE_USER);
603: pstmt.setString(1, passwordHash);
604: pstmt.setString(2, email);
605: pstmt.setInt(3, emailVisible ? 1 : 0);
606: pstmt.setString(4, name);
607: pstmt.setInt(5, nameVisible ? 1 : 0);
608: pstmt.setInt(6, id);
609: pstmt.executeUpdate();
610: } catch (SQLException sqle) {
611: log.error("SQLException in DbUser.java:saveToDb(): ", sqle);
612:
613: } finally {
614: try {
615: pstmt.close();
616: } catch (Exception e) {
617: log.error("", e);
618: }
619: try {
620: con.close();
621: } catch (Exception e) {
622: log.error("", e);
623: }
624: }
625: }
626: }
|