/*
* NEMESIS-FORUM.
* Copyright (C) 2002 David Laurent(lithium2@free.fr). All rights reserved.
*
* Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
*
* Copyright (C) 2001 Yasna.com. All rights reserved.
*
* Copyright (C) 2000 CoolServlets.com. All rights reserved.
*
* NEMESIS-FORUM. is free software; you can redistribute it and/or
* modify it under the terms of the Apache Software License, Version 1.1,
* or (at your option) any later version.
*
* NEMESIS-FORUM core framework, NEMESIS-FORUM backoffice, NEMESIS-FORUM frontoffice
* application are parts of NEMESIS-FORUM and are distributed under
* same terms of licence.
*
*
* NEMESIS-FORUM includes software developed by the Apache Software Foundation (http://www.apache.org/)
* and software developed by CoolServlets.com (http://www.coolservlets.com).
* and software developed by Yasna.com (http://www.yasna.com).
*
*/
package org.nemesis.forum.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nemesis.forum.Message;
import org.nemesis.forum.TreeWalker;
import org.nemesis.forum.util.jdbc.DbConnectionManager;
/**
* Database implementation of the TreeWalker interface. This class is relatively
* inefficient compared to how it will eventually be implemented. However,
* a schema change is needed before that optimization is needed (represent
* tree structure directly in schema).
*/
public class DbTreeWalker implements TreeWalker {
static protected Log log = LogFactory.getLog(DbTreeWalker.class);
/** DATABASE QUERIES **/
private static final String GET_CHILD =
"SELECT yazdMessageTree.childID, yazdMessage.creationDate FROM "
+ "yazdMessageTree, yazdMessage WHERE "
+ "yazdMessageTree.childID=yazdMessage.messageID AND "
+ "yazdMessageTree.parentID=? ORDER BY yazdMessage.creationDate";
private static final String CHILD_COUNT = "SELECT count(*) FROM yazdMessageTree WHERE parentID=?";
private static final String INDEX_OF_CHILD =
"SELECT yazdMessageTree.childID, yazdMessage.creationDate "
+ "FROM yazdMessageTree, yazdMessage WHERE yazdMessageTree.childID=yazdMessage.messageID "
+ "AND yazdMessageTree.parentID=? ORDER BY yazdMessage.creationDate";
private static final String GET_CHILD_APPROVED =
"SELECT yazdMessageTree.childID, yazdMessage.creationDate FROM "
+ "yazdMessageTree, yazdMessage WHERE "
+ "yazdMessageTree.childID=yazdMessage.messageID AND "
+ "yazdMessageTree.parentID=? AND yazdMessage.approved=? ORDER BY yazdMessage.creationDate";
private static final String CHILD_COUNT_APPROVED = "SELECT count(*) FROM yazdMessageTree, yazdMessage WHERE yazdMessageTree.childID=yazdMessage.messageID AND yazdMessageTree.parentID=? AND yazdMessage.approved=? ";
private static final String INDEX_OF_CHILD_APPROVED =
"SELECT yazdMessageTree.childID, yazdMessage.creationDate "
+ "FROM yazdMessageTree, yazdMessage WHERE yazdMessageTree.childID=yazdMessage.messageID "
+ "AND yazdMessageTree.parentID=? AND yazdMessage.approved=? ORDER BY yazdMessage.creationDate";
private DbForumThread thread;
private DbForumFactory factory;
private boolean approved;
private boolean filter=false;
public DbTreeWalker(DbForumThread thread, DbForumFactory factory) {
this.thread = thread;
this.factory = factory;
}
public DbTreeWalker(boolean approved, DbForumThread thread, DbForumFactory factory) {
this.thread = thread;
this.factory = factory;
this.approved=approved;
this.filter=true;
}
/**
* Returns the root of the tree. Returns null only if the tree has no nodes.
*
* @returns the root of the tree
*/
public Message getRoot() {
return thread.getRootMessage();
}
/**
* Returns the child of parent at index index in the parent's child array.
* This should not return null if index is a valid index for parent (that
* is index >= 0 && index < getChildCount(parent)).
*
* @param parent the parent message.
* @param index the index of the child.
* @returns the child of parent at index.
*/
public Message getChild(Message parent, int index) {
Message message = null;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
if(filter){
pstmt = con.prepareStatement(GET_CHILD_APPROVED);
pstmt.setInt(1, parent.getID());
pstmt.setInt(2, approved ? 1:0);
}
else{
pstmt = con.prepareStatement(GET_CHILD);
pstmt.setInt(1, parent.getID());
}
ResultSet rs = pstmt.executeQuery();
while (rs.next() && index > 0) {
index--;
}
if (index == 0) {
int messageID = rs.getInt(1);
message = thread.getMessage(messageID);
}
} catch (Exception e) {
log.error("Error in DbMessageTreeWalker:getChild(" + index + ")-" , e);
} finally {
try {
pstmt.close();
} catch (Exception e) {
log.error("" , e);
}
try {
con.close();
} catch (Exception e) {
log.error("" , e);
}
}
return message;
}
/**
* Returns the number of children of parent. Returns 0 if the node is a
* leaf or if it has no children.
*
* @param parent a node in the tree, obtained from this data source.
* @returns the number of children of the node parent.
*/
public int getChildCount(Message parent) {
int childCount = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
if(filter){
pstmt = con.prepareStatement(CHILD_COUNT_APPROVED);
pstmt.setInt(1, parent.getID());
pstmt.setInt(2, approved ? 1:0);
}
else{
pstmt = con.prepareStatement(CHILD_COUNT);
pstmt.setInt(1, parent.getID());
}
ResultSet rs = pstmt.executeQuery();
rs.next();
childCount = rs.getInt(1);
} catch (Exception e) {
log.error("Error in DbTreeWalker:getChildCount()-" ,e);
} finally {
try {
pstmt.close();
} catch (Exception e) {
log.error("" , e);
}
try {
con.close();
} catch (Exception e) {
log.error("" , e);
}
}
return childCount;
}
/**
* Returns the total number of recursive children of a parent. Returns 0
* if there are no children. This method is not intended to aid in
* navigation of a Thread but is included as an added utility.
*/
public int getRecursiveChildCount(Message parent) {
int numChildren = 0;
int num = getChildCount(parent);
numChildren += num;
for (int i = 0; i < num; i++) {
Message child = getChild(parent, i);
if (child != null) {
numChildren += getRecursiveChildCount(child);
}
}
return numChildren;
}
/**
* Returns the index of child in parent.
*/
public int getIndexOfChild(Message parent, Message child) {
int index = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
if(filter){
pstmt = con.prepareStatement(INDEX_OF_CHILD_APPROVED);
pstmt.setInt(1, parent.getID());
pstmt.setInt(2, approved ? 1:0);
}
else{
pstmt = con.prepareStatement(INDEX_OF_CHILD);
pstmt.setInt(1, parent.getID());
}
rs = pstmt.executeQuery();
while (rs.next()) {
if (rs.getInt(1) == child.getID()) {
break;
}
index++;
}
} catch (Exception e) {
log.error("Error in DbTreeWalker:getIndexOfChild()-" , e);
} finally {
try {
pstmt.close();
} catch (Exception e) {
log.error("" , e);
}
try {
con.close();
} catch (Exception e) {
log.error("" , e);
}
}
return index;
}
/**
* Returns true if node is a leaf. A node is a leaf when it has no children
* messages.
*
* @param node a node in the tree, obtained from this data source
* @returns true if node is a leaf
*/
public boolean isLeaf(Message node) {
return (getChildCount(node) == 0);
}
}
|