[jboss-cvs] jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum ...
Christian Bauer
christian at hibernate.org
Fri Nov 9 10:00:28 EST 2007
User: cbauer
Date: 07/11/09 10:00:28
Added: examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum
ForumQuery.java ReplyHome.java ForumInfo.java
TopicHome.java ForumTopic.java ForumListHome.java
ForumHome.java ForumDAO.java ForumQueries.hbm.xml
ForumSearchSupport.java ForumCookie.java
Log:
Initial import of forum plugin
Revision Changes Path
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumQuery.java
Index: ForumQuery.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.wiki.core.model.Directory;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.core.action.Pager;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.web.RequestParameter;
import org.jboss.seam.ScopeType;
import org.jboss.seam.Component;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.io.Serializable;
@Name("forumQuery")
@Scope(ScopeType.CONVERSATION)
public class ForumQuery implements Serializable {
private Pager pager;
@RequestParameter
public void setPage(Integer page) {
if (pager == null) pager = new Pager(2l);
pager.setPage(page);
}
public Pager getPager() {
return pager;
}
@In
Directory currentDirectory;
@In
User currentUser;
@In
int currentAccessLevel;
@In
ForumDAO forumDAO;
/* ####################### FORUMS ########################## */
List<Directory> forums;
public List<Directory> getForums() {
if (forums == null) loadForums();
return forums;
}
Map<Long, ForumInfo> forumInfo;
public Map<Long, ForumInfo> getForumInfo() {
return forumInfo;
}
@Observer(value = {"Forum.forumListRefresh", "org.jboss.seam.postAuthenticate"}, create = false)
public void loadForums() {
forums = forumDAO.findForums(currentDirectory);
forumInfo = forumDAO.findForumInfo(currentDirectory);
// Find unread postings
User adminUser = (User)Component.getInstance("adminUser");
User guestUser = (User)Component.getInstance("guestUser");
if ( !(currentUser.getId().equals(guestUser.getId())) &&
!(currentUser.getId().equals(adminUser.getId())) ) {
List<ForumTopic> unreadTopics = forumDAO.findUnreadTopics(currentUser.getPreviousLastLoginOn());
ForumCookie forumCookie = (ForumCookie)Component.getInstance("forumCookie");
for (ForumTopic unreadTopic : unreadTopics) {
if (forumInfo.containsKey(unreadTopic.getParent().getId()) &&
!forumCookie.getCookieValues().containsKey(unreadTopic.getId().toString())) {
forumInfo.get(unreadTopic.getParent().getId()).setUnreadPostings(true);
}
}
}
}
/* ####################### TOPICS ########################## */
private List<ForumTopic> topics;
public List<ForumTopic> getTopics() {
if (topics == null) loadTopics();
return topics;
}
@Observer(value = {"Forum.topicPersisted", "org.jboss.seam.postAuthenticate"}, create = false)
public void loadTopics() {
pager.setNumOfRecords( forumDAO.findTopicCount(currentDirectory) );
topics = pager.getNumOfRecords() > 0
? forumDAO.findTopics(currentDirectory, pager.getNextRecord(), pager.getPageSize())
: new ArrayList<ForumTopic>();
User adminUser = (User)Component.getInstance("adminUser");
User guestUser = (User)Component.getInstance("guestUser");
// Find unread postings
if ( !(currentUser.getId().equals(guestUser.getId())) &&
!(currentUser.getId().equals(adminUser.getId())) ) {
List<ForumTopic> unreadTopics = forumDAO.findUnreadTopics(currentUser.getPreviousLastLoginOn());
ForumCookie forumCookie = (ForumCookie)Component.getInstance("forumCookie");
// TODO: This is nested interation but it's difficult to make this more efficient
for (ForumTopic topic : topics) {
for (ForumTopic unreadTopic : unreadTopics) {
if (unreadTopic.getId().equals(topic.getId())&&
!forumCookie.getCookieValues().containsKey(topic.getId().toString())) {
topic.setUnread(true);
}
}
}
}
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ReplyHome.java
Index: ReplyHome.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.wiki.core.action.CommentHome;
import org.jboss.seam.wiki.core.model.Comment;
import org.jboss.seam.wiki.core.model.Document;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.core.dao.FeedDAO;
import org.jboss.seam.wiki.util.WikiUtil;
import org.jboss.seam.annotations.*;
import org.jboss.seam.ScopeType;
import org.jboss.seam.Component;
import org.jboss.seam.international.Messages;
import java.util.Date;
@Name("replyHome")
@Scope(ScopeType.CONVERSATION)
public class ReplyHome extends CommentHome {
@Create
public void initialize() {
super.initialize();
// Add this document to the "read" list in the forum cookie
// TODO: At some point, this adds up to the 4 kb cookie value limit, maybe we should only store unread ids?
ForumCookie forumCookie = (ForumCookie) Component.getInstance("forumCookie");
forumCookie.addCookieValue(currentDocument.getId().toString(), "r");
}
private boolean showForm = false;
public boolean isShowForm() {
return showForm;
}
public void setShowForm(boolean showForm) {
this.showForm = showForm;
}
public void createComment() {
comment = new Comment();
comment.setFromUser(currentUser);
}
public void createComment(Comment replyTo, boolean quote) {
createComment();
comment.setSubject(replyTo.getSubject());
if (quote) comment.setText(quote(replyTo.getText(), replyTo.getCreatedOn(), replyTo.getFromUser()));
}
public void createComment(ForumTopic replyTo, boolean quote) {
createComment();
comment.setSubject(replyTo.getName());
if (quote) comment.setText(quote(replyTo.getContentWithoutMacros(), replyTo.getCreatedOn(), replyTo.getCreatedBy()));
}
@Begin(flushMode = FlushModeType.MANUAL)
public void newReplyToComment(Long commentId, boolean quote) {
showForm = true;
// Take content from other comment
Comment foundCommment = restrictedEntityManager.find(Comment.class, commentId);
createComment(foundCommment, quote);
}
@Begin(flushMode = FlushModeType.MANUAL)
public void newReplyToTopic(Long topicId, boolean quote) {
showForm = true;
// Take content from topic
ForumTopic topic = restrictedEntityManager.find(ForumTopic.class, topicId);
createComment(topic, quote);
}
@End
public void cancel() {
showForm = false;
}
@End
@RaiseEvent("Forum.replyPersisted")
public void persist() {
Document doc = restrictedEntityManager.find(Document.class, currentDocument.getId());
comment.setDocument(doc);
// TODO: Break this, for performance reasons... doc.getComments().add(comment);
restrictedEntityManager.persist(comment);
StringBuilder feedEntryTitle = new StringBuilder();
if (doc.getName().equals(comment.getSubject())) {
feedEntryTitle.append("[").append(doc.getParent().getName()).append("] ");
feedEntryTitle.append( Messages.instance().get("forum.label.reply.FeedEntryTitlePrefix") );
feedEntryTitle.append(" ").append(comment.getSubject());
} else {
feedEntryTitle.append("[").append(doc.getParent().getName()).append("] ");
feedEntryTitle.append("(");
feedEntryTitle.append( Messages.instance().get("forum.label.reply.FeedEntryTitlePrefix") );
feedEntryTitle.append(" ").append(WikiUtil.truncateString(doc.getName(), 20, "...")).append(") ");
feedEntryTitle.append(comment.getSubject());
}
pushOnFeeds(doc, feedEntryTitle.toString());
restrictedEntityManager.flush();
restrictedEntityManager.clear();
refreshComments();
showForm = false;
}
private String quote(String text, Date date, User author) {
StringBuilder quoted = new StringBuilder();
quoted.append("<blockquote>").append("\n");
quoted.append("_").append(author.getFullname());
quoted.append(" ").append(Messages.instance().get("forum.label.WroteOn")).append(" ");
quoted.append(WikiUtil.formatDate(date)).append(":").append("_").append("<br/>\n");
quoted.append(text);
quoted.append("\n").append("</blockquote>").append("\n\n");
return quoted.toString();
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumInfo.java
Index: ForumInfo.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.wiki.core.model.Comment;
public class ForumInfo {
private boolean unreadPostings = false;
private long totalNumOfTopics;
private long totalNumOfPosts;
private ForumTopic lastTopic;
private Comment lastComment;
public ForumInfo(long totalNumOfTopics, long totalNumOfPosts) {
this.totalNumOfTopics = totalNumOfTopics;
this.totalNumOfPosts = totalNumOfPosts;
}
public boolean isUnreadPostings() {
return unreadPostings;
}
public void setUnreadPostings(boolean unreadPostings) {
this.unreadPostings = unreadPostings;
}
public long getTotalNumOfTopics() {
return totalNumOfTopics;
}
public void setTotalNumOfTopics(long totalNumOfTopics) {
this.totalNumOfTopics = totalNumOfTopics;
}
public long getTotalNumOfPosts() {
return totalNumOfPosts;
}
public void setTotalNumOfPosts(long totalNumOfPosts) {
this.totalNumOfPosts = totalNumOfPosts;
}
public ForumTopic getLastTopic() {
return lastTopic;
}
public void setLastTopic(ForumTopic lastTopic) {
this.lastTopic = lastTopic;
}
public Comment getLastComment() {
return lastComment;
}
public void setLastComment(Comment lastComment) {
this.lastComment = lastComment;
}
// Was the last post made a topic or a comment/reply
public boolean isLastPostLastTopic() {
if (lastComment == null && lastTopic != null) return true;
if (lastTopic != null && (lastTopic.getCreatedOn().getTime()>lastComment.getCreatedOn().getTime()) ) return true;
return false;
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/TopicHome.java
Index: TopicHome.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;
import org.jboss.seam.wiki.core.action.NodeHome;
import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
import org.jboss.seam.wiki.core.model.Directory;
import org.jboss.seam.wiki.core.dao.FeedDAO;
import static javax.faces.application.FacesMessage.SEVERITY_INFO;
import java.util.Date;
@Name("topicHome")
@Scope(ScopeType.CONVERSATION)
public class TopicHome extends NodeHome<ForumTopic> {
@In
Directory currentDirectory;
@In
private FeedDAO feedDAO;
private boolean showForm = false;
private String formContent;
/* -------------------------- Basic Overrides ------------------------------ */
public void create() {
super.create();
super.setParentDirectory(currentDirectory);
}
protected boolean beforePersist() {
// Sync topic content
syncFormToInstance(getParentDirectory());
// Macros
getInstance().setDefaultMacros();
// Set createdOn date _now_
getInstance().setCreatedOn(new Date());
return true;
}
/* -------------------------- Internal Methods ------------------------------ */
private void syncFormToInstance(Directory dir) {
WikiLinkResolver wikiLinkResolver = (WikiLinkResolver) Component.getInstance("wikiLinkResolver");
getInstance().setContentWithoutMacros(
wikiLinkResolver.convertToWikiProtocol(dir.getAreaNumber(), formContent)
);
}
private void syncInstanceToForm(Directory dir) {
WikiLinkResolver wikiLinkResolver = (WikiLinkResolver)Component.getInstance("wikiLinkResolver");
formContent = wikiLinkResolver.convertFromWikiProtocol(dir.getAreaNumber(), getInstance().getContentWithoutMacros());
}
/* -------------------------- Messages ------------------------------ */
protected void createdMessage() {
getFacesMessages().addFromResourceBundleOrDefault(
SEVERITY_INFO,
"lacewiki.msg.Topic.Persist",
"Topic '{0}' has been saved.",
getInstance().getName()
);
}
protected void updatedMessage() {
getFacesMessages().addFromResourceBundleOrDefault(
SEVERITY_INFO,
"lacewiki.msg.Topic.Update",
"Topic '{0}' has been updated.",
getInstance().getName()
);
}
protected void deletedMessage() {
getFacesMessages().addFromResourceBundleOrDefault(
SEVERITY_INFO,
"lacewiki.msg.Topic.Delete",
"Topic '{0}' has been deleted.",
getInstance().getName()
);
}
/* -------------------------- Public Features ------------------------------ */
@Begin(flushMode = FlushModeType.MANUAL)
public void newTopic() {
showForm = true;
// Start with a fresh instance
setInstance(createInstance());
// Get a fresh parent directory instance into the current persistence context
setParentDirectory(loadParentDirectory(getParentDirectory().getId()));
}
@End
public void cancel() {
showForm = false;
}
@End
@RaiseEvent("Forum.topicPersisted")
public String persist() {
String outcome = super.persist();
showForm = outcome == null; // Keep showing the form if there was a validation error
// Create feed entries (needs identifiers assigned, so we run after persist())
if (outcome != null) {
String feedEntryTitle = "[" + getParentDirectory().getName() + "] " + getInstance().getName();
feedDAO.createFeedEntry(getInstance(), false, feedEntryTitle);
getEntityManager().flush();
}
return outcome;
}
public boolean isShowForm() {
return showForm;
}
public void setShowForm(boolean showForm) {
this.showForm = showForm;
}
public String getFormContent() {
// Load the topic content and resolve links
if (formContent == null) syncInstanceToForm(getParentDirectory());
return formContent;
}
public void setFormContent(String formContent) {
this.formContent = formContent;
if (formContent != null) syncFormToInstance(getParentDirectory());
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumTopic.java
Index: ForumTopic.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.wiki.core.model.Document;
import org.jboss.seam.wiki.core.model.Comment;
import org.jboss.seam.wiki.core.search.annotations.Searchable;
import org.jboss.seam.wiki.util.WikiUtil;
import javax.persistence.*;
/**
* Represents a forum topic (a particular thread of discussion).
* <p>
* We re-use the <tt>Document</tt> class and extend the node hierarchy further with
* a new discriminator, <tt>FORUMTOPIC</tt>. In addition to normal document properties,
* a forum topic has a few transient properties (sticky, unread, last comment, etc.) and
* a few methods to handle macros that <i>must</i> appear before and after the topic
* content (e.g. hideControls, hideCreatorHistory, forumReplies).
* <p>
* Although pragmatic, I'm not sure we'll handle macros that way (with string concatenation)
* in the future. This should be made more generic and typesafe, I think we need macro metadata
* - which really depends on how plugin metadata will be designed.
*
* @author Christian Bauer
*/
@Entity
@DiscriminatorValue("FORUMTOPIC")
@org.hibernate.search.annotations.Indexed
@Searchable(description = "Forum Topics")
public class ForumTopic extends Document {
@Transient
protected final String[] MACROS_BEFORE_CONTENT =
{"clearBackground", "forumPosting"};
@Transient
protected final String[] MACROS_AFTER_CONTENT =
{"forumReplies", "hideControls", "hideComments", "hideTags", "hideCreatorHistory"};
@Transient
private long numOfComments;
@Transient
private boolean sticky;
@Transient
private boolean unread;
@Transient
private Comment lastComment;
public ForumTopic() {
super("New Topic");
setContentWithoutMacros("Edit this *wiki* text, the preview will update automatically.");
setNameAsTitle(false);
setEnableComments(true);
setEnableCommentForm(true);
setEnableCommentsOnFeeds(true);
}
public static ForumTopic fromArray(Object[] propertyValues) {
ForumTopic topic = (ForumTopic)propertyValues[0];
topic.setNumOfComments(propertyValues[1] != null ? (Long)propertyValues[1] : 0);
topic.setSticky(propertyValues[2] != null ? ((Integer) propertyValues[2] != 0) : false);
topic.setLastComment(propertyValues[3] != null ? (Comment)propertyValues[3] : null);
return topic;
}
public long getNumOfComments() {
return numOfComments;
}
public void setNumOfComments(long numOfComments) {
this.numOfComments = numOfComments;
}
public boolean isSticky() {
return sticky;
}
public void setSticky(boolean sticky) {
this.sticky = sticky;
}
public boolean isUnread() {
return unread;
}
public void setUnread(boolean unread) {
this.unread = unread;
}
public Comment getLastComment() {
return lastComment;
}
public void setLastComment(Comment lastComment) {
this.lastComment = lastComment;
}
public String getContentWithoutMacros() {
String content = getContent();
// Cut from first double newline to last double newline
return content.substring( content.indexOf("\n\n")+2, content.lastIndexOf("\n\n") );
}
public void setContentWithoutMacros(String content) {
// First, remove any macros that the user might have put into the text
content = WikiUtil.removeMacros(content);
// Apply the macros before and after content, separated with double newlines
StringBuilder contentWithMacros = new StringBuilder();
for (String s : MACROS_BEFORE_CONTENT) contentWithMacros.append("[<=").append(s).append("]\n");
contentWithMacros.append("\n").append(content).append("\n\n");
for (String s : MACROS_AFTER_CONTENT) contentWithMacros.append("[<=").append(s).append("]\n");
if (isSticky()) contentWithMacros.append("[<=forumStickyPosting]").append("]\n");
setContent(contentWithMacros.toString());
}
public void setDefaultMacros() {
StringBuilder macros = new StringBuilder();
for (String s : MACROS_BEFORE_CONTENT) macros.append(s).append(" ");
for (String s : MACROS_AFTER_CONTENT) macros.append(s).append(" ");
if (isSticky()) macros.append("forumStickyPosting").append(" ");
setMacros(macros.substring(0, macros.length()-1));
}
public String getIconName() {
StringBuilder iconName = new StringBuilder();
iconName.append("posting");
if (isSticky()) {
iconName.append("_sticky");
} else if (!getEnableCommentForm()) {
iconName.append("_locked");
}
if (isUnread()) iconName.append("_unread");
return iconName.toString();
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumListHome.java
Index: ForumListHome.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.annotations.*;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.ScopeType;
import org.jboss.seam.Component;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.wiki.core.model.Directory;
import org.jboss.seam.wiki.core.model.Node;
import org.jboss.seam.wiki.core.dao.NodeDAO;
import org.jboss.seam.wiki.util.WikiUtil;
import javax.persistence.EntityManager;
import java.io.Serializable;
@Name("forumListHome")
@Scope(ScopeType.PAGE)
public class ForumListHome implements Serializable {
@In
EntityManager restrictedEntityManager;
@In
ForumHome forumHome;
private boolean managed;
public boolean isManaged() {
return managed;
}
public void setManaged(boolean managed) {
this.managed = managed;
}
public void manage() {
managed = true;
}
@Restrict("#{s:hasPermission('Node', 'editMenu', currentDirectory)}")
@RaiseEvent("Forum.forumListRefresh")
public void moveNode(int currentPosition, int newPosition) {
Directory forumDirectory = (Directory)Component.getInstance("currentDirectory");
forumDirectory = restrictedEntityManager.find(Directory.class, forumDirectory.getId());
if (currentPosition != newPosition) {
// Shift and refresh displayed list
WikiUtil.shiftListElement(forumDirectory.getChildren(), currentPosition, newPosition);
// Required update, this is only refreshed on database load
for (Node node : forumDirectory.getChildren()) {
node.setDisplayPosition(forumDirectory.getChildren().indexOf(node));
}
}
Contexts.getPageContext().set("currentDirectory", forumDirectory);
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumHome.java
Index: ForumHome.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import static javax.faces.application.FacesMessage.SEVERITY_INFO;
import javax.faces.application.FacesMessage;
import org.jboss.seam.annotations.*;
import org.jboss.seam.ScopeType;
import org.jboss.seam.core.Conversation;
import org.jboss.seam.core.Events;
import org.jboss.seam.wiki.core.model.Directory;
import org.jboss.seam.wiki.core.model.Document;
import org.jboss.seam.wiki.core.action.NodeHome;
import org.jboss.seam.wiki.core.dao.FeedDAO;
import org.jboss.seam.wiki.util.WikiUtil;
import java.util.Date;
@Name("forumHome")
@Scope(ScopeType.CONVERSATION)
@AutoCreate
public class ForumHome extends NodeHome<Directory> {
@In
Directory currentDirectory;
@In
FeedDAO feedDAO;
private boolean showForm = false;
private boolean hasFeed = true;
/* -------------------------- Basic Overrides ------------------------------ */
protected Directory createInstance() {
Directory forum = super.createInstance();
forum.setName("New Forum");
hasFeed = true;
return forum;
}
public Directory find() {
Directory forum = super.find();
hasFeed = forum.getFeed()!=null;
return forum;
}
public void create() {
super.create();
setParentDirectoryId(currentDirectory.getId());
init();
}
protected boolean beforePersist() {
createOrRemoveFeed();
return super.beforePersist();
}
public String persist() {
// This is _always_ a subdirectory in an area
getInstance().setAreaNumber(getParentDirectory().getAreaNumber());
String outcome = super.persist();
if (outcome != null) {
// Default document is topic list
Document topicList = createDefaultDocument();
topicList.setAreaNumber(getInstance().getAreaNumber());
topicList.setName(getInstance().getName() + " Forum");
topicList.setWikiname(WikiUtil.convertToWikiName(topicList.getName()));
topicList.setCreatedBy(getCurrentUser());
topicList.setLastModifiedBy(getCurrentUser());
topicList.setLastModifiedOn(new Date());
getInstance().addChild(topicList);
getInstance().setDefaultDocument(topicList);
getEntityManager().persist(topicList);
getEntityManager().flush();
endConversation();
}
return null; // Prevent navigation
}
protected boolean beforeUpdate() {
createOrRemoveFeed();
return super.beforeUpdate();
}
public String update() {
String outcome = super.update();
if (outcome != null) endConversation();
return null; // Prevent navigation
}
protected boolean beforeRemove() {
// Remove all children (nested, recursively, udpates the second-level cache)
getNodeDAO().removeChildren(getInstance());
return true;
}
public String remove() {
String outcome = super.remove();
if (outcome != null) endConversation();
return null; // Prevent navigation
}
/* -------------------------- Messages ------------------------------ */
protected void createdMessage() {
getFacesMessages().addFromResourceBundleOrDefault(
SEVERITY_INFO,
"forum.msg.Forum.Persist",
"Forum '{0}' has been saved.",
getInstance().getName()
);
}
protected void updatedMessage() {
getFacesMessages().addFromResourceBundleOrDefault(
SEVERITY_INFO,
"forum.msg.Forum.Update",
"Forum '{0}' has been updated.",
getInstance().getName()
);
}
protected void deletedMessage() {
getFacesMessages().addFromResourceBundleOrDefault(
SEVERITY_INFO,
"forum.msg.Forum.Delete",
"Forum '{0}' has been deleted.",
getInstance().getName()
);
}
/* -------------------------- Internal Methods ------------------------------ */
private void endConversation() {
showForm = false;
Conversation.instance().end();
getEntityManager().clear(); // Need to force re-read in the forum list refresh
Events.instance().raiseEvent("Forum.forumListRefresh");
}
private Document createDefaultDocument() {
Document doc = new Document();
doc.setNameAsTitle(true);
doc.setReadAccessLevel(getInstance().getReadAccessLevel());
doc.setWriteAccessLevel(getInstance().getWriteAccessLevel());
doc.setEnableComments(false);
doc.setEnableCommentForm(false);
String[] defaultMacros = {"clearBackground", "hideControls", "hideComments", "hideTags", "hideCreatorHistory", "forumTopics"};
StringBuilder contentWithMacros = new StringBuilder();
StringBuilder macros = new StringBuilder();
for (String s : defaultMacros) {
contentWithMacros.append("[<=").append(s).append("]\n");
macros.append(s).append(" ");
}
doc.setContent(contentWithMacros.toString());
doc.setMacros(macros.substring(0, macros.length()-1));
return doc;
}
public void createOrRemoveFeed() {
if (hasFeed && getInstance().getFeed() == null) {
// Does not have a feed but user wants one, create it
feedDAO.createFeed(getInstance());
getFacesMessages().addFromResourceBundleOrDefault(
FacesMessage.SEVERITY_INFO,
"forum.msg.Feed.Create",
"Created syndication feed for this forum");
} else if (!hasFeed && getInstance().getFeed() != null) {
// Does have feed but user doesn't want it anymore... delete it
feedDAO.removeFeed(getInstance());
getFacesMessages().addFromResourceBundleOrDefault(
FacesMessage.SEVERITY_INFO,
"forum.msg.Feed.Remove",
"Removed syndication feed of this forum");
} else if (getInstance().getFeed() != null) {
// Does have a feed and user still wants it, update the feed
feedDAO.updateFeed(getInstance());
}
}
/* -------------------------- Public Features ------------------------------ */
public boolean isShowForm() {
return showForm;
}
public void setShowForm(boolean showForm) {
this.showForm = showForm;
}
public boolean isHasFeed() {
return hasFeed;
}
public void setHasFeed(boolean hasFeed) {
this.hasFeed = hasFeed;
}
@Begin(flushMode = FlushModeType.MANUAL)
public void newForum() {
init();
showForm = true;
}
@Begin(flushMode = FlushModeType.MANUAL)
public void edit(Long forumId) {
setId(forumId);
init();
showForm = true;
}
public void cancel() {
endConversation();
}
public void resetFeed() {
if (getInstance().getFeed() != null) {
getLog().debug("resetting feed of directory");
getInstance().getFeed().getFeedEntries().clear();
getInstance().getFeed().setPublishedDate(new Date());
getFacesMessages().addFromResourceBundleOrDefault(
FacesMessage.SEVERITY_INFO,
"forum.msg.Feed.Reset",
"Queued removal of all feed entries from the syndication feed of this directory, please update to finalize");
}
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumDAO.java
Index: ForumDAO.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.wiki.core.model.Directory;
import org.jboss.seam.wiki.core.model.Comment;
import org.hibernate.Session;
import org.hibernate.ScrollableResults;
import org.hibernate.transform.ResultTransformer;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Date;
@Name("forumDAO")
@AutoCreate
public class ForumDAO {
@In
EntityManager entityManager;
@In
EntityManager restrictedEntityManager;
public List<Directory> findForums(Directory forumDirectory) {
return getSession(true).getNamedQuery("forums")
.setParameter("parentDir", forumDirectory)
.list();
}
public Map<Long, ForumInfo> findForumInfo(Directory forumDirectory) {
final Map<Long, ForumInfo> forumInfoMap = new HashMap<Long, ForumInfo>();
// Append thread and posting count
getSession(true).getNamedQuery("forumTopicPostCount")
.setParameter("parentDir", forumDirectory)
.setResultTransformer(
new ResultTransformer() {
public Object transformTuple(Object[] result, String[] strings) {
forumInfoMap.put(
(Long) result[0],
new ForumInfo( (Long)result[1], (Long)result[2])
);
return null;
}
public List transformList(List list) { return list; }
}
)
.list();
// Append last topic Document
getSession(true).getNamedQuery("forumLastTopic")
.setParameter("parentDir", forumDirectory)
.setResultTransformer(
new ResultTransformer() {
public Object transformTuple(Object[] result, String[] strings) {
if (forumInfoMap.containsKey((Long)result[0]))
forumInfoMap.get( (Long)result[0] ).setLastTopic( (ForumTopic)result[1] );
return null;
}
public List transformList(List list) { return list; }
}
)
.list();
// Append last reply Comment
getSession(true).getNamedQuery("forumLastComment")
.setParameter("nsLeft", forumDirectory.getNsLeft())
.setParameter("nsRight", forumDirectory.getNsRight())
.setParameter("nsThread", forumDirectory.getNsThread())
.setResultTransformer(
new ResultTransformer() {
public Object transformTuple(Object[] result, String[] strings) {
if (forumInfoMap.containsKey((Long)result[0]))
forumInfoMap.get( (Long)result[0] ).setLastComment( (Comment)result[1] );
return null;
}
public List transformList(List list) { return list; }
}
)
.list();
return forumInfoMap;
}
public Long findTopicCount(Directory forum) {
ScrollableResults cursor =
getSession(true).getNamedQuery("forumTopics")
.setParameter("forum", forum)
.scroll();
cursor.last();
Long count = cursor.getRowNumber() + 1l;
cursor.close();
return count;
}
public List<ForumTopic> findTopics(Directory forum, long firstResult, long maxResults) {
return getSession(true).getNamedQuery("forumTopics")
.setParameter("forum", forum)
.setResultTransformer(
new ResultTransformer() {
public Object transformTuple(Object[] result, String[] strings) {
return ForumTopic.fromArray(result);
}
public List transformList(List list) { return list; }
}
)
.setFirstResult(new Long(firstResult).intValue())
.setMaxResults(new Long(maxResults).intValue())
.list();
}
public List<ForumTopic> findUnreadTopics(Date lastLoginDate) {
return getSession(true).getNamedQuery("forumUnreadTopics")
.setParameter("lastLoginDate", lastLoginDate)
.list();
}
private Session getSession(boolean restricted) {
if (restricted) {
return ((Session)((org.jboss.seam.persistence.EntityManagerProxy) restrictedEntityManager).getDelegate());
} else {
return ((Session)((org.jboss.seam.persistence.EntityManagerProxy) entityManager).getDelegate());
}
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumQueries.hbm.xml
Index: ForumQueries.hbm.xml
===================================================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<query name="forums">
select
f
from
Directory f left join fetch f.feed
where
f.parent = :parentDir
order by f.displayPosition asc
</query>
<query name="forumTopicPostCount">
select
f.id, count(distinct child), count(distinct child) + count(distinct comment)
from
Directory f
left outer join f.children as child
left outer join child.comments as comment
where
f.parent = :parentDir
and child != f.defaultDocument
group
by f.id
</query>
<query name="forumLastTopic">
select
f.id, lt
from
Directory f left outer join f.children as lt left join fetch lt.createdBy u join fetch u.profile
where
f.parent = :parentDir
and lt != f.defaultDocument
and lt.displayPosition = (select max(n.displayPosition) from Node n where n.parent = f)
</query>
<!-- This only uses the timestamp of all comments to identify the last comment - is that enough? -->
<query name="forumLastComment"><![CDATA[
select
f.id, c
from
Comment c left join fetch c.fromUser u join fetch u.profile, Document d, Directory f join fetch c.document
where
c.createdOn =
(select max(com.createdOn) from Document doc, Comment com where
doc.nsLeft > :nsLeft and doc.nsRight < :nsRight and doc.nsThread = :nsThread
and com.document = doc)
and c.document = d
and d.parent = f
]]></query>
<!-- Somewhat ugly workarounds for the missing case...when support in HQL select clause -->
<query name="forumTopics"><![CDATA[
select
t,
count(c),
locate('forumStickyPosting', t.macros, 1),
c2
from
Directory f,
ForumTopic t
join fetch t.createdBy u join fetch u.profile up
left outer join t.comments c
left outer join t.comments c2 left join fetch c2.fromUser u2 left join fetch u2.profile u2p
where
f = :forum
and t.parent = f
and t != f.defaultDocument
and (c2.createdOn = (select max(com.createdOn) from Comment com where com.document = t) or c2 is null)
group by t.id, t.class, t.version, t.nsLeft, t.nsRight, t.nsThread, t.parent,
t.areaNumber, t.createdBy, t.createdOn, t.lastModifiedBy, t.lastModifiedOn, t.menuItem, t.name, t.displayPosition,
t.readAccessLevel, t.revision, t.wikiname, t.writeAccessLevel, t.tags,
t.enableComments, t.enableCommentForm, t.enableCommentsOnFeeds, t.nameAsTitle, t.macros,
locate('forumStickyPosting', t.macros, 1),
c2.id, c2.version, c2.document, c2.subject, c2.fromUser, c2.fromUserName, c2.fromUserEmail, c2.fromUserHomepage, c2.text, c2.useWikiText, c2.createdOn,
u.id, u.version, u.firstname, u.lastname, u.username, u.passwordHash, u.email, u.activated, u.activationCode, u.createdOn, u.lastLoginOn, u.memberHome, u.profile,
up.id, up.version, up.createdOn, up.bio, up.website, up.location, up.occupation, up.signature, up.imageContentType,
u2.id, u2.version, u2.firstname, u2.lastname, u2.username, u2.passwordHash, u2.email, u2.activated, u2.activationCode, u2.createdOn, u.lastLoginOn, u2.memberHome, u2.profile,
u2p.id, u2p.version, u2p.createdOn, u2p.bio, u2p.website, u2p.location, u2p.occupation, u2p.signature, u2p.imageContentType
order by case locate('forumStickyPosting', t.macros, 1) when '0' then '0' else '1' end desc, t.createdOn desc, c2.createdOn desc
]]></query>
<query name="forumUnreadTopics"><![CDATA[
select
distinct t
from ForumTopic t left join fetch t.parent left outer join t.comments c
where
t.createdOn > :lastLoginDate
or
c.createdOn > :lastLoginDate
]]></query>
</hibernate-mapping>
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumSearchSupport.java
Index: ForumSearchSupport.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.wiki.core.search.metamodel.SearchSupport;
import org.jboss.seam.wiki.core.search.metamodel.SearchableEntityHandler;
import org.jboss.seam.wiki.core.search.SearchHit;
import org.jboss.seam.wiki.util.WikiUtil;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight.*;
import java.util.HashSet;
import java.util.Set;
@Name("forumSearchSupport")
public class ForumSearchSupport extends SearchSupport {
public Set<SearchableEntityHandler> getSearchableEntityHandlers() {
return new HashSet<SearchableEntityHandler>() {{
add(
new SearchableEntityHandler<ForumTopic>() {
public boolean isReadAccessChecked() {
return true;
}
public SearchHit extractHit(Query query, ForumTopic forumTopic) throws Exception {
return new SearchHit(
ForumTopic.class.getSimpleName(),
"icon.posting.gif",
escapeBestFragments(query, new NullFragmenter(), forumTopic.getName(), 0, 0),
WikiUtil.renderURL(forumTopic),
escapeBestFragments(query, new SimpleFragmenter(100), forumTopic.getContent(), 5, 350)
);
}
}
);
}};
}
}
1.1 date: 2007/11/09 15:00:28; author: cbauer; state: Exp;jboss-seam/examples/wiki/src/main/org/jboss/seam/wiki/plugin/forum/ForumCookie.java
Index: ForumCookie.java
===================================================================
package org.jboss.seam.wiki.plugin.forum;
import org.jboss.seam.annotations.*;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.HashMap;
import java.net.URLEncoder;
import java.net.URLDecoder;
/**
* Simplifes storing of cookie values in a temporary (browser-bound)
* coookie. Use <tt>forumCookie.addCookieValue(key, value)</tt> to add a string
* value to the cookie value map. Do not use the characters "=" and ";" in
* either keys or values. The cookie is also bound to the current HTTP session
* by appending the session identifier to the value. This means that the
* maximum lifetime of cookie values is in fact the session, not the browser
* instance.
* <p>
* One issue is that Tomcat apparently re-uses the session identifier if no
* session exists but a JSESSIONID cookie was present in the request. That means
* this code works only halfway, because we no longer can uniquely identify
* sessions by their identifier.
* <p>
* TODO: This class could be made generic (customizable cookie settings) and added to Seam?
*
* @author Christian Bauer
*/
@Name("forumCookie")
@AutoCreate
public class ForumCookie {
public static final String COOKIE_NAME = "lacewiki_forum_topics";
private static final String SESSION_KEY = "lacewiki_session_id";
@In
FacesContext facesContext;
private Map<String, String> cookieValues;
public Map<String, String> getCookieValues() {
return cookieValues;
}
public void addCookieValue(String key, String value) {
cookieValues.put(key, value);
createCookie();
}
@Create
public void create() {
readCookie();
if (getCookieValues() == null) {
cookieValues = new HashMap<String, String>();
cookieValues.put(SESSION_KEY, getSessionId());
createCookie();
}
}
private void readCookie() {
if (getCookie() != null) {
Map<String, String> values = decode(getCookie().getValue());
if (values.get(SESSION_KEY).equals(getSessionId())) {
cookieValues = values;
}
}
}
private void createCookie() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx != null) {
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
Cookie newCookie = new Cookie(COOKIE_NAME, encode(cookieValues));
newCookie.setMaxAge(-1); // Delete when browser closes
newCookie.setPath(ctx.getExternalContext().getRequestContextPath());
response.addCookie(newCookie);
}
}
private Cookie getCookie() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx != null) {
for (Map.Entry<String, Object> entry : ctx.getExternalContext().getRequestCookieMap().entrySet()) {
}
return (Cookie) ctx.getExternalContext().getRequestCookieMap().get(COOKIE_NAME);
} else {
return null;
}
}
@Observer(value = "org.jboss.seam.loggedOut", create = true)
public void destroyCookie() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx != null) {
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
Cookie newCookie = new Cookie(COOKIE_NAME, null);
newCookie.setMaxAge(0);
newCookie.setPath(ctx.getExternalContext().getRequestContextPath());
response.addCookie(newCookie);
}
}
private String getSessionId() {
return ((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()).getSession().getId();
}
private String encode(Map<String, String> keyValuePairs) {
StringBuilder cookieValue = new StringBuilder();
for (Map.Entry<String, String> entry : keyValuePairs.entrySet()) {
cookieValue.append(entry.getKey()).append("=").append(entry.getValue()).append(";");
}
String cookieValueEncoded;
try {
cookieValueEncoded = URLEncoder.encode(cookieValue.toString(), "UTF-8");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return cookieValueEncoded;
}
private Map<String, String> decode(String cookieValue) {
Map<String, String> keyValuePairs = new HashMap<String, String>();
String cookieValueDecoded;
try {
cookieValueDecoded = URLDecoder.decode(cookieValue, "UTF-8");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
String[] keyValuePair = cookieValueDecoded.split(";");
for (String keyValueString : keyValuePair) {
String[] keyValue = keyValueString.split("=");
keyValuePairs.put(keyValue[0], keyValue[1]);
}
return keyValuePairs;
}
}
More information about the jboss-cvs-commits
mailing list