Package com.Yasna.forum.database

Source Code of com.Yasna.forum.database.DbForum

/**
* Copyright (C) 2001 Yasna.com. All rights reserved.
*
* ===================================================================
* The Apache Software License, Version 1.1
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by
*        Yasna.com (http://www.yasna.com)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Yazd" and "Yasna.com" must not be used to
*    endorse or promote products derived from this software without
*    prior written permission. For written permission, please
*    contact yazd@yasna.com.
*
* 5. Products derived from this software may not be called "Yazd",
*    nor may "Yazd" appear in their name, without prior written
*    permission of Yasna.com.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL YASNA.COM OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of Yasna.com. For more information
* on Yasna.com, please see <http://www.yasna.com>.
*/

/**
* Copyright (C) 2000 CoolServlets.com. All rights reserved.
*
* ===================================================================
* The Apache Software License, Version 1.1
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by
*        CoolServlets.com (http://www.coolservlets.com)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Jive" and "CoolServlets.com" must not be used to
*    endorse or promote products derived from this software without
*    prior written permission. For written permission, please
*    contact webmaster@coolservlets.com.
*
* 5. Products derived from this software may not be called "Jive",
*    nor may "Jive" appear in their name, without prior written
*    permission of CoolServlets.com.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL COOLSERVLETS.COM OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of CoolServlets.com. For more information
* on CoolServlets.com, please see <http://www.coolservlets.com>.
*/

package com.Yasna.forum.database;

import java.util.Iterator;
import java.util.Enumeration;
import java.util.Properties;
import java.util.ArrayList;
import java.util.Date;
import java.sql.*;
import java.io.*;

import com.Yasna.forum.*;
import com.Yasna.forum.Exceptions.RapidPostingException;
import com.Yasna.forum.Exceptions.UserBlackListedException;
import com.Yasna.forum.util.ClientIP;
import com.Yasna.forum.filter.*;
import com.Yasna.util.Cache;
import com.Yasna.util.Cacheable;
import com.Yasna.util.CacheSizes;

/**
* Database implementation of the Forum interface. It loads and stores forum
* information from a a database.
*
* @see Forum
*/
public class DbForum implements Forum, Cacheable {

    /** DATABASE QUERIES **/
    private static final String ADD_THREAD =
        "UPDATE yazdThread set forumID=? WHERE threadID=?";
    protected static final String DELETE_THREAD = "DELETE FROM yazdThread WHERE threadID=?";
    private static final String THREAD_COUNT =
        "SELECT count(*) FROM yazdThread WHERE forumID=?";
    private static final String MESSAGE_COUNT =
        "SELECT count(*) FROM yazdThread, yazdMessage WHERE " +
        "yazdThread.forumID=? AND yazdThread.threadID=yazdMessage.threadID";
    private static final String ADD_USER_PERM =
        "INSERT INTO yazdUserPerm(forumID,userID,permission) VALUES(?,?,?)";
    private static final String REMOVE_USER_PERM =
        "DELETE FROM yazdUserPerm WHERE forumID=? AND userID=? AND permission=?";
    private static final String USERS_WITH_PERM =
        "SELECT DISTINCT userID FROM yazdUserPerm WHERE forumID=? AND permission=?";
    private static final String ADD_GROUP_PERM =
        "INSERT INTO yazdGroupPerm(forumID,groupID,permission) VALUES(?,?,?)";
    private static final String REMOVE_GROUP_PERM =
        "DELETE FROM yazdGroupPerm WHERE forumID=? AND groupID=? AND permission=?";
    private static final String GROUPS_WITH_PERM =
        "SELECT DISTINCT groupID FROM yazdGroupPerm WHERE forumID=? AND permission=?";
    private static final String LOAD_FILTERS =
        "SELECT filterObject, filterIndex FROM yazdFilter WHERE forumID=? ORDER BY filterIndex ASC";
    private static final String DELETE_FILTERS = "DELETE FROM yazdFilter WHERE forumID=?";
    private static final String ADD_FILTER =
        "INSERT INTO yazdFilter(forumID,filterIndex,filterObject) VALUES(?,?,?)";
    private static final String LOAD_PROPERTIES =
        "SELECT name, propValue FROM yazdForumProp WHERE forumID=?";
    private static final String DELETE_PROPERTIES =
        "DELETE FROM yazdForumProp WHERE forumID=?";
    private static final String INSERT_PROPERTY =
        "INSERT INTO yazdForumProp(forumID,name,propValue) VALUES(?,?,?)";
    private static final String LOAD_FORUM_BY_ID =
        "SELECT forumID, name, description, creationDate, modifiedDate, moderated, article,forumorder FROM yazdForum WHERE forumID=?";
    private static final String LOAD_FORUM_BY_NAME =
        "SELECT forumID, name, description, creationDate, modifiedDate, moderated, article,forumorder FROM yazdForum WHERE name=?";
    private static final String ADD_FORUM =
        "INSERT INTO yazdForum(forumID, name, description, creationDate, " +
        "modifiedDate, moderated, forumGroupID,article,forumorder) VALUES (?,?,?,?,?,?,?,?,0)";
    private static final String SAVE_FORUM =
        "UPDATE yazdForum SET name=?, description=?, creationDate=?, " +
        "modifiedDate=?, moderated=?,forumorder=? WHERE forumID=?";
    private static final String UPDATE_FORUM_MODIFIED_DATE =
        "UPDATE yazdForum SET modifiedDate=? WHERE forumID=?";
    private static final String INSERT_ARTICLE_MAP="insert into yazdArticleMap(threadID,pageKey,forumID) values(?,?,?)";

    private int id = -1;
    private String name;
    private String description;
    private int forumGroupID;
    private java.util.Date creationDate;
    private java.util.Date modifiedDate;
    private boolean moderated;
    private boolean isarticle=false;
    private ForumMessageFilter[] filters;
    private Properties properties;
    //Lock for saving state to database.
    private Object saveLock = new Object();
    private int order;

    private DbForumFactory factory;

    /**
     * Creates a new forum with the specified name and description.
     *
     * @param name the name of the forum.
     * @param description the description of the forum.
     * @param moderated when true - posted messages and threads must first be approved
     * @param forumGroupID every forum belongs to a Category and ForumGroup
     * @param factory the DbForumFactory the forum is a part of.
     */
    protected DbForum(String name, String description, boolean moderated,
                      int forumGroupID, DbForumFactory factory,boolean article) {
        this.id = DbSequenceManager.nextID("Forum");
        this.name = name;
        this.description = description;
        this.moderated = moderated;
        this.forumGroupID = forumGroupID;
        long now = System.currentTimeMillis();
        creationDate = new java.util.Date(now);
        modifiedDate = new java.util.Date(now);
        this.factory = factory;
        this.isarticle=article;
        insertIntoDb();
        properties = new Properties();
        //Forums should start with an html filter by default for
        //security purposes.
        filters = new ForumMessageFilter[2];
        filters[0] = new FilterHtml();
        filters[1] = new FilterNewline();
        saveFiltersToDb();
        //**Commenting out below since it doesn't seem to work for some reason.
        //try {
        //    addForumMessageFilter(new FilterHtml(), 0);
        //    addForumMessageFilter(new FilterNewline(), 1);
        //}
        //catch (UnauthorizedException ue) {
        //     ue.printStackTrace();
        //}
    }

    /**
     * Loads a forum with the specified id.
     */
    protected DbForum(int id, DbForumFactory factory)
            throws ForumNotFoundException
    {
        this.id = id;
        this.factory = factory;
        loadFromDb();
        loadFiltersFromDb();
        loadProperties();
    }

    /**
     * Loads a forum with the specified name.
     */
    protected DbForum(String name, DbForumFactory factory)
            throws ForumNotFoundException
    {
        this.name = name;
        this.factory = factory;
        loadFromDb();
        loadFiltersFromDb();
        loadProperties();
    }

    //FROM THE FORUM INTERFACE//

    public int getID() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) throws UnauthorizedException {
        this.name = name;
        saveToDb();
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) throws UnauthorizedException
    {
        this.description = description;
        saveToDb();
    }

    public java.util.Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(java.util.Date creationDate)
            throws UnauthorizedException
    {
       this.creationDate = creationDate;
       saveToDb();
    }

    public java.util.Date getModifiedDate() {
        return modifiedDate;
    }

    public void setModifiedDate(java.util.Date modifiedDate)
            throws UnauthorizedException
    {
        this.modifiedDate = modifiedDate;
        saveToDb();
    }

    public String getProperty(String name) {
        return (String)properties.get(name);
    }

    public void setProperty(String name, String value)
            throws UnauthorizedException
    {
        properties.put(name, value);
        saveProperties();
    }

    public Enumeration propertyNames() {
        return properties.keys();
    }

    public boolean isModerated() {
        return moderated;
    }

    public void setModerated(boolean moderated)
            throws UnauthorizedException
    {
        this.moderated = moderated;
        saveToDb();
    }

    public ForumThread createThread(ForumMessage rootMessage,ThreadType typeid)
        throws UnauthorizedException
    {
        //If the forum is moderated, the thread is not automatically
        //approved.
        boolean approved = !isModerated();
        return new DbForumThread(rootMessage, approved, this, factory,typeid);
    }

    public ForumMessage createMessage(User user,ClientIP clientIP)
        throws UnauthorizedException,RapidPostingException, UserBlackListedException
    {
        //If the forum is moderated, the message is not automatically
        //approved.
        boolean approved = !isModerated();
        ForumMessage message = new DbForumMessage(user, factory, approved,clientIP);
        return message;
    }
    public ForumMessage createDummyMessage(User user)
        throws UnauthorizedException
    {
        return new DbForumMessage(user, factory);
    }

    public void addThread(ForumThread thread) throws UnauthorizedException {
        boolean abortTransaction = false;
        boolean supportsTransactions = false;
        //Add message to db
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            supportsTransactions = con.getMetaData().supportsTransactions();
            if (supportsTransactions) {
                con.setAutoCommit(false);
            }

            pstmt = con.prepareStatement(ADD_THREAD);
            pstmt.setInt(1,id);
            pstmt.setInt(2,thread.getID());
            pstmt.executeUpdate();
            pstmt.close();

            //Now, insert the thread into the database.
            ((ForumThreadProxy)thread).insertIntoDb(con);
        }
        catch(Exception e) {
            e.printStackTrace();
            abortTransaction = true;
            return;
        }
        finally {
            try {
                if (supportsTransactions) {
                    if (abortTransaction == true) {
                        con.rollback();
                    }
                    else {
                        con.commit();
                    }
                }
            }
            catch (Exception e) { e.printStackTrace(); }
            try {
                if (supportsTransactions) {
                    con.setAutoCommit(true);
                }
                con.close();
            }
            catch (Exception e) { e.printStackTrace(); }
        }

        //Since we added a thread, update the modified date of this thread.
        updateModifiedDate(thread.getModifiedDate());
        //we add the subscription to the thread if necessary also
        User newUser = thread.getRootMessage().getUser();
        if(newUser.getThreadSubscribe() && newUser.getID() > 1){
            newUser.setProperty("WatchThread"+thread.getID(),"true");
        }

    }

    public ForumThread getThread(int threadID) throws
            ForumThreadNotFoundException
    {
        return factory.getThread(threadID, this);
    }

    public void deleteThread(ForumThread thread) throws UnauthorizedException
    {
        //Delete all messages from the thread. Deleting the root
        //message will delete all submessages.
        ForumMessage message = thread.getRootMessage();
        thread.deleteMessage(message);
    }

    protected void deleteThreadRecord(int threadID) {

        //Delete the actual thread
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(DELETE_THREAD);
            pstmt.setInt(1, threadID);
            pstmt.execute();
        }
        catch( Exception sqle ) {
            System.err.println("Error in DbForum:deleteThread()-" + sqle);
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }

        //Now, delete from cache
        Integer threadIDInteger = new Integer(threadID);
        factory.getCacheManager().remove(DbCacheManager.THREAD_CACHE, threadIDInteger);
    }

    public void moveThread(ForumThread thread, Forum forum)
        throws UnauthorizedException
    {
        //Ensure that thread belongs to this forum
        if (thread.getForum().getID() != this.id) {
            throw new IllegalArgumentException("The thread does not belong to this forum.");
        }
        //Ensure that thread is not in the same forum
        if (thread.getForum().getID() == forum.getID()) {
            throw new IllegalArgumentException("The thread is already in this forum.");
        }

        //Modify the SQL record. Only the thread table has information about
        //forumID, so we only need to modify that record. The message records
        //underneath the thread can be left alone.
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(ADD_THREAD);
            pstmt.setInt(1,forum.getID());
            pstmt.setInt(2,thread.getID());
            pstmt.executeUpdate();
            pstmt.close();
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum:addThread()-" + sqle);
            return;
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }

        DbCacheManager cacheManager = factory.getCacheManager();
        SearchIndexer indexer = factory.getSearchIndexer();

        //Remove both forums from cache.
        Integer key = new Integer(this.id);
        cacheManager.remove(DbCacheManager.FORUM_CACHE, key);
        key = new Integer(forum.getID());
        cacheManager.remove(DbCacheManager.FORUM_CACHE, key);

        //Remove thread from cache.
        key = new Integer(thread.getID());
        cacheManager.remove(DbCacheManager.THREAD_CACHE, key);

        //Loop through all messages in thread
        Iterator messages = thread.messages();
        while (messages.hasNext()) {
            ForumMessage message = (ForumMessage)messages.next();
            //Remove each message from cache.
            key = new Integer(message.getID());
            cacheManager.remove(DbCacheManager.MESSAGE_CACHE, key);
            //Remove and re-add every message to the search index.
            indexer.removeFromIndex(message);
            indexer.addToIndex(message);
        }

        // Update the modified date of thread
        Date now = new Date();
        thread.setModifiedDate(now);
        // Update the modified date of forum thread is now in
        forum.setModifiedDate(now);
    }

    public Iterator threads() {
        return new DbForumIterator(this, factory);
    }

    public Iterator threads(int startIndex, int numResults, int sortBy) {
        return new DbForumIterator(this, factory, startIndex, numResults, sortBy);
    }

    public int getThreadCount() {
        int threadCount = 0;
        // Based on the id in the object, get the thread data from the database:
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(THREAD_COUNT);
            pstmt.setInt(1, id);
            ResultSet rs = pstmt.executeQuery();
            rs.next();
            threadCount = rs.getInt(1 /*"threadCount"*/);
        }
        catch( SQLException sqle ) {
            System.err.println("DbForum:getThreadCount() failed: " + sqle);
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
        return threadCount;
    }

    public int getMessageCount() {
        int messageCount = 0;
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(MESSAGE_COUNT);
            pstmt.setInt(1, id);
            ResultSet rs = pstmt.executeQuery();
            rs.next();
            messageCount = rs.getInt(1 /*"messageCount"*/);
        }
        catch( SQLException sqle ) {
            System.err.println("DbForum:getMessageCount() failed: " + sqle);
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
        return messageCount;
    }

    public Query createQuery() {
        return new DbQuery(this, factory);
    }

    public void addUserPermission(User user, int permissionType)
            throws UnauthorizedException
    {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(ADD_USER_PERM);
            pstmt.setInt(1,id);
            pstmt.setInt(2,user.getID());
            pstmt.setInt(3,permissionType);
            pstmt.execute();
            //Remove user permissions from cache since they've changed.
            factory.getCacheManager().removeUserPerm(
                    new Integer(user.getID()),
                    new Integer(id)
            );
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum.java:" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    public void removeUserPermission(User user, int permissionType)
            throws UnauthorizedException
    {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(REMOVE_USER_PERM);
            pstmt.setInt(1,id);
            pstmt.setInt(2,user.getID());
            pstmt.setInt(3,permissionType);
            pstmt.execute();
            //Remove user permissions from cache since they've changed.
            factory.getCacheManager().removeUserPerm(
                    new Integer(user.getID()),
                    new Integer(id)
            );
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum.java:" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    public int[] usersWithPermission(int permissionType)
            throws UnauthorizedException
    {
        int [] users = new int[0];
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(USERS_WITH_PERM);
            pstmt.setInt(1,id);
            pstmt.setInt(2,permissionType);
            ResultSet rs = pstmt.executeQuery();
            ArrayList userList = new ArrayList();
            while (rs.next()) {
                userList.add(new Integer(rs.getInt("userID")));
            }
            users = new int[userList.size()];
            for (int i=0; i<users.length; i++) {
                users[i] = ((Integer)userList.get(i)).intValue();
            }
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum.java:" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
        return users;
    }

    public void addGroupPermission(Group group, int permissionType)
            throws UnauthorizedException
    {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(ADD_GROUP_PERM);
            pstmt.setInt(1,id);
            pstmt.setInt(2,group.getID());
            pstmt.setInt(3,permissionType);
            pstmt.execute();
            //Remove user permissions from cache since they've changed. Because
            //of the way that user perm cache is handled, it is easiest to
            //simply remove all the user perm cache for the forum. This is ok
            //since happens infrequently.
            factory.getCacheManager().remove(
                DbCacheManager.USER_PERMS_CACHE,
                new Integer(id)
            );
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum.java:" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    public void removeGroupPermission(Group group, int permissionType)
            throws UnauthorizedException
    {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(REMOVE_GROUP_PERM);
            pstmt.setInt(1,id);
            pstmt.setInt(2,group.getID());
            pstmt.setInt(3,permissionType);
            pstmt.execute();
            //Remove user permissions from cache since they've changed. Because
            //of the way that user perm cache is handled, it is easiest to
            //simply remove all the user perm cache for the forum. This is ok
            //since happens infrequently.
            factory.getCacheManager().remove(
                DbCacheManager.USER_PERMS_CACHE,
                new Integer(id)
            );
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum.java:" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    public int[] groupsWithPermission(int permissionType)
            throws UnauthorizedException
    {
        int [] groups = new int[0];
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(GROUPS_WITH_PERM);
            pstmt.setInt(1,id);
            pstmt.setInt(2,permissionType);
            ResultSet rs = pstmt.executeQuery();
            ArrayList groupList = new ArrayList();
            while (rs.next()) {
                groupList.add(new Integer(rs.getInt("groupID")));
            }
            groups = new int[groupList.size()];
            for (int i=0; i<groups.length; i++) {
                groups[i] = ((Integer)groupList.get(i)).intValue();
            }
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum.groupsWithPermission:" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
        return groups;
    }

    public ForumMessage applyFilters(ForumMessage message) {
        //Loop through filters and apply them
        for (int i=0; i < filters.length; i++) {
            message = filters[i].clone(message);
        }
        return message;
    }

    public ForumMessageFilter[] getForumMessageFilters()
            throws UnauthorizedException
    {
        ForumMessageFilter [] dbFilters = new ForumMessageFilter[filters.length];
        for (int i=0; i<filters.length; i++) {
            dbFilters[i] = new DbForumMessageFilter((ForumMessage)filters[i], this);
        }
        return dbFilters;
    }

    public void addForumMessageFilter(ForumMessageFilter filter)
            throws UnauthorizedException
    {
        ArrayList newFilters = new ArrayList(filters.length+1);
        for (int i=0; i<filters.length; i++) {
            newFilters.add(filters[i]);
        }
        newFilters.add(filter);
        ForumMessageFilter[] newArray = new ForumMessageFilter[newFilters.size()];
        for (int i=0; i<newArray.length; i++) {
            newArray[i] = (ForumMessageFilter)newFilters.get(i);
        }
        //Finally, overwrite filters with the new array
        filters = newArray;
        saveFiltersToDb();
    }

    public void addForumMessageFilter(ForumMessageFilter filter, int index)
            throws UnauthorizedException
    {
        ArrayList newFilters = new ArrayList(filters.length+1);
        for (int i=0; i<filters.length; i++) {
            newFilters.add(filters[i]);
        }
        newFilters.add(index, filter);
        ForumMessageFilter[] newArray = new ForumMessageFilter[newFilters.size()];
        for (int i=0; i<newArray.length; i++) {
            newArray[i] = (ForumMessageFilter)newFilters.get(i);
        }
        //Finally, overwrite filters with the new array
        filters = newArray;
        saveFiltersToDb();
    }

    public void removeForumMessageFilter(int index)
            throws UnauthorizedException
    {
        ArrayList newFilters = new ArrayList(filters.length);
        for (int i=0; i<filters.length; i++) {
            newFilters.add(filters[i]);
        }
        newFilters.remove(index);
        ForumMessageFilter[] newArray = new ForumMessageFilter[newFilters.size()];
        for (int i=0; i<newArray.length; i++) {
            newArray[i] = (ForumMessageFilter)newFilters.get(i);
        }
        //Finally, overwrite filters with the new array
        filters = newArray;
        saveFiltersToDb();
    }

    public ForumPermissions getPermissions(Authorization authorization) {
        int userID = authorization.getUserID();

        //Get the user perm cache for this forum
        Cache userPermCache = (Cache)factory.getCacheManager().get(
            DbCacheManager.USER_PERMS_CACHE,
            new Integer(id)
        );

        //Simple case: if cache is turned on and the user is already cached,
        //we can simply return the cached permissions.
        if (userPermCache != null) {
            ForumPermissions permissions =
                    (ForumPermissions)userPermCache.get(new Integer(userID));
            if (permissions != null) {
                return permissions;
            }
        }

        //Not so simple case: cache is not turned on or the user permissions
        //have not been cached yet.
        boolean isAnonymous = (userID == -1);
        boolean isUser = !isAnonymous;

        ForumPermissions finalPermissions = ForumPermissions.none();

        //Step 1 - Get permissions for the User. This includes anonymous
        //perms, "special user" perms, and the specific perms for the user.
        if (isUser) {
            ForumPermissions userPermissions = factory.getUserPermissions(userID, id);
            //Combine permissions
            finalPermissions = new ForumPermissions(finalPermissions, userPermissions);
        }
        //Add in anonymous perms.
        ForumPermissions anonyPermissions = null;
        if (userPermCache != null) {
            anonyPermissions = (ForumPermissions)userPermCache.get(new Integer(-1));
        }
        //Otherwise, do our own lookup.
        if (anonyPermissions == null) {
            anonyPermissions = factory.getUserPermissions(-1, id);
            //Add to cache so it will be there next time.
            if (userPermCache != null) {
                userPermCache.add(new Integer(-1), anonyPermissions);
            }
        }
        //Combine permissions
        finalPermissions = new ForumPermissions(finalPermissions, anonyPermissions);

        //If they are a valid user, figure out "any user" permissions.
        if (isUser) {
            ForumPermissions specialUserPermissions = null;
            //Check for cache
            if (userPermCache != null) {
                specialUserPermissions = (ForumPermissions)userPermCache.get(new Integer(0));
            }
            //Otherwise, do our own lookup.
            if (specialUserPermissions == null) {
                specialUserPermissions = factory.getUserPermissions(0, id);
                //Add to cache so it will be there next time.
                if (userPermCache != null) {
                    userPermCache.add(new Integer(0), specialUserPermissions);
                }
            }
            //Combine permissions
            finalPermissions = new ForumPermissions(finalPermissions, specialUserPermissions);
        }

        //Step 2 -- get Permissions for all groups the user is in.
        int [] groups = ((DbProfileManager)factory.getProfileManager()).getUserGroups(userID);
        for (int i=0; i<groups.length; i++) {
            ForumPermissions groupPermissions = factory.getGroupPermissions(groups[i], id);
            finalPermissions = new ForumPermissions(finalPermissions, groupPermissions);
        }

        //Finally, add user to cache so it will be there next time.
        if (isUser && userPermCache != null) {
            userPermCache.add(new Integer(userID), finalPermissions);
        }

        return finalPermissions;
    }

    public boolean hasPermission(int type) {
        return true;
    }

    //FROM THE CACHEABLE INTERFACE//

    public int getSize() {
        //Approximate the size of the object in bytes by calculating the size
        //of each field.
        int size = 0;
        size += CacheSizes.sizeOfObject();              //overhead of object
        size += CacheSizes.sizeOfInt();                 //id
        size += CacheSizes.sizeOfString(name);          //name
        size += CacheSizes.sizeOfString(description);   //description
        size += CacheSizes.sizeOfDate();                //creation date
        size += CacheSizes.sizeOfDate();                //modified date
        size += CacheSizes.sizeOfBoolean();                 //moderated
        size += filters.length * 8;                     //each filter is 8 bytes
        size += CacheSizes.sizeOfProperties(properties);//properties object
        size += CacheSizes.sizeOfObject();              //save lock
        size += CacheSizes.sizeOfBoolean();             //isarticle

        return size;
    }

    //OTHER METHODS

    /**
     * Returns a String representation of the Forum object using the forum name.
     *
     * @return a String representation of the Forum object.
     */
    public String toString() {
        return name;
    }

    public int hashCode() {
        return id;
    }

    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (object != null && object instanceof DbForum) {
            return id == ((DbForum)object).getID();
        }
        else {
            return false;
        }
    }

    /**
     * Updates the modified date but doesn't require a security check since
     * it is a protected method.
     */
    protected void updateModifiedDate(java.util.Date modifiedDate) {
        this.modifiedDate = modifiedDate;
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(UPDATE_FORUM_MODIFIED_DATE);
            pstmt.setString(1, ""+modifiedDate.getTime());
            pstmt.setInt(2, id);
            pstmt.executeUpdate();
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum:updateModifiedDate()-" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    /**
     * Loads forum properties from the database.
     */
    private void loadProperties() {
        synchronized(saveLock) {
            Properties newProps = new Properties();
            Connection con = null;
            PreparedStatement pstmt = null;
            try {
                con = DbConnectionManager.getConnection();
                pstmt = con.prepareStatement(LOAD_PROPERTIES);
                pstmt.setInt(1, id);
                ResultSet rs = pstmt.executeQuery();
                while(rs.next()) {
                    String name = rs.getString("name");
                    String value = rs.getString("propValue");
                    newProps.put(name, value);
                }
            }
            catch( SQLException sqle ) {
                System.err.println("Error in DbForum:loadProperties():" + sqle);
                sqle.printStackTrace();
            }
            finally {
                try pstmt.close(); }
                catch (Exception e) { e.printStackTrace(); }
                try con.close();   }
                catch (Exception e) { e.printStackTrace(); }
            }
            this.properties = newProps;
        }
    }

    /**
     * Saves forum properties to the database.
     */
    private void saveProperties() {
        synchronized(saveLock) {
            Connection con = null;
            PreparedStatement pstmt = null;
            try {
                con = DbConnectionManager.getConnection();
                //Delete all old values.
                pstmt = con.prepareStatement(DELETE_PROPERTIES);
                pstmt.setInt(1, id);
                pstmt.execute();
                pstmt.close();
                //Now insert new values.
                pstmt = con.prepareStatement(INSERT_PROPERTY);
                Enumeration enume = properties.keys();
                while (enume.hasMoreElements()) {
                    String name = (String)enume.nextElement();
                    String value = (String)properties.get(name);
                    pstmt.setInt(1, id);
                    pstmt.setString(2, name);
                    pstmt.setString(3, value);
                    pstmt.executeUpdate();
                }
            }
            catch( SQLException sqle ) {
                System.err.println(sqle);
            }
            finally {
                try pstmt.close(); }
                catch (Exception e) { e.printStackTrace(); }
                try con.close();   }
                catch (Exception e) { e.printStackTrace(); }
            }
        }
    }

    /**
     * Loads filters from the database.
     */
    private void loadFiltersFromDb() {
        ArrayList newFilters = new ArrayList();
        Connection con = null;
        boolean abort = false;
        boolean supportsTransactions = false;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            supportsTransactions = con.getMetaData().supportsTransactions();
            if (supportsTransactions) {
                 con.setAutoCommit(false);
            }

            pstmt = con.prepareStatement(LOAD_FILTERS);
            pstmt.setInt(1,id);
            ResultSet rs = pstmt.executeQuery();
            while(rs.next()) {
                try {
                    ObjectInputStream in = new ObjectInputStream(rs.getBinaryStream("filterObject"));
                    newFilters.add(in.readObject());
                }
                catch (ClassCastException cce) {
                    //ignore for now since the filter might be updated. we
                    //need a solution for this. probably custom class loading
                    //of filter classes to protect against failure like this.
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        catch( SQLException sqle ) {
            sqle.printStackTrace();
        }
        finally {
                try {
                    if (supportsTransactions) {
                        if (abort == true) {
                            con.rollback();
                        }
                        else {
                            con.commit();
                        }
                    }
                }
                catch (Exception e) { e.printStackTrace(); }
                try {
                    if (supportsTransactions) {
                        con.setAutoCommit(true);
                    }
                }
                catch (Exception e) { e.printStackTrace(); }
                try pstmt.close();   }
                catch (Exception e) { e.printStackTrace(); }
                try con.close();   }
                catch (Exception e) { e.printStackTrace(); }

        }
        filters = new ForumMessageFilter[newFilters.size()];
        for (int i=0; i<filters.length; i++) {
            filters[i] = (ForumMessageFilter)newFilters.get(i);
        }
        //Finally, save filters back to Db. Effectively, this deletes filters
        //from the database that failed to load. See note above.
        //saveFiltersToDb(); <<-- commenting out to try to fix filters bug.
    }

    /**
     * Saves filters to the database. Filter saving works by serializing
     * each filter to a byte stream and then inserting that stream into
     * the database.
     */
    protected void saveFiltersToDb() {
        boolean abort = false;
        boolean supportsTransactions = false;
        synchronized (saveLock) {
            Connection con = null;
            PreparedStatement pstmt = null;
            try {
                con = DbConnectionManager.getConnection();

                supportsTransactions = con.getMetaData().supportsTransactions();
                if (supportsTransactions) {
                    con.setAutoCommit(false);
                }

                pstmt = con.prepareStatement(DELETE_FILTERS);
                pstmt.setInt(1,id);
                pstmt.execute();
                //Now insert new list of filters.
                pstmt.close();
                pstmt = con.prepareStatement(ADD_FILTER);
                for (int i=0; i<filters.length; i++) {
                    try {
                        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                        ObjectOutputStream out = new ObjectOutputStream(byteOut);
                        out.writeObject(filters[i]);
                        pstmt.setInt(1,id);
                        pstmt.setInt(2,i);
                        pstmt.setBytes(3,byteOut.toByteArray());
                        pstmt.execute();
                    }
                    catch (Exception e) {
                        abort = true;
                        e.printStackTrace();
                    }
                }
                pstmt.close();
            }
            catch( SQLException sqle ) {
                abort = true;
                sqle.printStackTrace();
            }
            finally {
                try {
                    if (supportsTransactions) {
                        if (abort == true) {
                            con.rollback();
                        }
                        else {
                            con.commit();
                        }
                    }
                }
                catch (Exception e) { e.printStackTrace(); }
                try {
                    if (supportsTransactions) {
                        con.setAutoCommit(true);
                    }
                }
                catch (Exception e) { e.printStackTrace(); }
                try con.close();   }
                catch (Exception e) { e.printStackTrace(); }
            }
        }
    }

    /**
     * Loads forum data from the database.
     */
    private void loadFromDb() throws ForumNotFoundException {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            //See if we should load by forumID or by name
            if (id == -1) {
                pstmt = con.prepareStatement(LOAD_FORUM_BY_NAME);
                pstmt.setString(1,name);
            }
            else {
                pstmt = con.prepareStatement(LOAD_FORUM_BY_ID);
                pstmt.setInt(1, id);
            }
            ResultSet rs = pstmt.executeQuery();
            if( !rs.next() ) {
                throw new ForumNotFoundException("Forum " + getID() +
                    " could not be loaded from the database.");
            }
            id = rs.getInt("forumID");
            name = rs.getString("name");
            description = rs.getString("description");
            this.creationDate =
                new java.util.Date(Long.parseLong(rs.getString("creationDate").trim()));
            this.modifiedDate =
                new java.util.Date(Long.parseLong(rs.getString("modifiedDate").trim()));
            moderated = rs.getInt("moderated")==1 ? true : false;
            isarticle = rs.getInt("article")==1 ? true : false;
            order = rs.getInt("forumorder");
        }
        catch( SQLException sqle ) {
            sqle.printStackTrace();
            throw new ForumNotFoundException("Forum " + getID() +
                " could not be loaded from the database.");
        }
        catch (NumberFormatException nfe) {
            System.err.println("WARNING: In DbForum.loadFromDb() -- there " +
                "was an error parsing the dates returned from the database. Ensure " +
                "that they're being stored correctly.");
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    /**
     * Inserts a new record into the database.
     */
    private void insertIntoDb() {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(ADD_FORUM);
            pstmt.setInt(1,id);
            pstmt.setString(2,name);
            pstmt.setString(3,description);
            pstmt.setString(4, Long.toString(creationDate.getTime()));
            pstmt.setString(5, Long.toString(modifiedDate.getTime()));
            pstmt.setInt(6, moderated?1:0);
            pstmt.setInt(7, forumGroupID);
            pstmt.setInt(8,isarticle?1:0);
            pstmt.executeUpdate();
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum:insertIntoDb()-" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }

    /**
     * Saves forum data to the database.
     */
    private synchronized void saveToDb() {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(SAVE_FORUM);
            pstmt.setString(1, name);
            pstmt.setString(2, description);
            pstmt.setString(3, Long.toString(creationDate.getTime()));
            pstmt.setString(4, Long.toString(modifiedDate.getTime()));
            pstmt.setInt(5, moderated?1:0);
            pstmt.setInt(6,order);
            pstmt.setInt(7, id);
            pstmt.executeUpdate();
        }
        catch( SQLException sqle ) {
            System.err.println("Error in DbForum:saveToDb()-" + sqle);
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }
    }
    public boolean isArticleForum(){
        return this.isarticle;
    }
    public void addArticleMap(String pageKey,ForumThread thread) throws UnauthorizedException{
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(INSERT_ARTICLE_MAP);
            pstmt.setInt(1, thread.getID());
            pstmt.setString(2, pageKey);
            pstmt.setInt(3, id);
            pstmt.executeUpdate();
        }
        catch( SQLException sqle ) {
            sqle.printStackTrace();
        }
        finally {
            try pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try con.close();   }
            catch (Exception e) { e.printStackTrace(); }
        }

    }
    public int forumOrder(){
        return order;
    }
    public void setForumOrder(int param) throws UnauthorizedException{
        this.order=param;
        saveToDb();
    }

}
TOP

Related Classes of com.Yasna.forum.database.DbForum

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.