/*
* Copyright (c) JForum Team. All rights reserved.
*
* The software in this package is published under the terms of the LGPL
* license a copy of which has been included with this distribution in the
* license.txt file.
*
* The JForum Project
* http://www.jforum.net
*/
package net.jforum.entities;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import net.jforum.repository.TopicRepository;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.search.annotations.ContainedIn;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.springframework.beans.factory.annotation.Autowired;
import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.PrototypeScoped;
/**
* Represents every topic in the forum.
*
* @author Rafael Steil
*/
@Entity
@Table(name = "jforum_topics")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Component
@PrototypeScoped
public class Topic implements Serializable {
public static final int TYPE_NORMAL = 0;
public static final int TYPE_STICKY = 1;
public static final int TYPE_ANNOUNCE = 2;
public static final int STATUS_UNLOCKED = 0;
public static final int STATUS_LOCKED = 1;
@Id
@SequenceGenerator(name = "sequence", sequenceName = "jforum_topics_seq")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "sequence")
@Column(name = "topic_id")
private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "forum_id")
@IndexedEmbedded
private Forum forum = new Forum();
@Column(name = "topic_views")
private int totalViews;
@Column(name = "topic_replies")
private int totalReplies;
@Column(name = "topic_status")
private int status;
@Column(name = "topic_type")
private int type;
@Column(name = "has_attachment")
private boolean hasAttachment;
@Transient
private boolean paginate;
@Column(name = "topic_subject")
private String subject;
@Column(name = "topic_date")
private Date date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "topic_first_post_id")
private Post firstPost;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "topic_last_post_id")
private Post lastPost;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "topic_vote_id")
private Poll poll;
@Column(name = "topic_vote_id", updatable = false, insertable = false)
private Integer pollId;
@ContainedIn
@OneToMany(mappedBy = "topic")
private List<Post> posts = new ArrayList<Post>();
@Column(name = "need_moderate")
private boolean pendingModeration;
@Column(name = "topic_moved_id")
private int movedId;
@Transient
private TopicRepository repository;
public Topic() {}
/**
* sometimes,in HQL, if we just want to load the id of the topic
* rather all the properites, this is quit usefull
* @param id
*/
public Topic(int id) {
this.id = id;
}
@Autowired
public Topic(TopicRepository repository) {
this.repository = repository;
}
public void setPendingModeration(boolean status) {
this.pendingModeration = status;
}
public void setRepository(TopicRepository repository) {
this.repository = repository;
}
/**
* @return the movedId
*/
public int getMovedId() {
return this.movedId;
}
/**
* Check if this topic was moved to another forum
* @return true if it was moved to another forum
*/
public boolean getHasMoved() {
return this.movedId > 0;
}
/**
* @param movedId the movedId to set
*/
public void setMovedId(int movedId) {
this.movedId = movedId;
}
/**
* Returns the ID of the topic
*
* @return int value with the ID
*/
public int getId() {
return this.id;
}
/**
* Return all posts from this topic
* @return all non-pending moderation posts
*/
public List<Post> getPosts() {
return this.posts;
}
/**
* Get all posts from this topic
* @param start the first record to start fetching
* @param count how many records to fetch
* @return all non-pending moderation posts in the specified range
*/
public List<Post> getPosts(int start, int count) {
this.assertRepository();
return this.repository.getPosts(this, start, count);
}
/**
* Returns the Forum this topic belongs to
*
* @return Forum this topic belongs to
*/
public Forum getForum() {
return this.forum;
}
/**
* Teturns the ID of the last post in the topic
*
* @return int value with the ID
*/
public Post getLastPost() {
return this.lastPost;
}
/**
* Returns the status
*
* @return int value with the status
*/
public int getStatus() {
return this.status;
}
/**
* Returns the time the topic was posted
*
* @return int value representing the time
*/
public Date getDate() {
return this.date;
}
/**
* Returns the title of the topci
*
* @return String with the topic title
*/
public String getSubject() {
return this.subject == null ? "" : this.subject;
}
/**
* Returns the total number of replies
*
* @return int value with the total
*/
public int getTotalReplies() {
return this.totalReplies;
}
/**
* Returns the number of posts in this topic.
* This includes only non-pending moderation posts.
* In fact, the result of this method is a call to {@link #getTotalReplies()} + 1
* @return the number of posts
*/
public int getTotalPosts() {
return this.getTotalReplies() + 1;
}
/**
* Returns the total number of views
*
* @return int value with the total number of views
*/
public int getTotalViews() {
return this.totalViews;
}
public User getUser() {
return this.user;
}
/**
* Returns the type
*
* @return int value representing the type
*/
public int getType() {
return this.type;
}
/**
* Sets the id to the topic
*
* @param id The id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* Sets the Forum associeted with this topic
*
* @param Forum The Forum to set
*/
public void setForum(Forum forum) {
this.forum = forum;
}
/**
* Sets the status.
*
* @param status The status to set
*/
public void setStatus(int status) {
this.status = status;
}
/**
* Sets the time.
*
* @param date The time to set
*/
public void setDate(Date date) {
this.date = date;
}
/**
* Sets the title.
*
* @param title The title to set
*/
public void setSubject(String title) {
this.subject = title;
}
/**
* Increment by 1 the number of replies of this topic
*/
public void incrementTotalReplies() {
this.totalReplies++;
}
/**
* Decrement by 1 the number of replies of this topic
*/
public void decrementTotalReplies() {
this.totalReplies--;
}
/**
* Sets the type.
*
* @param type The type to set
*/
public void setType(int type) {
this.type = type;
}
public void setUser(User u) {
this.user = u;
}
public void setPaginate(boolean paginate) {
this.paginate = paginate;
}
public boolean getPaginate() {
return this.paginate;
}
public void setHasAttachment(boolean b) {
this.hasAttachment = b;
}
public boolean getHasAttachment() {
return this.hasAttachment;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Topic)) {
return false;
}
return ((Topic) o).getId() == this.id;
}
/**
* @return true if {@link #getType()} == {@link #TYPE_NORMAL}
*/
public boolean isNormal() {
return this.getType() == TYPE_NORMAL;
}
/**
* @return true if {@link #getType()} == {@link #TYPE_STICKY}
*/
public boolean isSticky() {
return this.getType() == TYPE_STICKY;
}
/**
* @return true if {@link #getType()} == {@link #TYPE_ANNOUNCE}
*/
public boolean isAnnounce() {
return this.getType() == TYPE_ANNOUNCE;
}
/**
* @return true if {@link #getStatus()} == {@link #STATUS_LOCKED}
*/
public boolean isLocked() {
return this.getStatus() == STATUS_LOCKED;
}
/**
* Unlock this topic, if locked.
*/
public void unlock() {
this.status = STATUS_UNLOCKED;
}
/**
* Lock this topic
*/
public void lock() {
this.status = STATUS_LOCKED;
}
/**
* Get the first post in this topic
* @return the first post
*/
public Post getFirstPost() {
return this.firstPost;
}
public void setFirstPost(Post firstPost) {
this.firstPost = firstPost;
}
public void setLastPost(Post lastPost) {
this.lastPost = lastPost;
}
/**
* Increment by 1 the number of views of this topic
*/
public void incrementViews() {
this.totalViews++;
}
/**
* Check is this topic is waiting for moderation
* @return true if moderation is needed
*/
public boolean isWaitingModeration() {
return this.pendingModeration;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.id;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return new StringBuilder(64)
.append('[')
.append(this.id)
.append(", ").append(this.subject)
.append(']')
.toString();
}
private void assertRepository() {
if (this.repository == null) {
throw new IllegalStateException("repository was not initialized");
}
}
/**
* @param poll the poll to set
*/
public void setPoll(Poll poll) {
this.poll = poll;
if (poll != null) {
this.pollId = poll.getId();
}
}
/**
* @return the poll
*/
public Poll getPoll() {
return poll;
}
public boolean isPollEnabled() {
return this.pollId != null && this.pollId > 0;
}
}