File Source: relatedpostsdecorator.java
1 package net.sourceforge.pebble.decorator;
2
3 import java.util.HashSet;
4 import java.util.List;
5 import java.util.Set;
6
7 import net.sourceforge.pebble.PluginProperties;
8 import net.sourceforge.pebble.api.decorator.ContentDecoratorContext;
9 import net.sourceforge.pebble.domain.Blog;
10 import net.sourceforge.pebble.domain.BlogEntry;
11 import net.sourceforge.pebble.domain.Tag;
12 import net.sourceforge.pebble.util.I18n;
13 import net.sourceforge.pebble.util.StringUtils;
14
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17
18 /**
19 * Adds related posts to the current post. The posts are selected by matching
20 * tags of the current post to the tags of other posts in the blog. One related
21 * post per tag.
22 *
23 * Each blog entry can have up to six related posts or none.
24 *
25 * @author Alexander Zagniotov
26 */
/*
P/P * Method: void net.sourceforge.pebble.decorator.RelatedPostsDecorator()
*/
27 public class RelatedPostsDecorator extends ContentDecoratorSupport {
28
/*
P/P * Method: net.sourceforge.pebble.decorator.RelatedPostsDecorator__static_init
*
* Postconditions:
* init'ed(log)
*/
29 private static final Log log = LogFactory.getLog(RelatedPostsDecorator.class);
30
31 /** the name of the max number of posts property */
32 public static final String MAX_POSTS = "RelatedPostsDecorator.maxPosts";
33
34 /**
35 * Decorates the specified blog entry.
36 *
37 * @param context
38 * the context in which the decoration is running
39 * @param blogEntry
40 * the blog entry to be decorated
41 */
42 public void decorate(ContentDecoratorContext context, BlogEntry blogEntry) {
43
/*
P/P * Method: void decorate(ContentDecoratorContext, BlogEntry)
*
* Preconditions:
* blogEntry != null
*
* Presumptions:
* java.util.Iterator:next(...)@77 != null
* java.util.Iterator:next(...)@85 != null
* org.apache.commons.logging.LogFactory:getLog(...)@29 != null
*
* Test Vectors:
* java.lang.String:equals(...)@80: {0}, {1}
* java.lang.String:length(...)@60: {0}, {1..232-1}
* java.util.Iterator:hasNext(...)@77: {1}, {0}
* java.util.Iterator:hasNext(...)@85: {1}, {0}
* java.util.Set:add(...)@90: {0}, {1}
* java.util.Set:size(...)@103: {-231..-1, 1..232-1}, {0}
*
* Preconditions:
* blogEntry.blog != null
* init'ed(blogEntry.body)
* (soft) init'ed(blogEntry.categories)
* (soft) blogEntry.propertyChangeSupport != null
* (soft) blogEntry.tagsAsList != null
* (soft) init'ed(blogEntry.title)
*
* Presumptions:
* entry.blog@77 != null
* entry.blog@90 != null
* entry.tagsAsList@77 != null
* entry.title@77 != null
*
* Postconditions:
* init'ed(blogEntry.body)
*
* Preconditions:
* blogEntry.blog.pluginProperties != null
* (soft) blogEntry.blog.rootCategory != null
* (soft) init'ed(blogEntry.blog.rootCategory...parent)
* (soft) init'ed(blogEntry.blog.rootCategory...tagsAsList)
* (soft) init'ed(blogEntry.blog.rootCategory.parent)
* (soft) init'ed(blogEntry.blog.rootCategory.tagsAsList)
* (soft) blogEntry.blog.years != null
* (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
* (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
*
* Presumptions:
* entry.blog.rootCategory@77 != null
*
* Test Vectors:
* blogEntry.body: Addr_Set{null}, Inverse{null}
* net.sourceforge.pebble.PluginProperties:hasProperty(...)@47: {0}, {1}
*/
44 PluginProperties props = blogEntry.getBlog().getPluginProperties();
45 int maxPosts = StringUtils.MAX_NUM_OF_POSTS;
46
47 if (props.hasProperty(RelatedPostsDecorator.MAX_POSTS)) {
48 try {
49 maxPosts = Integer.parseInt(props.getProperty(MAX_POSTS));
50 }
51 catch (NumberFormatException nfe) {
52 log.error(nfe.getMessage());
53 // do nothing, the value has already been defaulted
54 }
55 }
56
57 Blog blog = blogEntry.getBlog();
58 String body = blogEntry.getBody();
59
60 if (body != null && body.trim().length() > 0) {
61
62 StringBuffer buf = new StringBuffer();
63 buf.append(body);
64 buf.append("<p><b>" + I18n.getMessage(blog, "common.relatedPosts") + "</b><br />");
65
66 // tags of the current entry
67 List<Tag> currentEntryTags = blogEntry.getAllTags();
68
69 // all blog entries of the current blog
70 List<BlogEntry> allBlogEntries = (List<BlogEntry>) blog.getBlogEntries();
71
72 // temporary holder for accumulated unique related posts.
73 // using hash set assures that we wont have same related post twice for
74 // different tags.
75 Set<BlogEntry> relatedEntries = new HashSet<BlogEntry>();
76
77 for (BlogEntry entry : allBlogEntries) {
78
79 // don't add current entry as a related post of it self, skip it
80 if (entry.getTitle().equals(blogEntry.getTitle()))
81 continue;
82
83 // loop through each of the current entry tags, and try to find related
84 // post by matching current tag to the posts tags
85 for (Tag currentTag : currentEntryTags) {
86 if (entry.hasTag(currentTag.getName())) {
87 // if we successfully selected related post - create hyperlink for
88 // it
89 // TODO: Missing escaping -- XSS vulnerabilities here :(
90 if (relatedEntries.add(entry))
91 buf.append("<a href=\"" + entry.getPermalink() + "\" rel=\"bookmark\" title=\"" + entry.getTitle()
92 + "\">" + entry.getTitle() + "</a><br />");
93 }
94 }
95
96 // do not allow more than default amount of posts or
97 // amount set through the RelatedPostsDecorator.maxPosts property
98 if (relatedEntries.size() == maxPosts) {
99 break;
100 }
101 }
102
103 if (relatedEntries.size() == 0)
104 buf.append("<i>" + I18n.getMessage(blog, "common.noRelatedPosts") + "</i>");
105
106 buf.append("</p><br />");
107 blogEntry.setBody(buf.toString());
108 }
109 }
110 }
SofCheck Inspector Build Version : 2.22510
| relatedpostsdecorator.java |
2010-Jun-25 19:40:32 |
| relatedpostsdecorator.class |
2010-Jul-19 20:23:40 |