Coverage Report - net.sourceforge.pebble.decorator.RelatedPostsDecorator
 
Classes in this File Line Coverage Branch Coverage Complexity
RelatedPostsDecorator
93%
30/32
80%
16/20
12
 
 1  
 /*
 2  
  * Copyright (c) 2003-2011, Simon Brown
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions are met:
 7  
  *
 8  
  *   - Redistributions of source code must retain the above copyright
 9  
  *     notice, this list of conditions and the following disclaimer.
 10  
  *
 11  
  *   - Redistributions in binary form must reproduce the above copyright
 12  
  *     notice, this list of conditions and the following disclaimer in
 13  
  *     the documentation and/or other materials provided with the
 14  
  *     distribution.
 15  
  *
 16  
  *   - Neither the name of Pebble nor the names of its contributors may
 17  
  *     be used to endorse or promote products derived from this software
 18  
  *     without specific prior written permission.
 19  
  *
 20  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 21  
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  
  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 24  
  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 25  
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 26  
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 27  
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 28  
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 29  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 30  
  * POSSIBILITY OF SUCH DAMAGE.
 31  
  */
 32  
 
 33  
 package net.sourceforge.pebble.decorator;
 34  
 
 35  
 import java.util.HashSet;
 36  
 import java.util.List;
 37  
 import java.util.Set;
 38  
 
 39  
 import net.sourceforge.pebble.PluginProperties;
 40  
 import net.sourceforge.pebble.api.decorator.ContentDecoratorContext;
 41  
 import net.sourceforge.pebble.domain.Blog;
 42  
 import net.sourceforge.pebble.domain.BlogEntry;
 43  
 import net.sourceforge.pebble.domain.Tag;
 44  
 import net.sourceforge.pebble.util.I18n;
 45  
 import net.sourceforge.pebble.util.StringUtils;
 46  
 
 47  
 import org.apache.commons.logging.Log;
 48  
 import org.apache.commons.logging.LogFactory;
 49  
 
 50  
 /**
 51  
  * Adds related posts to the current post. The posts are selected by matching
 52  
  * tags of the current post to the tags of other posts in the blog. One related
 53  
  * post per tag.
 54  
  * 
 55  
  * Each blog entry can have up to six related posts or none.
 56  
  * 
 57  
  * @author Alexander Zagniotov
 58  
  */
 59  12
 public class RelatedPostsDecorator extends ContentDecoratorSupport {
 60  
 
 61  4
   private static final Log log = LogFactory.getLog(RelatedPostsDecorator.class);
 62  
 
 63  
   /** the name of the max number of posts property */
 64  
   public static final String MAX_POSTS = "RelatedPostsDecorator.maxPosts";
 65  
 
 66  
   /**
 67  
    * Decorates the specified blog entry.
 68  
    * 
 69  
    * @param context
 70  
    *          the context in which the decoration is running
 71  
    * @param blogEntry
 72  
    *          the blog entry to be decorated
 73  
    */
 74  
   public void decorate(ContentDecoratorContext context, BlogEntry blogEntry) {
 75  
 
 76  12
     PluginProperties props = blogEntry.getBlog().getPluginProperties();
 77  12
     int maxPosts = StringUtils.MAX_NUM_OF_POSTS;
 78  
 
 79  12
     if (props.hasProperty(RelatedPostsDecorator.MAX_POSTS)) {
 80  
       try {
 81  12
         maxPosts = Integer.parseInt(props.getProperty(MAX_POSTS));
 82  
       }
 83  0
       catch (NumberFormatException nfe) {
 84  0
         log.error(nfe.getMessage());
 85  
         // do nothing, the value has already been defaulted
 86  12
       }
 87  
     }
 88  
 
 89  12
     Blog blog = blogEntry.getBlog();
 90  12
     String body = blogEntry.getBody();
 91  
 
 92  12
     if (body != null && body.trim().length() > 0) {
 93  
 
 94  12
       StringBuffer buf = new StringBuffer();
 95  12
       buf.append(body);
 96  12
       buf.append("<p><b>" + I18n.getMessage(blog, "common.relatedPosts") + "</b><br />");
 97  
 
 98  
       // tags of the current entry
 99  12
       List<Tag> currentEntryTags = blogEntry.getAllTags();
 100  
 
 101  
       // all blog entries of the current blog
 102  12
       List<BlogEntry> allBlogEntries = (List<BlogEntry>) blog.getBlogEntries();
 103  
 
 104  
       // temporary holder for accumulated unique related posts.
 105  
       // using hash set assures that we wont have same related post twice for
 106  
       // different tags.
 107  12
       Set<BlogEntry> relatedEntries = new HashSet<BlogEntry>();
 108  
 
 109  12
       for (BlogEntry entry : allBlogEntries) {
 110  
 
 111  
         // don't add current entry as a related post of it self, skip it
 112  48
         if (entry.getTitle().equals(blogEntry.getTitle()))
 113  8
           continue;
 114  
 
 115  
         // loop through each of the current entry tags, and try to find related
 116  
         // post by matching current tag to the posts tags
 117  40
         for (Tag currentTag : currentEntryTags) {
 118  48
           if (entry.hasTag(currentTag.getName())) {
 119  
             // if we successfully selected related post - create hyperlink for
 120  
             // it
 121  
             // TODO: Missing escaping -- XSS vulnerabilities here :(
 122  32
             if (relatedEntries.add(entry))
 123  32
               buf.append("<a href=\"" + entry.getPermalink() + "\" rel=\"bookmark\" title=\"" + entry.getTitle()
 124  
                   + "\">" + entry.getTitle() + "</a><br />");
 125  
           }
 126  
         }
 127  
 
 128  
         // do not allow more than default amount of posts or
 129  
         // amount set through the RelatedPostsDecorator.maxPosts property
 130  40
         if (relatedEntries.size() == maxPosts) {
 131  4
           break;
 132  
         }
 133  
       }
 134  
 
 135  12
       if (relatedEntries.size() == 0)
 136  4
         buf.append("<i>" + I18n.getMessage(blog, "common.noRelatedPosts") + "</i>");
 137  
 
 138  12
       buf.append("</p><br />");
 139  12
       blogEntry.setBody(buf.toString());
 140  
     }
 141  12
   }
 142  
 }