Coverage Report - net.sourceforge.pebble.index.TagIndex
 
Classes in this File Line Coverage Branch Coverage Complexity
TagIndex
73%
67/91
65%
26/40
3
 
 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  
 package net.sourceforge.pebble.index;
 33  
 
 34  
 import net.sourceforge.pebble.domain.Blog;
 35  
 import net.sourceforge.pebble.domain.BlogEntry;
 36  
 import net.sourceforge.pebble.domain.Tag;
 37  
 import org.apache.commons.logging.Log;
 38  
 import org.apache.commons.logging.LogFactory;
 39  
 
 40  
 import java.io.*;
 41  
 import java.util.*;
 42  
 
 43  
 /**
 44  
  * Represents the tag index for a blog.
 45  
  *
 46  
  * @author    Simon Brown
 47  
  */
 48  
 public class TagIndex {
 49  
 
 50  4
   private static final Log log = LogFactory.getLog(TagIndex.class);
 51  
 
 52  
   private Blog blog;
 53  
 
 54  
   /** the map containing the tags */
 55  2728
   private Map<String,IndexedTag> tags = new HashMap<String,IndexedTag>();
 56  
 
 57  
   /** a view onto the map, ordered by tag name */
 58  2728
   private List<Tag> orderedTags = new ArrayList<Tag>();
 59  
 
 60  2728
   public TagIndex(Blog blog) {
 61  2728
     this.blog = blog;
 62  
 
 63  2728
     readIndex();
 64  2728
     recalculateTagRankings();
 65  2728
   }
 66  
 
 67  
   /**
 68  
    * Clears the index.
 69  
    */
 70  
   public void clear() {
 71  36
     tags = new HashMap<String,IndexedTag>();
 72  36
     writeIndex();
 73  36
   }
 74  
 
 75  
   /**
 76  
    * Indexes one or more blog entries.
 77  
    *
 78  
    * @param blogEntries   a List of BlogEntry instances
 79  
    */
 80  
   public synchronized void index(Collection<BlogEntry> blogEntries) {
 81  36
     for (BlogEntry blogEntry : blogEntries) {
 82  36
       if (blogEntry.isPublished()) {
 83  36
         for (Tag tag : blogEntry.getAllTags()) {
 84  0
           IndexedTag t = getTag(tag.getName());
 85  0
           t.addBlogEntry(blogEntry.getId());
 86  0
         }
 87  
       }
 88  
     }
 89  
 
 90  36
     writeIndex();
 91  36
     recalculateTagRankings();
 92  36
   }
 93  
 
 94  
   /**
 95  
    * Indexes a single blog entry.
 96  
    *
 97  
    * @param blogEntry   a BlogEntry instance
 98  
    */
 99  
   public synchronized void index(BlogEntry blogEntry) {
 100  200
     if (blogEntry.isPublished()) {
 101  196
       for (Tag tag : blogEntry.getAllTags()) {
 102  4
         IndexedTag t = getTag(tag.getName());
 103  4
         t.addBlogEntry(blogEntry.getId());
 104  4
       }
 105  
 
 106  196
       writeIndex();
 107  196
       recalculateTagRankings();
 108  
     }
 109  200
   }
 110  
 
 111  
   /**
 112  
    * Unindexes a single blog entry.
 113  
    *
 114  
    * @param blogEntry   a BlogEntry instance
 115  
    */
 116  
   public synchronized void unindex(BlogEntry blogEntry) {
 117  56
     for (Tag tag : tags.values()) {
 118  0
       IndexedTag t = getTag(tag.getName());
 119  0
       t.removeBlogEntry(blogEntry.getId());
 120  0
     }
 121  
 
 122  56
     writeIndex();
 123  56
     recalculateTagRankings();
 124  56
   }
 125  
 
 126  
   /**
 127  
    * Helper method to load the index.
 128  
    */
 129  
   private void readIndex() {
 130  2728
     File indexFile = new File(blog.getIndexesDirectory(), "tags.index");
 131  2728
     if (indexFile.exists()) {
 132  
       try {
 133  0
         BufferedReader reader = new BufferedReader(new FileReader(indexFile));
 134  0
         String indexEntry = reader.readLine();
 135  0
         while (indexEntry != null) {
 136  0
           String[] tuple = indexEntry.split("=");
 137  0
           IndexedTag tag = getTag(tuple[0]);
 138  
 
 139  0
           if (tuple.length > 1 && tuple[1] != null) {
 140  0
             String[] blogEntries = tuple[1].split(",");
 141  0
             for (String blogEntry : blogEntries) {
 142  0
               tag.addBlogEntry(blogEntry);
 143  
             }
 144  
           }
 145  
 
 146  0
           indexEntry = reader.readLine();
 147  0
         }
 148  
 
 149  0
         reader.close();
 150  0
       } catch (Exception e) {
 151  0
         log.error("Error while reading index", e);
 152  0
       }
 153  
     }
 154  2728
   }
 155  
 
 156  
   /**
 157  
    * Helper method to write out the index to disk.
 158  
    */
 159  
   private void writeIndex() {
 160  
     try {
 161  324
       File indexFile = new File(blog.getIndexesDirectory(), "tags.index");
 162  324
       BufferedWriter writer = new BufferedWriter(new FileWriter(indexFile));
 163  
 
 164  324
       for (IndexedTag tag : tags.values()) {
 165  4
         writer.write(tag.getName());
 166  4
         writer.write("=");
 167  4
         for (String blogEntry : tag.getBlogEntries()) {
 168  4
           writer.write(blogEntry);
 169  4
           writer.write(",");
 170  
         }
 171  4
         writer.newLine();
 172  
       }
 173  
 
 174  324
       writer.flush();
 175  324
       writer.close();
 176  0
     } catch (Exception e) {
 177  0
       log.error("Error while writing index", e);
 178  324
     }
 179  324
   }
 180  
 
 181  
   /**
 182  
    * Gets a tag from the index, creating it if necessary.
 183  
    *
 184  
    * @param name    the tag as a String
 185  
    * @return    a Tag instance
 186  
    */
 187  
   synchronized IndexedTag getTag(String name) {
 188  12
     String encodedName = Tag.encode(name);
 189  12
     IndexedTag tag = tags.get(encodedName);
 190  12
     if (tag == null) {
 191  8
       tag = new IndexedTag(name, blog);
 192  8
       tags.put(encodedName, tag);
 193  
     }
 194  12
     return tag;
 195  
   }
 196  
 
 197  
   private synchronized void recalculateTagRankings() {
 198  3016
     if (tags.size() > 0) {
 199  
       // find the maximum
 200  4
       int maxBlogEntries = 0;
 201  4
       for (IndexedTag tag : tags.values()) {
 202  4
         if (tag.getNumberOfBlogEntries() > maxBlogEntries) {
 203  4
           maxBlogEntries = tag.getNumberOfBlogEntries();
 204  
         }
 205  
       }
 206  
 
 207  4
       int[] thresholds = new int[10];
 208  44
       for (int i = 0; i < 10; i++) {
 209  40
         thresholds[i] = (int)Math.round((maxBlogEntries/10.0) * (i+1));
 210  
       }
 211  
 
 212  4
       orderedTags = new ArrayList<Tag>();
 213  
 
 214  
       // now rank the tags
 215  4
       for (IndexedTag tag : tags.values()) {
 216  4
         tag.calculateRank(thresholds);
 217  
 
 218  4
         if (tag.getNumberOfBlogEntries() > 0) {
 219  4
           orderedTags.add(tag);
 220  
         }
 221  
       }
 222  
 
 223  4
       Collections.sort(orderedTags);
 224  
     }
 225  
 
 226  3016
   }
 227  
 
 228  
   /**
 229  
    * Gets the list of tags associated with this blog.
 230  
    */
 231  
   public List<Tag> getTags() {
 232  12
     return new ArrayList<Tag>(orderedTags);
 233  
   }
 234  
 
 235  
   /**
 236  
    * Gets the blog entries for a given tag.
 237  
    *
 238  
    * @param tag   a tag
 239  
    * @return  a List of blog entry IDs
 240  
    */
 241  
   public List<String> getRecentBlogEntries(Tag tag) {
 242  0
     return new ArrayList<String>(getTag(tag.getName()).getBlogEntries());
 243  
   }
 244  
 
 245  
 }