0001: /*
0002: * NEMESIS-FORUM.
0003: * Copyright (C) 2002 David Laurent(lithium2@free.fr). All rights reserved.
0004: *
0005: * Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
0006: *
0007: * Copyright (C) 2001 Yasna.com. All rights reserved.
0008: *
0009: * Copyright (C) 2000 CoolServlets.com. All rights reserved.
0010: *
0011: * NEMESIS-FORUM. is free software; you can redistribute it and/or
0012: * modify it under the terms of the Apache Software License, Version 1.1,
0013: * or (at your option) any later version.
0014: *
0015: * NEMESIS-FORUM core framework, NEMESIS-FORUM backoffice, NEMESIS-FORUM frontoffice
0016: * application are parts of NEMESIS-FORUM and are distributed under
0017: * same terms of licence.
0018: *
0019: *
0020: * NEMESIS-FORUM includes software developed by the Apache Software Foundation (http://www.apache.org/)
0021: * and software developed by CoolServlets.com (http://www.coolservlets.com).
0022: * and software developed by Yasna.com (http://www.yasna.com).
0023: *
0024: */
0025: package org.nemesis.forum.impl;
0026:
0027: import java.io.ByteArrayOutputStream;
0028: import java.io.ObjectInputStream;
0029: import java.io.ObjectOutputStream;
0030: import java.sql.Connection;
0031: import java.sql.PreparedStatement;
0032: import java.sql.ResultSet;
0033: import java.sql.SQLException;
0034: import java.util.ArrayList;
0035: import java.util.Date;
0036: import java.util.Enumeration;
0037: import java.util.Iterator;
0038: import java.util.Properties;
0039:
0040: import org.apache.commons.logging.Log;
0041: import org.apache.commons.logging.LogFactory;
0042: import org.nemesis.forum.Authorization;
0043: import org.nemesis.forum.Forum;
0044: import org.nemesis.forum.ForumPermissions;
0045: import org.nemesis.forum.ForumThread;
0046: import org.nemesis.forum.Group;
0047: import org.nemesis.forum.Message;
0048: import org.nemesis.forum.MessageFilter;
0049: import org.nemesis.forum.User;
0050: import org.nemesis.forum.config.Constants;
0051: import org.nemesis.forum.exception.ForumMessageNotFoundException;
0052: import org.nemesis.forum.exception.ForumNotFoundException;
0053: import org.nemesis.forum.exception.ForumThreadNotFoundException;
0054: import org.nemesis.forum.exception.UnauthorizedException;
0055: import org.nemesis.forum.filter.FilterHtml;
0056: import org.nemesis.forum.filter.FilterNewline;
0057: import org.nemesis.forum.proxy.ForumThreadProxy;
0058: import org.nemesis.forum.proxy.MessageProxy;
0059: import org.nemesis.forum.util.cache.Cache;
0060: import org.nemesis.forum.util.cache.CacheSizes;
0061: import org.nemesis.forum.util.cache.Cacheable;
0062: import org.nemesis.forum.util.jdbc.DbConnectionManager;
0063:
0064: /**
0065: * Database implementation of the Forum interface. It loads and stores forum
0066: * information from a a database.
0067: *
0068: * @see Forum
0069: */
0070: public class DbForum implements Forum, Cacheable {
0071:
0072: static protected Log log = LogFactory.getLog(DbForum.class);
0073: /** DATABASE QUERIES **/
0074: private static final String ADD_THREAD = "UPDATE yazdThread set forumID=? WHERE threadID=?";
0075: protected static final String DELETE_THREAD = "DELETE FROM yazdThread WHERE threadID=?";
0076: private static final String THREAD_COUNT = "SELECT count(*) FROM yazdThread WHERE forumID=?";
0077: private static final String MESSAGE_COUNT = "SELECT count(*) FROM yazdThread, yazdMessage WHERE "
0078: + "yazdThread.forumID=? AND yazdThread.threadID=yazdMessage.threadID";
0079: private static final String ADD_USER_PERM = "INSERT INTO yazdUserPerm(forumID,userID,permission) VALUES(?,?,?)";
0080: private static final String REMOVE_USER_PERM = "DELETE FROM yazdUserPerm WHERE forumID=? AND userID=? AND permission=?";
0081: private static final String USERS_WITH_PERM = "SELECT DISTINCT userID FROM yazdUserPerm WHERE forumID=? AND permission=?";
0082: private static final String ADD_GROUP_PERM = "INSERT INTO yazdGroupPerm(forumID,groupID,permission) VALUES(?,?,?)";
0083: private static final String REMOVE_GROUP_PERM = "DELETE FROM yazdGroupPerm WHERE forumID=? AND groupID=? AND permission=?";
0084: private static final String GROUPS_WITH_PERM = "SELECT DISTINCT groupID FROM yazdGroupPerm WHERE forumID=? AND permission=?";
0085: private static final String LOAD_FILTERS = "SELECT filterObject, filterIndex FROM yazdFilter WHERE forumID=? ORDER BY filterIndex ASC";
0086: private static final String DELETE_FILTERS = "DELETE FROM yazdFilter WHERE forumID=?";
0087: private static final String ADD_FILTER = "INSERT INTO yazdFilter(forumID,filterIndex,filterObject) VALUES(?,?,?)";
0088: private static final String LOAD_PROPERTIES = "SELECT name, propValue FROM yazdForumProp WHERE forumID=?";
0089: private static final String DELETE_PROPERTIES = "DELETE FROM yazdForumProp WHERE forumID=?";
0090: private static final String INSERT_PROPERTY = "INSERT INTO yazdForumProp(forumID,name,propValue) VALUES(?,?,?)";
0091: private static final String LOAD_FORUM_BY_ID = "SELECT forumID, name, description, creationDate, modifiedDate, moderated FROM yazdForum WHERE forumID=?";
0092: private static final String LOAD_FORUM_BY_NAME = "SELECT forumID, name, description, creationDate, modifiedDate, moderated FROM yazdForum WHERE name=?";
0093: private static final String ADD_FORUM = "INSERT INTO yazdForum(forumID, name, description, creationDate, "
0094: + "modifiedDate, moderated) VALUES (?,?,?,?,?,?)";
0095: private static final String SAVE_FORUM = "UPDATE yazdForum SET name=?, description=?, creationDate=?, "
0096: + "modifiedDate=?, moderated=? WHERE forumID=?";
0097: private static final String UPDATE_FORUM_MODIFIED_DATE = "UPDATE yazdForum SET modifiedDate=? WHERE forumID=?";
0098:
0099: private static final String APPROVED_MESSAGE_COUNT = "SELECT count(*) FROM yazdThread, yazdMessage WHERE "
0100: + "yazdThread.forumID=? AND yazdMessage.approved=? AND yazdThread.threadID=yazdMessage.threadID";
0101: private static final String APPROVED_THREAD_COUNT = "SELECT count(*) FROM yazdThread WHERE forumID=? AND approved=? ";
0102:
0103: private int id = -1;
0104: private String name;
0105: private String description;
0106: private java.util.Date creationDate;
0107: private java.util.Date modifiedDate;
0108: private int moderation = 0;
0109: private MessageFilter[] filters;
0110: private Properties properties;
0111: //Lock for saving state to database.
0112: private Object saveLock = new Object();
0113:
0114: private DbForumFactory factory;
0115:
0116: /**
0117: * Creates a new forum with the specified name and description.
0118: *
0119: * @param name the name of the forum.
0120: * @param description the description of the forum.
0121: * @param factory the DbForumFactory the forum is a part of.
0122: */
0123: protected DbForum(String name, String description,
0124: DbForumFactory factory) {
0125: this .id = DbSequenceManager.nextID("Forum");
0126: this .name = name;
0127: this .description = description;
0128: long now = System.currentTimeMillis();
0129: creationDate = new java.util.Date(now);
0130: modifiedDate = new java.util.Date(now);
0131: this .factory = factory;
0132: insertIntoDb();
0133: properties = new Properties();
0134: //Forums should start with an html filter by default for
0135: //security purposes.
0136: filters = new MessageFilter[2];
0137: filters[0] = new FilterHtml();
0138: filters[1] = new FilterNewline();
0139: saveFiltersToDb();
0140: //**Commenting out below since it doesn't seem to work for some reason.
0141: //try {
0142: // addForumMessageFilter(new FilterHtml(), 0);
0143: // addForumMessageFilter(new FilterNewline(), 1);
0144: //}
0145: //catch (UnauthorizedException ue) {
0146: //
0147: //}
0148: }
0149:
0150: /**
0151: * Loads a forum with the specified id.
0152: */
0153: protected DbForum(int id, DbForumFactory factory)
0154: throws ForumNotFoundException {
0155: this .id = id;
0156: this .factory = factory;
0157: loadFromDb();
0158: loadFiltersFromDb();
0159: loadProperties();
0160: }
0161:
0162: /**
0163: * Loads a forum with the specified name.
0164: */
0165: protected DbForum(String name, DbForumFactory factory)
0166: throws ForumNotFoundException {
0167: this .name = name;
0168: this .factory = factory;
0169: loadFromDb();
0170: loadFiltersFromDb();
0171: loadProperties();
0172: }
0173:
0174: //FROM THE FORUM INTERFACE//
0175:
0176: public int getModerationType() {
0177: return moderation;
0178: }
0179:
0180: public void setModerationType(int type)
0181: throws UnauthorizedException {
0182: this .moderation = type;
0183: saveToDb();
0184: }
0185:
0186: public int getID() {
0187: return id;
0188: }
0189:
0190: public String getName() {
0191: return name;
0192: }
0193:
0194: public void setName(String name) throws UnauthorizedException {
0195: this .name = name;
0196: saveToDb();
0197: }
0198:
0199: public String getDescription() {
0200: return description;
0201: }
0202:
0203: public void setDescription(String description)
0204: throws UnauthorizedException {
0205: this .description = description;
0206: saveToDb();
0207: }
0208:
0209: public java.util.Date getCreationDate() {
0210: return creationDate;
0211: }
0212:
0213: public void setCreationDate(java.util.Date creationDate)
0214: throws UnauthorizedException {
0215: this .creationDate = creationDate;
0216: saveToDb();
0217: }
0218:
0219: public java.util.Date getModifiedDate() {
0220: return modifiedDate;
0221: }
0222:
0223: public void setModifiedDate(java.util.Date modifiedDate)
0224: throws UnauthorizedException {
0225: this .modifiedDate = modifiedDate;
0226: saveToDb();
0227: }
0228:
0229: public String getProperty(String name) {
0230: return (String) properties.get(name);
0231: }
0232:
0233: public void setProperty(String name, String value)
0234: throws UnauthorizedException {
0235: properties.put(name, value);
0236: saveProperties();
0237: }
0238:
0239: public Enumeration propertyNames() {
0240: return properties.keys();
0241: }
0242:
0243: public ForumThread createThread(Message rootMessage)
0244: throws UnauthorizedException {
0245: //If the forum is 'THREAD OR MESSAGE' moderated, the message is not automatically
0246: //approved.
0247: boolean approved = !(getModerationType() == Constants.MODERATION_MESSAGE || getModerationType() == Constants.MODERATION_THREAD);
0248: // message is root -->force moderation,architecture violation @see messageproxy !!!
0249: ((MessageProxy) rootMessage).setApproved2(approved);
0250: return new DbForumThread(rootMessage, approved, this , factory);
0251: }
0252:
0253: public Message createMessage(User user)
0254: throws UnauthorizedException {
0255: //If the forum is 'MESSAGE' moderated, the message is not automatically
0256: //approved.
0257: boolean approved = getModerationType() != Constants.MODERATION_MESSAGE;
0258: return new DbForumMessage(user, approved, factory);//---------:ICI:
0259: }
0260:
0261: public void addThread(ForumThread thread)
0262: throws UnauthorizedException {
0263: boolean abortTransaction = false;
0264: boolean supportsTransactions = false;
0265: //Add message to db
0266: Connection con = null;
0267: PreparedStatement pstmt = null;
0268: try {
0269: con = DbConnectionManager.getConnection();
0270: supportsTransactions = con.getMetaData()
0271: .supportsTransactions();
0272: if (supportsTransactions) {
0273: con.setAutoCommit(false);
0274: }
0275:
0276: pstmt = con.prepareStatement(ADD_THREAD);
0277: pstmt.setInt(1, id);
0278: pstmt.setInt(2, thread.getID());
0279: pstmt.executeUpdate();
0280: pstmt.close();
0281:
0282: //Now, insert the thread into the database.
0283: ((ForumThreadProxy) thread).insertIntoDb(con);
0284: } catch (Exception e) {
0285: log.error("", e);
0286: abortTransaction = true;
0287: return;
0288: } finally {
0289: try {
0290: if (supportsTransactions) {
0291: if (abortTransaction == true) {
0292: con.rollback();
0293: } else {
0294: con.commit();
0295: }
0296: }
0297: } catch (Exception e) {
0298: log.error("", e);
0299: }
0300: try {
0301: if (supportsTransactions) {
0302: con.setAutoCommit(true);
0303: }
0304: con.close();
0305: } catch (Exception e) {
0306: log.error("", e);
0307: }
0308: }
0309:
0310: //Since we added a thread, update the modified date of this thread.
0311: updateModifiedDate(thread.getModifiedDate());
0312: }
0313:
0314: public ForumThread getThread(int threadID)
0315: throws ForumThreadNotFoundException {
0316: return factory.getThread(threadID, this );
0317: }
0318:
0319: public Message getMessage(int messageID)
0320: throws ForumMessageNotFoundException {
0321: return factory.getMessage(messageID);
0322: }
0323:
0324: public void deleteThread(ForumThread thread)
0325: throws UnauthorizedException {
0326: //Delete all messages from the thread. Deleting the root
0327: //message will delete all submessages.
0328: Message message = thread.getRootMessage();
0329: thread.deleteMessage(message);
0330: }
0331:
0332: protected void deleteThreadRecord(int threadID) {
0333:
0334: //Delete the actual thread
0335: Connection con = null;
0336: PreparedStatement pstmt = null;
0337: try {
0338: con = DbConnectionManager.getConnection();
0339: pstmt = con.prepareStatement(DELETE_THREAD);
0340: pstmt.setInt(1, threadID);
0341: pstmt.execute();
0342: } catch (Exception sqle) {
0343: log.error("Error in DbForum:deleteThread()-" + sqle);
0344: } finally {
0345: try {
0346: pstmt.close();
0347: } catch (Exception e) {
0348: log.error("", e);
0349: }
0350: try {
0351: con.close();
0352: } catch (Exception e) {
0353: log.error("", e);
0354: }
0355: }
0356:
0357: //Now, delete from cache
0358: Integer threadIDInteger = new Integer(threadID);
0359: factory.getCacheManager().remove(DbCacheManager.THREAD_CACHE,
0360: threadIDInteger);
0361: }
0362:
0363: public void moveThread(ForumThread thread, Forum forum)
0364: throws UnauthorizedException {
0365: //Ensure that thread belongs to this forum
0366: if (thread.getForum().getID() != this .id) {
0367: throw new IllegalArgumentException(
0368: "The thread does not belong to this forum.");
0369: }
0370:
0371: //Modify the SQL record. Only the thread table has information about
0372: //forumID, so we only need to modify that record. The message records
0373: //underneath the thread can be left alone.
0374: Connection con = null;
0375: PreparedStatement pstmt = null;
0376: try {
0377: con = DbConnectionManager.getConnection();
0378: pstmt = con.prepareStatement(ADD_THREAD);
0379: pstmt.setInt(1, forum.getID());
0380: pstmt.setInt(2, thread.getID());
0381: pstmt.executeUpdate();
0382: pstmt.close();
0383: } catch (SQLException sqle) {
0384: log.error("Error in DbForum:addThread()-", sqle);
0385: return;
0386: } finally {
0387: try {
0388: pstmt.close();
0389: } catch (Exception e) {
0390: log.error("", e);
0391: }
0392: try {
0393: con.close();
0394: } catch (Exception e) {
0395: log.error("", e);
0396: }
0397: }
0398:
0399: DbCacheManager cacheManager = factory.getCacheManager();
0400: //SearchIndexer indexer = factory.getSearchIndexer();
0401:
0402: //Remove both forums from cache.
0403: Integer key = new Integer(this .id);
0404: cacheManager.remove(DbCacheManager.FORUM_CACHE, key);
0405: key = new Integer(forum.getID());
0406: cacheManager.remove(DbCacheManager.FORUM_CACHE, key);
0407:
0408: //Remove thread from cache.
0409: key = new Integer(thread.getID());
0410: cacheManager.remove(DbCacheManager.THREAD_CACHE, key);
0411:
0412: //Loop through all messages in thread
0413: Iterator messages = thread.messages();
0414: while (messages.hasNext()) {
0415: Message message = (Message) messages.next();
0416: //Remove each message from cache.
0417: key = new Integer(message.getID());
0418: cacheManager.remove(DbCacheManager.MESSAGE_CACHE, key);
0419: //Remove and re-add every message to the search index.
0420: // indexer.removeFromIndex(message);
0421: // indexer.addToIndex(message);
0422: }
0423:
0424: // Update the modified date of thread
0425: Date now = new Date();
0426: thread.setModifiedDate(now);
0427: // Update the modified date of forum thread is now in
0428: forum.setModifiedDate(now);
0429: }
0430:
0431: public Iterator threads() {
0432: return new DbForumIterator(this , factory);
0433: }
0434:
0435: public Iterator threads(int startIndex, int numResults) {
0436: return new DbForumIterator(this , factory, startIndex,
0437: numResults);
0438: }
0439:
0440: public Iterator threads(boolean approved) {
0441: return new DbForumIterator(this , factory, approved);
0442: }
0443:
0444: public Iterator threads(boolean approved, int startIndex,
0445: int numResults) {
0446: return new DbForumIterator(this , factory, startIndex,
0447: numResults, approved);
0448: }
0449:
0450: public int getThreadCount() {
0451: int threadCount = 0;
0452: // Based on the id in the object, get the thread data from the database:
0453: Connection con = null;
0454: PreparedStatement pstmt = null;
0455: try {
0456: con = DbConnectionManager.getConnection();
0457: pstmt = con.prepareStatement(THREAD_COUNT);
0458: pstmt.setInt(1, id);
0459: ResultSet rs = pstmt.executeQuery();
0460: rs.next();
0461: threadCount = rs.getInt(1 /*"threadCount"*/
0462: );
0463: } catch (SQLException sqle) {
0464: log.error("DbForum:getThreadCount() failed: ", sqle);
0465: } finally {
0466: try {
0467: pstmt.close();
0468: } catch (Exception e) {
0469: log.error("", e);
0470: }
0471: try {
0472: con.close();
0473: } catch (Exception e) {
0474: log.error("", e);
0475: }
0476: }
0477: return threadCount;
0478: }
0479:
0480: public int getThreadCount(boolean approved) {
0481: int threadCount = 0;
0482: // Based on the id in the object, get the thread data from the database:
0483: Connection con = null;
0484: PreparedStatement pstmt = null;
0485: try {
0486: con = DbConnectionManager.getConnection();
0487: pstmt = con.prepareStatement(APPROVED_THREAD_COUNT);
0488: pstmt.setInt(1, id);
0489: pstmt.setInt(2, approved ? 1 : 0);
0490: ResultSet rs = pstmt.executeQuery();
0491: rs.next();
0492: threadCount = rs.getInt(1 /*"threadCount"*/
0493: );
0494: } catch (SQLException sqle) {
0495: log.error("DbForum:getThreadCount() failed: ", sqle);
0496: } finally {
0497: try {
0498: pstmt.close();
0499: } catch (Exception e) {
0500: log.error("", e);
0501: }
0502: try {
0503: con.close();
0504: } catch (Exception e) {
0505: log.error("", e);
0506: }
0507: }
0508: return threadCount;
0509: }
0510:
0511: public int getMessageCount() {
0512: int messageCount = 0;
0513: Connection con = null;
0514: PreparedStatement pstmt = null;
0515: try {
0516: con = DbConnectionManager.getConnection();
0517: pstmt = con.prepareStatement(MESSAGE_COUNT);
0518: pstmt.setInt(1, id);
0519: ResultSet rs = pstmt.executeQuery();
0520: rs.next();
0521: messageCount = rs.getInt(1 /*"messageCount"*/
0522: );
0523: } catch (SQLException sqle) {
0524: log.error("DbForum:getMessageCount() failed: ", sqle);
0525: } finally {
0526: try {
0527: pstmt.close();
0528: } catch (Exception e) {
0529: log.error("", e);
0530: }
0531: try {
0532: con.close();
0533: } catch (Exception e) {
0534: log.error("", e);
0535: }
0536: }
0537: return messageCount;
0538: }
0539:
0540: public int getMessageCount(boolean approved) {
0541: int messageCount = 0;
0542: Connection con = null;
0543: PreparedStatement pstmt = null;
0544: try {
0545: con = DbConnectionManager.getConnection();
0546: pstmt = con.prepareStatement(APPROVED_MESSAGE_COUNT);
0547: pstmt.setInt(1, id);
0548: pstmt.setInt(2, approved ? 1 : 0);
0549: ResultSet rs = pstmt.executeQuery();
0550: rs.next();
0551: messageCount = rs.getInt(1 /*"messageCount"*/
0552: );
0553: } catch (SQLException sqle) {
0554: log.error("DbForum:getMessageCount() failed: ", sqle);
0555: } finally {
0556: try {
0557: pstmt.close();
0558: } catch (Exception e) {
0559: log.error("", e);
0560: }
0561: try {
0562: con.close();
0563: } catch (Exception e) {
0564: log.error("", e);
0565: }
0566: }
0567: return messageCount;
0568: }
0569:
0570: public void addUserPermission(User user, int permissionType)
0571: throws UnauthorizedException {
0572: Connection con = null;
0573: PreparedStatement pstmt = null;
0574: try {
0575: con = DbConnectionManager.getConnection();
0576: pstmt = con.prepareStatement(ADD_USER_PERM);
0577: pstmt.setInt(1, id);
0578: pstmt.setInt(2, user.getID());
0579: pstmt.setInt(3, permissionType);
0580: pstmt.execute();
0581: //Remove user permissions from cache since they've changed.
0582: factory.getCacheManager().removeUserPerm(
0583: new Integer(user.getID()), new Integer(id));
0584: } catch (SQLException sqle) {
0585: log.error("Error in DbForum.java:", sqle);
0586: } finally {
0587: try {
0588: pstmt.close();
0589: } catch (Exception e) {
0590: log.error("", e);
0591: }
0592: try {
0593: con.close();
0594: } catch (Exception e) {
0595: log.error("", e);
0596: }
0597: }
0598: }
0599:
0600: public void removeUserPermission(User user, int permissionType)
0601: throws UnauthorizedException {
0602: Connection con = null;
0603: PreparedStatement pstmt = null;
0604: try {
0605: con = DbConnectionManager.getConnection();
0606: pstmt = con.prepareStatement(REMOVE_USER_PERM);
0607: pstmt.setInt(1, id);
0608: pstmt.setInt(2, user.getID());
0609: pstmt.setInt(3, permissionType);
0610: pstmt.execute();
0611: //Remove user permissions from cache since they've changed.
0612: factory.getCacheManager().removeUserPerm(
0613: new Integer(user.getID()), new Integer(id));
0614: } catch (SQLException sqle) {
0615: log.error("Error in DbForum.java:", sqle);
0616: } finally {
0617: try {
0618: pstmt.close();
0619: } catch (Exception e) {
0620: log.error("Error in DbForum.java:", e);
0621: }
0622: try {
0623: con.close();
0624: } catch (Exception e) {
0625: log.error("Error in DbForum.java:", e);
0626: }
0627: }
0628: }
0629:
0630: public int[] usersWithPermission(int permissionType)
0631: throws UnauthorizedException {
0632: int[] users = new int[0];
0633: Connection con = null;
0634: PreparedStatement pstmt = null;
0635: try {
0636: con = DbConnectionManager.getConnection();
0637: pstmt = con.prepareStatement(USERS_WITH_PERM);
0638: pstmt.setInt(1, id);
0639: pstmt.setInt(2, permissionType);
0640: ResultSet rs = pstmt.executeQuery();
0641: ArrayList userList = new ArrayList();
0642: while (rs.next()) {
0643: userList.add(new Integer(rs.getInt("userID")));
0644: }
0645: users = new int[userList.size()];
0646: for (int i = 0; i < users.length; i++) {
0647: users[i] = ((Integer) userList.get(i)).intValue();
0648: }
0649: } catch (SQLException sqle) {
0650: log.error("Error in DbForum.java:", sqle);
0651:
0652: } finally {
0653: try {
0654: pstmt.close();
0655: } catch (Exception e) {
0656: log.error("Error in DbForum.java:", e);
0657: }
0658: try {
0659: con.close();
0660: } catch (Exception e) {
0661: log.error("Error in DbForum.java:", e);
0662: }
0663: }
0664: return users;
0665: }
0666:
0667: public void addGroupPermission(Group group, int permissionType)
0668: throws UnauthorizedException {
0669: Connection con = null;
0670: PreparedStatement pstmt = null;
0671: try {
0672: con = DbConnectionManager.getConnection();
0673: pstmt = con.prepareStatement(ADD_GROUP_PERM);
0674: pstmt.setInt(1, id);
0675: pstmt.setInt(2, group.getID());
0676: pstmt.setInt(3, permissionType);
0677: pstmt.execute();
0678: //Remove user permissions from cache since they've changed. Because
0679: //of the way that user perm cache is handled, it is easiest to
0680: //simply remove all the user perm cache for the forum. This is ok
0681: //since happens infrequently.
0682: factory.getCacheManager().remove(
0683: DbCacheManager.USER_PERMS_CACHE, new Integer(id));
0684: } catch (SQLException sqle) {
0685: log.error("Error in DbForum.java:", sqle);
0686: } finally {
0687: try {
0688: pstmt.close();
0689: } catch (Exception e) {
0690: log.error("Error in DbForum.java:", e);
0691: }
0692: try {
0693: con.close();
0694: } catch (Exception e) {
0695: log.error("Error in DbForum.java:", e);
0696: }
0697: }
0698: }
0699:
0700: public void removeGroupPermission(Group group, int permissionType)
0701: throws UnauthorizedException {
0702: Connection con = null;
0703: PreparedStatement pstmt = null;
0704: try {
0705: con = DbConnectionManager.getConnection();
0706: pstmt = con.prepareStatement(REMOVE_GROUP_PERM);
0707: pstmt.setInt(1, id);
0708: pstmt.setInt(2, group.getID());
0709: pstmt.setInt(3, permissionType);
0710: pstmt.execute();
0711: //Remove user permissions from cache since they've changed. Because
0712: //of the way that user perm cache is handled, it is easiest to
0713: //simply remove all the user perm cache for the forum. This is ok
0714: //since happens infrequently.
0715: factory.getCacheManager().remove(
0716: DbCacheManager.USER_PERMS_CACHE, new Integer(id));
0717: } catch (SQLException sqle) {
0718: log.error("Error in DbForum.java:", sqle);
0719:
0720: } finally {
0721: try {
0722: pstmt.close();
0723: } catch (Exception e) {
0724: log.error("Error in DbForum.java:", e);
0725: }
0726: try {
0727: con.close();
0728: } catch (Exception e) {
0729: log.error("Error in DbForum.java:", e);
0730: }
0731: }
0732: }
0733:
0734: public int[] groupsWithPermission(int permissionType)
0735: throws UnauthorizedException {
0736: int[] groups = new int[0];
0737: Connection con = null;
0738: PreparedStatement pstmt = null;
0739: try {
0740: con = DbConnectionManager.getConnection();
0741: pstmt = con.prepareStatement(GROUPS_WITH_PERM);
0742: pstmt.setInt(1, id);
0743: pstmt.setInt(2, permissionType);
0744: ResultSet rs = pstmt.executeQuery();
0745: ArrayList groupList = new ArrayList();
0746: while (rs.next()) {
0747: groupList.add(new Integer(rs.getInt("groupID")));
0748: }
0749: groups = new int[groupList.size()];
0750: for (int i = 0; i < groups.length; i++) {
0751: groups[i] = ((Integer) groupList.get(i)).intValue();
0752: }
0753: } catch (SQLException sqle) {
0754: log.error("Error in DbForum.groupsWithPermission:", sqle);
0755:
0756: } finally {
0757: try {
0758: pstmt.close();
0759: } catch (Exception e) {
0760: log.error("Error in DbForum.java:", e);
0761: }
0762: try {
0763: con.close();
0764: } catch (Exception e) {
0765: log.error("Error in DbForum.java:", e);
0766: }
0767: }
0768: return groups;
0769: }
0770:
0771: public Message applyFilters(Message message) {
0772: //Loop through filters and apply them
0773: for (int i = 0; i < filters.length; i++) {
0774: message = filters[i].clone(message);
0775: }
0776: return message;
0777: }
0778:
0779: public MessageFilter[] getForumMessageFilters()
0780: throws UnauthorizedException {
0781: MessageFilter[] dbFilters = new MessageFilter[filters.length];
0782: for (int i = 0; i < filters.length; i++) {
0783: dbFilters[i] = new DbForumMessageFilter(
0784: (Message) filters[i], this );
0785: }
0786: return dbFilters;
0787: }
0788:
0789: public void addForumMessageFilter(MessageFilter filter)
0790: throws UnauthorizedException {
0791: ArrayList newFilters = new ArrayList(filters.length + 1);
0792: for (int i = 0; i < filters.length; i++) {
0793: newFilters.add(filters[i]);
0794: }
0795: newFilters.add(filter);
0796: MessageFilter[] newArray = new MessageFilter[newFilters.size()];
0797: for (int i = 0; i < newArray.length; i++) {
0798: newArray[i] = (MessageFilter) newFilters.get(i);
0799: }
0800: //Finally, overwrite filters with the new array
0801: filters = newArray;
0802: saveFiltersToDb();
0803: }
0804:
0805: public void addForumMessageFilter(MessageFilter filter, int index)
0806: throws UnauthorizedException {
0807: ArrayList newFilters = new ArrayList(filters.length + 1);
0808: for (int i = 0; i < filters.length; i++) {
0809: newFilters.add(filters[i]);
0810: }
0811: newFilters.add(index, filter);
0812: MessageFilter[] newArray = new MessageFilter[newFilters.size()];
0813: for (int i = 0; i < newArray.length; i++) {
0814: newArray[i] = (MessageFilter) newFilters.get(i);
0815: }
0816: //Finally, overwrite filters with the new array
0817: filters = newArray;
0818: saveFiltersToDb();
0819: }
0820:
0821: public void removeForumMessageFilter(int index)
0822: throws UnauthorizedException {
0823: ArrayList newFilters = new ArrayList(filters.length);
0824: for (int i = 0; i < filters.length; i++) {
0825: newFilters.add(filters[i]);
0826: }
0827: newFilters.remove(index);
0828: MessageFilter[] newArray = new MessageFilter[newFilters.size()];
0829: for (int i = 0; i < newArray.length; i++) {
0830: newArray[i] = (MessageFilter) newFilters.get(i);
0831: }
0832: //Finally, overwrite filters with the new array
0833: filters = newArray;
0834: saveFiltersToDb();
0835: }
0836:
0837: public ForumPermissions getPermissions(Authorization authorization) {
0838: int userID = authorization.getUserID();
0839:
0840: //Get the user perm cache for this forum
0841: Cache userPermCache = (Cache) factory.getCacheManager().get(
0842: DbCacheManager.USER_PERMS_CACHE, new Integer(id));
0843:
0844: //Simple case: if cache is turned on and the user is already cached,
0845: //we can simply return the cached permissions.
0846: if (userPermCache != null) {
0847: ForumPermissions permissions = (ForumPermissions) userPermCache
0848: .get(new Integer(userID));
0849: if (permissions != null) {
0850: return permissions;
0851: }
0852: }
0853:
0854: //Not so simple case: cache is not turned on or the user permissions
0855: //have not been cached yet.
0856: boolean isAnonymous = (userID == -1);
0857: boolean isUser = !isAnonymous;
0858:
0859: ForumPermissions finalPermissions = ForumPermissions.none();
0860:
0861: //Step 1 - Get permissions for the User. This includes anonymous
0862: //perms, "special user" perms, and the specific perms for the user.
0863: if (isUser) {
0864: ForumPermissions userPermissions = factory
0865: .getUserPermissions(userID, id);
0866: //Combine permissions
0867: finalPermissions = new ForumPermissions(finalPermissions,
0868: userPermissions);
0869: }
0870: //Add in anonymous perms.
0871: ForumPermissions anonyPermissions = null;
0872: if (userPermCache != null) {
0873: anonyPermissions = (ForumPermissions) userPermCache
0874: .get(new Integer(-1));
0875: }
0876: //Otherwise, do our own lookup.
0877: if (anonyPermissions == null) {
0878: anonyPermissions = factory.getUserPermissions(-1, id);
0879: //Add to cache so it will be there next time.
0880: if (userPermCache != null) {
0881: userPermCache.add(new Integer(-1), anonyPermissions);
0882: }
0883: }
0884: //Combine permissions
0885: finalPermissions = new ForumPermissions(finalPermissions,
0886: anonyPermissions);
0887:
0888: //If they are a valid user, figure out "any user" permissions.
0889: if (isUser) {
0890: ForumPermissions specialUserPermissions = null;
0891: //Check for cache
0892: if (userPermCache != null) {
0893: specialUserPermissions = (ForumPermissions) userPermCache
0894: .get(new Integer(0));
0895: }
0896: //Otherwise, do our own lookup.
0897: if (specialUserPermissions == null) {
0898: specialUserPermissions = factory.getUserPermissions(0,
0899: id);
0900: //Add to cache so it will be there next time.
0901: if (userPermCache != null) {
0902: userPermCache.add(new Integer(0),
0903: specialUserPermissions);
0904: }
0905: }
0906: //Combine permissions
0907: finalPermissions = new ForumPermissions(finalPermissions,
0908: specialUserPermissions);
0909: }
0910:
0911: //Step 2 -- get Permissions for all groups the user is in.
0912: int[] groups = ((DbProfileManager) factory.getProfileManager())
0913: .getUserGroups(userID);
0914: for (int i = 0; i < groups.length; i++) {
0915: ForumPermissions groupPermissions = factory
0916: .getGroupPermissions(groups[i], id);
0917: finalPermissions = new ForumPermissions(finalPermissions,
0918: groupPermissions);
0919: }
0920:
0921: //Finally, add user to cache so it will be there next time.
0922: if (isUser && userPermCache != null) {
0923: userPermCache.add(new Integer(userID), finalPermissions);
0924: }
0925:
0926: return finalPermissions;
0927: }
0928:
0929: public boolean hasPermission(int type) {
0930: return true;
0931: }
0932:
0933: //FROM THE CACHEABLE INTERFACE//
0934:
0935: public int getSize() {
0936: //Approximate the size of the object in bytes by calculating the size
0937: //of each field.
0938: int size = 0;
0939: size += CacheSizes.sizeOfObject(); //overhead of object
0940: size += CacheSizes.sizeOfInt(); //id
0941: size += CacheSizes.sizeOfString(name); //name
0942: size += CacheSizes.sizeOfString(description); //description
0943: size += CacheSizes.sizeOfDate(); //creation date
0944: size += CacheSizes.sizeOfDate(); //modified date
0945: size += CacheSizes.sizeOfInt(); //moderated
0946: size += filters.length * 8; //each filter is 8 bytes
0947: size += CacheSizes.sizeOfProperties(properties); //properties object
0948: size += CacheSizes.sizeOfObject(); //save lock
0949:
0950: return size;
0951: }
0952:
0953: //OTHER METHODS
0954:
0955: /**
0956: * Returns a String representation of the Forum object using the forum name.
0957: *
0958: * @return a String representation of the Forum object.
0959: */
0960: public String toString() {
0961: return name;
0962: }
0963:
0964: public int hashCode() {
0965: return id;
0966: }
0967:
0968: public boolean equals(Object object) {
0969: if (this == object) {
0970: return true;
0971: }
0972: if (object != null && object instanceof DbForum) {
0973: return id == ((DbForum) object).getID();
0974: } else {
0975: return false;
0976: }
0977: }
0978:
0979: /**
0980: * Updates the modified date but doesn't require a security check since
0981: * it is a protected method.
0982: */
0983: protected void updateModifiedDate(java.util.Date modifiedDate) {
0984: this .modifiedDate = modifiedDate;
0985: Connection con = null;
0986: PreparedStatement pstmt = null;
0987: try {
0988: con = DbConnectionManager.getConnection();
0989: pstmt = con.prepareStatement(UPDATE_FORUM_MODIFIED_DATE);
0990: pstmt.setString(1, "" + modifiedDate.getTime());
0991: pstmt.setInt(2, id);
0992: pstmt.executeUpdate();
0993: } catch (SQLException sqle) {
0994: log.error("Error in DbForum:updateModifiedDate()-", sqle);
0995:
0996: } finally {
0997: try {
0998: pstmt.close();
0999: } catch (Exception e) {
1000: log.error("Error in DbForum.java:", e);
1001: }
1002: try {
1003: con.close();
1004: } catch (Exception e) {
1005: log.error("Error in DbForum.java:", e);
1006: }
1007: }
1008: }
1009:
1010: /**
1011: * Loads forum properties from the database.
1012: */
1013: private void loadProperties() {
1014: synchronized (saveLock) {
1015: Properties newProps = new Properties();
1016: Connection con = null;
1017: PreparedStatement pstmt = null;
1018: try {
1019: con = DbConnectionManager.getConnection();
1020: pstmt = con.prepareStatement(LOAD_PROPERTIES);
1021: pstmt.setInt(1, id);
1022: ResultSet rs = pstmt.executeQuery();
1023: while (rs.next()) {
1024: String name = rs.getString("name");
1025: String value = rs.getString("propValue");
1026: newProps.put(name, value);
1027: }
1028: } catch (SQLException sqle) {
1029: log.error("Error in DbForum:loadProperties():", sqle);
1030:
1031: } finally {
1032: try {
1033: pstmt.close();
1034: } catch (Exception e) {
1035: log.error("Error in DbForum.java:", e);
1036: }
1037: try {
1038: con.close();
1039: } catch (Exception e) {
1040: log.error("Error in DbForum.java:", e);
1041: }
1042: }
1043: this .properties = newProps;
1044: }
1045: }
1046:
1047: /**
1048: * Saves forum properties to the database.
1049: */
1050: private void saveProperties() {
1051: synchronized (saveLock) {
1052: Connection con = null;
1053: PreparedStatement pstmt = null;
1054: try {
1055: con = DbConnectionManager.getConnection();
1056: //Delete all old values.
1057: pstmt = con.prepareStatement(DELETE_PROPERTIES);
1058: pstmt.setInt(1, id);
1059: pstmt.execute();
1060: pstmt.close();
1061: //Now insert new values.
1062: pstmt = con.prepareStatement(INSERT_PROPERTY);
1063: Enumeration e = properties.keys();
1064: while (e.hasMoreElements()) {
1065: String name = (String) e.nextElement();
1066: String value = (String) properties.get(name);
1067: pstmt.setInt(1, id);
1068: pstmt.setString(2, name);
1069: pstmt.setString(3, value);
1070: pstmt.executeUpdate();
1071: }
1072: } catch (SQLException sqle) {
1073: log.error("saveProperties", sqle);
1074: } finally {
1075: try {
1076: pstmt.close();
1077: } catch (Exception e) {
1078: log.error("", e);
1079: }
1080: try {
1081: con.close();
1082: } catch (Exception e) {
1083: log.error("", e);
1084: }
1085: }
1086: }
1087: }
1088:
1089: /**
1090: * Loads filters from the database.
1091: */
1092: private void loadFiltersFromDb() {
1093: ArrayList newFilters = new ArrayList();
1094: Connection con = null;
1095: PreparedStatement pstmt = null;
1096: try {
1097: con = DbConnectionManager.getConnection();
1098: pstmt = con.prepareStatement(LOAD_FILTERS);
1099: pstmt.setInt(1, id);
1100: ResultSet rs = pstmt.executeQuery();
1101: while (rs.next()) {
1102: try {
1103: ObjectInputStream in = new ObjectInputStream(rs
1104: .getBinaryStream("filterObject"));
1105: newFilters.add(in.readObject());
1106: } catch (ClassCastException cce) {
1107: //ignore for now since the filter might be updated. we
1108: //need a solution for this. probably custom class loading
1109: //of filter classes to protect against failure like this.
1110: } catch (Exception e) {
1111: log.error("", e);
1112: }
1113: }
1114: } catch (SQLException sqle) {
1115: log.error("", sqle);
1116: } finally {
1117: try {
1118: pstmt.close();
1119: } catch (Exception e) {
1120: log.error("", e);
1121: }
1122: try {
1123: con.close();
1124: } catch (Exception e) {
1125: log.error("", e);
1126: }
1127: }
1128: filters = new MessageFilter[newFilters.size()];
1129: for (int i = 0; i < filters.length; i++) {
1130: filters[i] = (MessageFilter) newFilters.get(i);
1131: }
1132: //Finally, save filters back to Db. Effectively, this deletes filters
1133: //from the database that failed to load. See note above.
1134: //saveFiltersToDb(); <<-- commenting out to try to fix filters bug.
1135: }
1136:
1137: /**
1138: * Saves filters to the database. Filter saving works by serializing
1139: * each filter to a byte stream and then inserting that stream into
1140: * the database.
1141: */
1142: protected void saveFiltersToDb() {
1143: boolean abort = false;
1144: boolean supportsTransactions = false;
1145: synchronized (saveLock) {
1146: Connection con = null;
1147: PreparedStatement pstmt = null;
1148: try {
1149: con = DbConnectionManager.getConnection();
1150:
1151: supportsTransactions = con.getMetaData()
1152: .supportsTransactions();
1153: if (supportsTransactions) {
1154: con.setAutoCommit(false);
1155: }
1156:
1157: pstmt = con.prepareStatement(DELETE_FILTERS);
1158: pstmt.setInt(1, id);
1159: pstmt.execute();
1160: //Now insert new list of filters.
1161: pstmt.close();
1162: pstmt = con.prepareStatement(ADD_FILTER);
1163: for (int i = 0; i < filters.length; i++) {
1164: try {
1165: ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
1166: ObjectOutputStream out = new ObjectOutputStream(
1167: byteOut);
1168: out.writeObject(filters[i]);
1169: pstmt.setInt(1, id);
1170: pstmt.setInt(2, i);
1171: pstmt.setBytes(3, byteOut.toByteArray());
1172: pstmt.execute();
1173: } catch (Exception e) {
1174: abort = true;
1175: log.error("", e);
1176: }
1177: }
1178: pstmt.close();
1179: } catch (SQLException sqle) {
1180: abort = true;
1181: log.error("", sqle);
1182: } finally {
1183: try {
1184: if (supportsTransactions) {
1185: if (abort == true) {
1186: con.rollback();
1187: } else {
1188: con.commit();
1189: }
1190: }
1191: } catch (Exception e) {
1192: log.error("", e);
1193: }
1194: try {
1195: if (supportsTransactions) {
1196: con.setAutoCommit(true);
1197: }
1198: } catch (Exception e) {
1199: log.error("", e);
1200: }
1201: try {
1202: con.close();
1203: } catch (Exception e) {
1204: log.error("", e);
1205: }
1206: }
1207: }
1208: }
1209:
1210: /**
1211: * Loads forum data from the database.
1212: */
1213: private void loadFromDb() throws ForumNotFoundException {
1214: Connection con = null;
1215: PreparedStatement pstmt = null;
1216: try {
1217: con = DbConnectionManager.getConnection();
1218: //See if we should load by forumID or by name
1219: if (id == -1) {
1220: pstmt = con.prepareStatement(LOAD_FORUM_BY_NAME);
1221: pstmt.setString(1, name);
1222: } else {
1223: pstmt = con.prepareStatement(LOAD_FORUM_BY_ID);
1224: pstmt.setInt(1, id);
1225: }
1226: ResultSet rs = pstmt.executeQuery();
1227: if (!rs.next()) {
1228: throw new ForumNotFoundException("Forum " + getID()
1229: + " could not be loaded from the database.");
1230: }
1231: id = rs.getInt("forumID");
1232: name = rs.getString("name");
1233: description = rs.getString("description");
1234: this .creationDate = new java.util.Date(Long.parseLong(rs
1235: .getString("creationDate").trim()));
1236: this .modifiedDate = new java.util.Date(Long.parseLong(rs
1237: .getString("modifiedDate").trim()));
1238: moderation = rs.getInt("moderated");
1239: } catch (SQLException sqle) {
1240: log.error("", sqle);
1241: throw new ForumNotFoundException("Forum " + getID()
1242: + " could not be loaded from the database.");
1243: } catch (NumberFormatException nfe) {
1244: log
1245: .error("WARNING: In DbForum.loadFromDb() -- there "
1246: + "was an error parsing the dates returned from the database. Ensure "
1247: + "that they're being stored correctly.");
1248: } finally {
1249: try {
1250: pstmt.close();
1251: } catch (Exception e) {
1252: log.error("", e);
1253: }
1254: try {
1255: con.close();
1256: } catch (Exception e) {
1257: log.error("", e);
1258: }
1259: }
1260: }
1261:
1262: /**
1263: * Inserts a new record into the database.
1264: */
1265: private void insertIntoDb() {
1266: Connection con = null;
1267: PreparedStatement pstmt = null;
1268: try {
1269: con = DbConnectionManager.getConnection();
1270: pstmt = con.prepareStatement(ADD_FORUM);
1271: pstmt.setInt(1, id);
1272: pstmt.setString(2, name);
1273: pstmt.setString(3, description);
1274: pstmt.setString(4, Long.toString(creationDate.getTime()));
1275: pstmt.setString(5, Long.toString(modifiedDate.getTime()));
1276: pstmt.setInt(6, moderation);
1277: pstmt.executeUpdate();
1278: } catch (SQLException sqle) {
1279: log.error("Error in DbForum:insertIntoDb()-", sqle);
1280:
1281: } finally {
1282: try {
1283: pstmt.close();
1284: } catch (Exception e) {
1285: log.error("", e);
1286: }
1287: try {
1288: con.close();
1289: } catch (Exception e) {
1290: log.error("", e);
1291: }
1292: }
1293: }
1294:
1295: /**
1296: * Saves forum data to the database.
1297: */
1298: private synchronized void saveToDb() {
1299: Connection con = null;
1300: PreparedStatement pstmt = null;
1301: try {
1302: con = DbConnectionManager.getConnection();
1303: pstmt = con.prepareStatement(SAVE_FORUM);
1304: pstmt.setString(1, name);
1305: pstmt.setString(2, description);
1306: pstmt.setString(3, Long.toString(creationDate.getTime()));
1307: pstmt.setString(4, Long.toString(modifiedDate.getTime()));
1308: pstmt.setInt(5, moderation);
1309: pstmt.setInt(6, id);
1310: pstmt.executeUpdate();
1311: } catch (SQLException sqle) {
1312: log.error("Error in DbForum:saveToDb()-", sqle);
1313:
1314: } finally {
1315: try {
1316: pstmt.close();
1317: } catch (Exception e) {
1318: log.error("", e);
1319: }
1320: try {
1321: con.close();
1322: } catch (Exception e) {
1323: log.error("", e);
1324: }
1325: }
1326: }
1327: }
|