1 25 package org.nemesis.forum.impl; 26 27 import java.sql.Connection ; 28 import java.sql.PreparedStatement ; 29 import java.sql.ResultSet ; 30 import java.sql.SQLException ; 31 import java.util.Date ; 32 import java.util.Iterator ; 33 import java.util.Vector ; 34 35 import org.apache.commons.logging.Log; 36 import org.apache.commons.logging.LogFactory; 37 import org.nemesis.forum.Forum; 38 import org.nemesis.forum.ForumThread; 39 import org.nemesis.forum.Message; 40 import org.nemesis.forum.TreeWalker; 41 import org.nemesis.forum.proxy.MessageProxy; 42 import org.nemesis.forum.event.ForumEvent; 43 import org.nemesis.forum.event.ForumListener; 44 import org.nemesis.forum.exception.ForumMessageNotFoundException; 45 import org.nemesis.forum.exception.ForumThreadNotFoundException; 46 import org.nemesis.forum.exception.UnauthorizedException; 47 import org.nemesis.forum.util.cache.CacheSizes; 48 import org.nemesis.forum.util.cache.Cacheable; 49 import org.nemesis.forum.util.jdbc.DbConnectionManager; 50 55 public class DbForumThread implements ForumThread, Cacheable { 56 static protected Log log = LogFactory.getLog(DbForumThread.class); 57 58 private static final String MESSAGE_COUNT = "SELECT count(*) FROM yazdMessage WHERE threadID=?"; 59 private static final String ADD_MESSAGE = "INSERT INTO yazdMessageTree(parentID,childID) VALUES(?,?)"; 60 private static final String MOVE_MESSAGE = "UPDATE yazdMessageTree SET parentID=? WHERE childID=?"; 61 private static final String CHANGE_MESSAGE_THREAD = "UPDATE yazdMessage SET threadID=? WHERE messageID=?"; 62 private static final String UPDATE_THREAD_MODIFIED_DATE = "UPDATE yazdThread SET modifiedDate=? WHERE threadID=?"; 63 private static final String DELETE_MESSAGE1 = "DELETE FROM yazdMessageTree WHERE childID=?"; 64 private static final String DELETE_MESSAGE2 = "DELETE FROM yazdMessage WHERE messageID=?"; 65 private static final String DELETE_MESSAGE_PROPERTIES = "DELETE FROM yazdMessageProp WHERE messageID=?"; 66 67 private static final String LOAD_THREAD = "SELECT rootMessageID, creationDate, modifiedDate,approved FROM yazdThread WHERE threadID=?"; 68 private static final String INSERT_THREAD = "INSERT INTO yazdThread(threadID,forumID, rootMessageID,creationDate, modifiedDate,approved) VALUES(?,?,?,?,?,?)"; 69 private static final String SAVE_THREAD = "UPDATE yazdThread SET rootMessageID=?, creationDate=?, modifiedDate=?, approved=? WHERE threadID=?"; 70 71 private static final String APPROVED_MESSAGE_COUNT = "SELECT count(*) FROM yazdMessage WHERE threadID=? AND approved=?"; 72 73 74 private int id = -1; 75 private Message rootMessage; 77 private int rootMessageID; 78 private java.util.Date creationDate; 79 private java.util.Date modifiedDate; 80 private boolean approved; 81 82 87 private boolean isReadyToSave = false; 88 89 92 private DbForum forum; 93 94 97 private DbForumFactory factory; 98 99 106 protected DbForumThread(Message rootMessage, boolean approved, DbForum forum, DbForumFactory factory) 107 throws UnauthorizedException { 108 this.id = DbSequenceManager.nextID("ForumThread"); 109 this.forum = forum; 110 this.factory = factory; 111 this.rootMessage = rootMessage; 112 this.rootMessageID = rootMessage.getID(); 113 long rootMessageTime = rootMessage.getCreationDate().getTime(); 116 this.creationDate = new java.util.Date (rootMessageTime); 117 this.modifiedDate = new java.util.Date (rootMessageTime); 118 this.approved = approved; 119 } 120 121 128 protected DbForumThread(int id, DbForum forum, DbForumFactory factory) throws ForumThreadNotFoundException { 129 this.id = id; 130 this.forum = forum; 131 this.factory = factory; 132 loadFromDb(); 133 isReadyToSave = true; 134 } 135 136 public boolean isApproved(){ 138 return approved; 139 } 140 public void setApproved(boolean approved) throws UnauthorizedException{ 141 this.approved = approved; 142 if (!isReadyToSave) { 144 return; 145 } 146 saveToDb(); 147 } 148 149 public int getID() { 150 return id; 151 } 152 153 public String getName() { 154 return getRootMessage().getSubject(); 155 } 156 157 public java.util.Date getCreationDate() { 158 return creationDate; 159 } 160 161 public void setCreationDate(java.util.Date creationDate) throws UnauthorizedException { 162 this.creationDate = creationDate; 163 if (!isReadyToSave) { 165 return; 166 } 167 saveToDb(); 168 } 169 170 public java.util.Date getModifiedDate() { 171 return modifiedDate; 172 } 173 174 public void setModifiedDate(java.util.Date modifiedDate) throws UnauthorizedException { 175 this.modifiedDate = modifiedDate; 176 if (!isReadyToSave) { 178 return; 179 } 180 saveToDb(); 181 } 182 183 public Forum getForum() { 184 return forum; 185 } 186 187 public Message getMessage(int messageID) throws ForumMessageNotFoundException { 188 Message message = factory.getMessage(messageID); 189 190 message = forum.applyFilters(message); 192 return message; 193 } 194 195 public Message getRootMessage() { 196 try { 197 return getMessage(rootMessageID); 198 } catch (ForumMessageNotFoundException e) { 199 log.error("Could not load root message with id " + rootMessageID); 200 return null; 201 } 202 219 } 220 221 public int getMessageCount() { 222 int messageCount = 0; 223 Connection con = null; 224 PreparedStatement pstmt = null; 225 try { 226 con = DbConnectionManager.getConnection(); 227 pstmt = con.prepareStatement(MESSAGE_COUNT); 228 pstmt.setInt(1, id); 229 ResultSet rs = pstmt.executeQuery(); 230 rs.next(); 231 messageCount = rs.getInt(1); 232 } catch (SQLException sqle) { 233 log.error("DbForumThread:getMessageCount() failed: " , sqle); 234 } finally { 235 try { 236 pstmt.close(); 237 } catch (Exception e) { 238 log.error("",e); 239 } 240 try { 241 con.close(); 242 } catch (Exception e) { 243 log.error("",e); 244 } 245 } 246 return messageCount; 247 } 248 249 public int getMessageCount(boolean approved) { 250 int messageCount = 0; 251 Connection con = null; 252 PreparedStatement pstmt = null; 253 try { 254 con = DbConnectionManager.getConnection(); 255 pstmt = con.prepareStatement(APPROVED_MESSAGE_COUNT); 256 pstmt.setInt(1, id); 257 pstmt.setInt(2, approved?1:0); 258 ResultSet rs = pstmt.executeQuery(); 259 rs.next(); 260 messageCount = rs.getInt(1); 261 } catch (SQLException sqle) { 262 log.error("DbForumThread:getMessageCount() failed: " , sqle); 263 } finally { 264 try { 265 pstmt.close(); 266 } catch (Exception e) { 267 log.error("",e); 268 } 269 try { 270 con.close(); 271 } catch (Exception e) { 272 log.error("",e); 273 } 274 } 275 return messageCount; 276 } 277 278 public void addMessage(Message parentMessage, Message newMessage) { 279 boolean abortTransaction = false; 280 boolean supportsTransactions = false; 281 Connection con = null; 283 PreparedStatement pstmt = null; 284 try { 285 con = DbConnectionManager.getConnection(); 286 supportsTransactions = con.getMetaData().supportsTransactions(); 287 if (supportsTransactions) { 288 con.setAutoCommit(false); 289 } 290 291 ((MessageProxy) newMessage).insertIntoDb(con, this); 294 295 pstmt = con.prepareStatement(ADD_MESSAGE); 296 pstmt.setInt(1, parentMessage.getID()); 297 pstmt.setInt(2, newMessage.getID()); 298 pstmt.executeUpdate(); 299 pstmt.close(); 300 } catch (Exception e) { 301 log.error("",e); 302 abortTransaction = true; 303 return; 304 } finally { 305 try { 306 if (supportsTransactions) { 307 if (abortTransaction == true) { 308 con.rollback(); 309 } else { 310 con.commit(); 311 } 312 } 313 } catch (Exception e) { 314 log.error("",e); 315 } 316 try { 317 if (supportsTransactions) { 318 con.setAutoCommit(true); 319 } 320 con.close(); 321 } catch (Exception e) { 322 log.error("",e); 323 } 324 } 325 326 updateModifiedDate(newMessage.getModifiedDate()); 328 DbForum dbForum = (DbForum) factory.cacheManager.get(DbCacheManager.FORUM_CACHE, new Integer (forum.getID())); 330 if (dbForum != null) { 331 dbForum.updateModifiedDate(modifiedDate); 332 } else { 333 forum.updateModifiedDate(modifiedDate); 334 } 335 } 336 337 public void deleteMessage(Message message) throws UnauthorizedException { 338 if (message == null) { 340 return; 341 } 342 if (message.getForumThread().getID() != this.id) { 344 throw new IllegalArgumentException ( 345 "Message " 346 + message.getID() 347 + " could not be deleted. It belongs to thread " 348 + message.getForumThread().getID() 349 + ", and not thread " 350 + this.id 351 + "."); 352 } 353 354 Connection con = null; 355 PreparedStatement pstmt = null; 356 try { 357 con = DbConnectionManager.getConnection(); 358 pstmt = con.prepareStatement(DELETE_MESSAGE1); 360 pstmt.setInt(1, message.getID()); 361 pstmt.execute(); 362 } catch (SQLException sqle) { 363 log.error("Error in DbForumThread:deleteMessage()-" , sqle); 364 } finally { 365 try { 366 pstmt.close(); 367 } catch (Exception e) { 368 log.error("",e); 369 } 370 try { 371 con.close(); 372 } catch (Exception e) { 373 log.error("",e); 374 } 375 } 376 377 TreeWalker walker = treeWalker(); 379 int childCount = walker.getChildCount(message); 380 for (int i = childCount - 1; i >= 0; i--) { 381 Message childMessage = walker.getChild(message, i); 382 if (childMessage == null) { 383 log.error("child message was null -- index " + i); 384 } 385 deleteMessage(childMessage); 386 } 387 388 try { 389 con = DbConnectionManager.getConnection(); 391 pstmt = con.prepareStatement(DELETE_MESSAGE2); 392 pstmt.setInt(1, message.getID()); 393 pstmt.execute(); 394 pstmt.close(); 395 396 pstmt = con.prepareStatement(DELETE_MESSAGE_PROPERTIES); 398 pstmt.setInt(1, message.getID()); 399 pstmt.execute(); 400 401 ForumEvent event = new ForumEvent(message); 402 for (int i = 0; i < listeners.size(); i++) { 403 ((ForumListener) listeners.get(i)).objectDeleted(event); 404 } 405 406 407 408 } catch (SQLException sqle) { 409 log.error("Error in DbForumThread:deleteMessage()-" , sqle); 410 } finally { 411 try { 412 pstmt.close(); 413 } catch (Exception e) { 414 log.error("",e); 415 } 416 try { 417 con.close(); 418 } catch (Exception e) { 419 log.error("",e); 420 } 421 } 422 423 factory.getCacheManager().remove(DbCacheManager.MESSAGE_CACHE, new Integer (message.getID())); 425 426 429 if (message.getID() == this.rootMessageID) { 432 forum.deleteThreadRecord(this.id); 433 } 434 } 435 436 public void moveMessage(Message message, ForumThread newThread, Message parentMessage) 437 throws UnauthorizedException, IllegalArgumentException { 438 if (message.getForumThread().getID() != this.id 439 || parentMessage.getForumThread().getID() != newThread.getID()) { 440 throw new IllegalArgumentException ("The messages and threads did not match."); 441 } 442 443 int messageID = message.getID(); 445 int oldRootMessageID = getRootMessage().getID(); 447 448 TreeWalker walker = treeWalker(); 450 int childCount = walker.getChildCount(message); 451 for (int i = 0; i < childCount; i++) { 452 Message childMessage = walker.getChild(message, i); 453 changeMessageThread(childMessage, newThread); 454 } 455 456 changeMessageThread(message, newThread); 458 459 Connection con = null; 461 PreparedStatement pstmt = null; 462 try { 463 con = DbConnectionManager.getConnection(); 464 465 if (oldRootMessageID != messageID) { 466 pstmt = con.prepareStatement(MOVE_MESSAGE); 467 pstmt.setInt(1, parentMessage.getID()); 468 pstmt.setInt(2, messageID); 469 } else { 470 pstmt = con.prepareStatement(ADD_MESSAGE); 471 pstmt.setInt(1, parentMessage.getID()); 472 pstmt.setInt(2, messageID); 473 } 474 475 pstmt.executeUpdate(); 476 pstmt.close(); 477 } catch (SQLException sqle) { 478 log.error("Error in DbForumThread:moveMessage()-" , sqle); 479 } finally { 480 try { 481 pstmt.close(); 482 } catch (Exception e) { 483 log.error("",e); 484 } 485 try { 486 con.close(); 487 } catch (Exception e) { 488 log.error("",e); 489 } 490 } 491 492 Date now = new Date (); 494 newThread.setModifiedDate(now); 495 newThread.getForum().setModifiedDate(now); 497 498 DbCacheManager cacheManager = factory.getCacheManager(); 500 Integer key = new Integer (this.id); 501 cacheManager.remove(DbCacheManager.THREAD_CACHE, key); 502 503 if (getRootMessage().getID() == messageID) { 508 this.getForum().deleteThread(this); 510 } 511 } 512 513 public TreeWalker treeWalker() { 514 return new DbTreeWalker(this, factory); 515 } 516 517 public TreeWalker treeWalker(boolean approved) { 518 return new DbTreeWalker(approved,this, factory); 519 } 520 521 public Iterator messages() { 522 return new DbThreadIterator(this); 523 } 524 525 public Iterator messages(int startIndex, int numResults) { 526 return new DbThreadIterator(this, startIndex, numResults); 527 } 528 529 public Iterator messages(boolean approved) { 530 return new DbThreadIterator(approved,this); 531 } 532 533 public Iterator messages(boolean approved,int startIndex, int numResults) { 534 return new DbThreadIterator(approved,this, startIndex, numResults); 535 } 536 537 public boolean hasPermission(int type) { 538 return true; 539 } 540 541 543 public int getSize() { 544 int size = 0; 547 size += CacheSizes.sizeOfObject(); size += CacheSizes.sizeOfInt(); size += CacheSizes.sizeOfDate(); size += CacheSizes.sizeOfDate(); size += CacheSizes.sizeOfBoolean(); size += CacheSizes.sizeOfObject(); size += CacheSizes.sizeOfObject(); size += CacheSizes.sizeOfObject(); size += CacheSizes.sizeOfBoolean(); size += CacheSizes.sizeOfBoolean(); 558 return size; 559 } 560 561 563 568 public String toString() { 569 return getName(); 570 } 571 572 public int hashCode() { 573 return id; 574 } 575 576 public boolean equals(Object object) { 577 if (this == object) { 578 return true; 579 } 580 if (object != null && object instanceof DbForumThread) { 581 return id == ((DbForumThread) object).getID(); 582 } else { 583 return false; 584 } 585 } 586 587 591 protected void updateModifiedDate(java.util.Date modifiedDate) { 592 this.modifiedDate = modifiedDate; 593 Connection con = null; 594 PreparedStatement pstmt = null; 595 try { 596 con = DbConnectionManager.getConnection(); 597 pstmt = con.prepareStatement(UPDATE_THREAD_MODIFIED_DATE); 598 pstmt.setString(1, "" + modifiedDate.getTime()); 599 pstmt.setInt(2, id); 600 pstmt.executeUpdate(); 601 } catch (SQLException sqle) { 602 log.error("Error in DbForumThread:updateModifiedDate()-" , sqle); 603 604 } finally { 605 try { 606 pstmt.close(); 607 } catch (Exception e) { 608 log.error("",e); 609 } 610 try { 611 con.close(); 612 } catch (Exception e) { 613 log.error("",e); 614 } 615 } 616 } 617 618 625 private void changeMessageThread(Message message, ForumThread newThread) throws UnauthorizedException { 626 629 DbCacheManager cacheManager = factory.getCacheManager(); 631 Integer key = new Integer (message.getID()); 632 cacheManager.remove(DbCacheManager.MESSAGE_CACHE, key); 633 634 Connection con = null; 635 PreparedStatement pstmt = null; 636 try { 637 con = DbConnectionManager.getConnection(); 638 pstmt = con.prepareStatement(CHANGE_MESSAGE_THREAD); 639 pstmt.setInt(1, newThread.getID()); 640 pstmt.setInt(2, key.intValue()); 641 pstmt.executeUpdate(); 642 } catch (SQLException sqle) { 643 log.error("",sqle); 644 } 645 646 try { 648 Message movedMessage = newThread.getMessage(key.intValue()); 649 movedMessage.setModifiedDate(new Date ()); 651 } catch (ForumMessageNotFoundException e) { 652 log.error( 653 "Error in DbForumThread:changeMessageThread()-" 654 + "messageID=" 655 + key.intValue() 656 + "newThreadID=" 657 + newThread.getID()); 658 } finally { 659 try { 660 pstmt.close(); 661 } catch (Exception e) { 662 log.error("",e); 663 } 664 try { 665 con.close(); 666 } catch (Exception e) { 667 log.error("",e); 668 } 669 } 670 } 671 672 675 private void loadFromDb() throws ForumThreadNotFoundException { 676 Connection con = null; 677 PreparedStatement pstmt = null; 678 try { 679 con = DbConnectionManager.getConnection(); 680 pstmt = con.prepareStatement(LOAD_THREAD); 681 pstmt.setInt(1, id); 682 ResultSet rs = pstmt.executeQuery(); 683 if (!rs.next()) { 684 throw new ForumThreadNotFoundException("Thread " + id + " could not be loaded from the database."); 685 } 686 rootMessageID = rs.getInt("rootMessageID"); 688 creationDate = new java.util.Date (Long.parseLong(rs.getString("creationDate").trim())); 695 modifiedDate = new java.util.Date (Long.parseLong(rs.getString("modifiedDate").trim())); 696 approved = rs.getInt("approved")==1; 697 pstmt.close(); 698 } catch (SQLException sqle) { 699 log.error("load",sqle); 700 throw new ForumThreadNotFoundException("Thread " + id + " could not be loaded from the database."); 701 } catch (NumberFormatException nfe) { 702 log.error( 703 "WARNING: In DbForumThread.loadFromDb() -- there " 704 + "was an error parsing the dates returned from the database. Ensure " 705 + "that they're being stored correctly."); 706 } finally { 707 try { 708 con.close(); 709 } catch (Exception e) { 710 log.error("",e); 711 } 712 } 713 } 714 715 723 public void insertIntoDb(Connection con) throws SQLException { 724 PreparedStatement pstmt = con.prepareStatement(INSERT_THREAD); 725 pstmt.setInt(1, id); 726 pstmt.setInt(2, forum.getID()); 727 pstmt.setInt(3, rootMessageID); 728 pstmt.setString(4, Long.toString(creationDate.getTime())); 729 pstmt.setString(5, Long.toString(modifiedDate.getTime())); 730 pstmt.setInt(6, approved ? 1 : 0); 731 pstmt.executeUpdate(); 732 pstmt.close(); 733 734 736 737 ((MessageProxy) rootMessage).insertIntoDb(con, this); 738 739 isReadyToSave = true; 742 } 743 744 747 private synchronized void saveToDb() { 748 Connection con = null; 749 PreparedStatement pstmt = null; 750 try { 751 con = DbConnectionManager.getConnection(); 752 pstmt = con.prepareStatement(SAVE_THREAD); 753 pstmt.setInt(1, rootMessageID); 754 pstmt.setString(2, Long.toString(creationDate.getTime())); 755 pstmt.setString(3, Long.toString(modifiedDate.getTime())); 756 pstmt.setInt(4, approved ? 1 : 0); 757 pstmt.setInt(5, id); 758 pstmt.executeUpdate(); 759 } catch (SQLException sqle) { 760 log.error("Error in DbForumThread:saveToDb()-" , sqle); 761 } finally { 762 try { 763 pstmt.close(); 764 } catch (Exception e) { 765 log.error("",e); 766 } 767 try { 768 con.close(); 769 } catch (Exception e) { 770 log.error("",e); 771 } 772 } 773 } 774 775 private static Vector listeners = new Vector (); 777 778 public static void addListener(ForumListener listener) { 779 listeners.add(listener); 780 } 781 782 public static void removeListener(ForumListener listener) { 783 listeners.remove(listener); 784 } 785 } 786 | Popular Tags |