tagindex.java

### File Source: tagindex.java

         1  /*
         2   * Copyright (c) 2003-2006, 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    private static final Log log = LogFactory.getLog(TagIndex.class);
        51
        52    private Blog blog;
        53
        54    /** the map containing the tags */
        55    private Map<String,IndexedTag> tags = new HashMap<String,IndexedTag>();
        56
        57    /** a view onto the map, ordered by tag name */
        58    private List<Tag> orderedTags = new ArrayList<Tag>();
        59
        60    public TagIndex(Blog blog) {
        61      this.blog = blog;
        62
        63      readIndex();
        64      recalculateTagRankings();
        65    }
        66
        67    /**
        68     * Clears the index.
        69     */
        70    public void clear() {
                 /*
        P/P       *  Method: void clear()
                  *
                  *  Preconditions:
                  *    (soft) this.blog != null
                  *
                  *  Postconditions:
                  *    this.tags == &new HashMap(clear#1)
                  *    new HashMap(clear#1) num objects == 1
                  */
        71      tags = new HashMap<String,IndexedTag>();
        72      writeIndex();
        73    }
        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) {
                 /*
        P/P       *  Method: void index(Collection)
                  *
                  *  Preconditions:
                  *    blogEntries != null
                  *    (soft) net.sourceforge.pebble.domain.State__static_init.new State(State__static_init#5).name != null
                  *    (soft) this.blog != null
                  *    (soft) this.tags != null
                  *
                  *  Presumptions:
                  *    blogEntry.blog@82 != null
                  *    blogEntry.state@81 != null
                  *    blogEntry.blog.rootCategory@82 != null
                  *    blogEntry.tagsAsList@82 != null
                  *    java.util.Iterator:next(...)@81 != null
                  *    ...
                  *
                  *  Postconditions:
                  *    this.orderedTags == One-of{old this.orderedTags, &new ArrayList(recalculateTagRankings#2)}
                  *    new ArrayList(recalculateTagRankings#2) num objects <= 1
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@81: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@83: {1}, {0}
                  */
        81      for (BlogEntry blogEntry : blogEntries) {
        82        if (blogEntry.isPublished()) {
        83          for (Tag tag : blogEntry.getAllTags()) {
        84            IndexedTag t = getTag(tag.getName());
        85            t.addBlogEntry(blogEntry.getId());
        86          }
        87        }
        88      }
        89
        90      writeIndex();
        91      recalculateTagRankings();
        92    }
        93
        94    /**
        95     * Indexes a single blog entry.
        96     *
        97     * @param blogEntry   a BlogEntry instance
        98     */
        99    public synchronized void index(BlogEntry blogEntry) {
                 /*
        P/P       *  Method: void index(BlogEntry)
                  *
                  *  Preconditions:
                  *    blogEntry != null
                  *    blogEntry.state != null
                  *    (soft) blogEntry.blog != null
                  *    (soft) init'ed(blogEntry.categories)
                  *    (soft) init'ed(blogEntry.id)
                  *    (soft) init'ed(blogEntry.state.name)
                  *    (soft) blogEntry.tagsAsList != null
                  *    (soft) net.sourceforge.pebble.domain.State__static_init.new State(State__static_init#5).name != null
                  *    (soft) this.blog != null
                  *    (soft) this.tags != null
                  *    ...
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@101 != null
                  *    t.blogEntries@102 != null
                  *
                  *  Preconditions:
                  *    (soft) init'ed(blogEntry.blog.rootCategory...parent)
                  *    (soft) init'ed(blogEntry.blog.rootCategory...tagsAsList)
                  *
                  *  Postconditions:
                  *    this.orderedTags == One-of{old this.orderedTags, &new ArrayList(recalculateTagRankings#2)}
                  *    new ArrayList(recalculateTagRankings#2) num objects <= 1
                  *
                  *  Preconditions:
                  *    (soft) init'ed(blogEntry.blog.rootCategory.parent)
                  *    (soft) init'ed(blogEntry.blog.rootCategory.tagsAsList)
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@101: {1}, {0}
                  */
       100      if (blogEntry.isPublished()) {
       101        for (Tag tag : blogEntry.getAllTags()) {
       102          IndexedTag t = getTag(tag.getName());
       103          t.addBlogEntry(blogEntry.getId());
       104        }
       105
       106        writeIndex();
       107        recalculateTagRankings();
       108      }
       109    }
       110
       111    /**
       112     * Unindexes a single blog entry.
       113     *
       114     * @param blogEntry   a BlogEntry instance
       115     */
       116    public synchronized void unindex(BlogEntry blogEntry) {
                 /*
        P/P       *  Method: void unindex(BlogEntry)
                  *
                  *  Preconditions:
                  *    this.tags != null
                  *    (soft) blogEntry != null
                  *    (soft) init'ed(blogEntry.id)
                  *    (soft) this.blog != null
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@117 != null
                  *    java.util.Map:values(...)@117 != null
                  *    t.blogEntries@118 != null
                  *
                  *  Postconditions:
                  *    this.orderedTags == One-of{old this.orderedTags, &new ArrayList(recalculateTagRankings#2)}
                  *    new ArrayList(recalculateTagRankings#2) num objects <= 1
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@117: {1}, {0}
                  */
       117      for (Tag tag : tags.values()) {
       118        IndexedTag t = getTag(tag.getName());
       119        t.removeBlogEntry(blogEntry.getId());
       120      }
       121
       122      writeIndex();
       123      recalculateTagRankings();
       124    }
       125
       126    /**
       127     * Helper method to load the index.
       128     */
       129    private void readIndex() {
                 /*
        P/P       *  Method: void readIndex()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    (soft) this.tags != null
                  *
                  *  Presumptions:
                  *    blogEntries.length@140 <= 232-1
                  *    org.apache.commons.logging.LogFactory:getLog(...)@50 != null
                  *    tag.blogEntries@137 != null
                  *    tuple.length@136 >= 1
                  *
                  *  Test Vectors:
                  *    java.io.File:exists(...)@131: {0}, {1}
                  *    tuple.length@136: {1}, {2..+Inf}
                  *    tuple[1]@136: Addr_Set{null}, Inverse{null}
                  */
       130      File indexFile = new File(blog.getIndexesDirectory(), "tags.index");
       131      if (indexFile.exists()) {
       132        try {
       133          BufferedReader reader = new BufferedReader(new FileReader(indexFile));
       134          String indexEntry = reader.readLine();
       135          while (indexEntry != null) {
       136            String[] tuple = indexEntry.split("=");
       137            IndexedTag tag = getTag(tuple[0]);
       138
       139            if (tuple.length > 1 && tuple[1] != null) {
       140              String[] blogEntries = tuple[1].split(",");
       141              for (String blogEntry : blogEntries) {
       142                tag.addBlogEntry(blogEntry);
       143              }
       144            }
       145
       146            indexEntry = reader.readLine();
       147          }
       148
       149          reader.close();
       150        } catch (Exception e) {
       151          log.error("Error while reading index", e);
       152        }
       153      }
       154    }
       155
       156    /**
       157     * Helper method to write out the index to disk.
       158     */
       159    private void writeIndex() {
       160      try {
                   /*
        P/P         *  Method: void writeIndex()
                    *
                    *  Preconditions:
                    *    (soft) this.blog != null
                    *    (soft) this.tags != null
                    *
                    *  Presumptions:
                    *    java.util.Iterator:next(...)@164 != null
                    *    java.util.Map:values(...)@164 != null
                    *    org.apache.commons.logging.LogFactory:getLog(...)@50 != null
                    *
                    *  Test Vectors:
                    *    java.util.Iterator:hasNext(...)@164: {1}, {0}
                    *    java.util.Iterator:hasNext(...)@167: {1}, {0}
                    */
       161        File indexFile = new File(blog.getIndexesDirectory(), "tags.index");
       162        BufferedWriter writer = new BufferedWriter(new FileWriter(indexFile));
       163
       164        for (IndexedTag tag : tags.values()) {
       165          writer.write(tag.getName());
       166          writer.write("=");
       167          for (String blogEntry : tag.getBlogEntries()) {
       168            writer.write(blogEntry);
       169            writer.write(",");
       170          }
       171          writer.newLine();
       172        }
       173
       174        writer.flush();
       175        writer.close();
       176      } catch (Exception e) {
       177        log.error("Error while writing index", e);
       178      }
       179    }
       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) {
                 /*
        P/P       *  Method: IndexedTag getTag(String)
                  *
                  *  Preconditions:
                  *    this.tags != null
                  *    (soft) init'ed(this.blog)
                  *
                  *  Postconditions:
                  *    return_value != null
                  *    new ArrayList(IndexedTag#1) num objects <= 1
                  *    new IndexedTag(getTag#1) num objects <= 1
                  *    new IndexedTag(getTag#1).blog == this.blog
                  *    (soft) init'ed(new IndexedTag(getTag#1).blog)
                  *    new IndexedTag(getTag#1).blogEntries == &new ArrayList(IndexedTag#1)
                  *    new IndexedTag(getTag#1).name != null
                  *
                  *  Test Vectors:
                  *    java.util.Map:get(...)@189: Inverse{null}, Addr_Set{null}
                  */
       188      String encodedName = Tag.encode(name);
       189      IndexedTag tag = tags.get(encodedName);
       190      if (tag == null) {
       191        tag = new IndexedTag(name, blog);
       192        tags.put(encodedName, tag);
       193      }
       194      return tag;
       195    }
       196
       197    private synchronized void recalculateTagRankings() {
                 /*
        P/P       *  Method: void recalculateTagRankings()
                  *
                  *  Preconditions:
                  *    this.tags != null
                  *
                  *  Presumptions:
                  *    java.lang.Math:round(...)@209 in -231..232-1
                  *    java.util.Iterator:next(...)@201 != null
                  *    java.util.Iterator:next(...)@215 != null
                  *    java.util.Map:values(...)@201 != null
                  *    java.util.Map:values(...)@215 != null
                  *    ...
                  *
                  *  Postconditions:
                  *    this.orderedTags == One-of{old this.orderedTags, &new ArrayList(recalculateTagRankings#2)}
                  *    new ArrayList(recalculateTagRankings#2) num objects <= 1
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@201: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@215: {1}, {0}
                  *    java.util.List:size(...)@100: {-231..0}, {1..232-1}
                  *    java.util.Map:size(...)@198: {-231..0}, {1..232-1}
                  */
       198      if (tags.size() > 0) {
       199        // find the maximum
       200        int maxBlogEntries = 0;
       201        for (IndexedTag tag : tags.values()) {
       202          if (tag.getNumberOfBlogEntries() > maxBlogEntries) {
       203            maxBlogEntries = tag.getNumberOfBlogEntries();
       204          }
       205        }
       206
       207        int[] thresholds = new int[10];
       208        for (int i = 0; i < 10; i++) {
       209          thresholds[i] = (int)Math.round((maxBlogEntries/10.0) * (i+1));
       210        }
       211
       212        orderedTags = new ArrayList<Tag>();
       213
       214        // now rank the tags
       215        for (IndexedTag tag : tags.values()) {
       216          tag.calculateRank(thresholds);
       217
       218          if (tag.getNumberOfBlogEntries() > 0) {
       219            orderedTags.add(tag);
       220          }
       221        }
       222
       223        Collections.sort(orderedTags);
       224      }
       225
       226    }
       227
       228    /**
       229     * Gets the list of tags associated with this blog.
       230     */
       231    public List<Tag> getTags() {
                 /*
        P/P       *  Method: List getTags()
                  *
                  *  Preconditions:
                  *    init'ed(this.orderedTags)
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getTags#1)
                  *    new ArrayList(getTags#1) num objects == 1
                  */
       232      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) {
                 /*
        P/P       *  Method: List getRecentBlogEntries(Tag)
                  *
                  *  Preconditions:
                  *    tag != null
                  *    init'ed(tag.name)
                  *    this.tags != null
                  *    (soft) init'ed(this.blog)
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getRecentBlogEntries#1)
                  *    new ArrayList(getRecentBlogEntries#1) num objects == 1
                  */
       242      return new ArrayList<String>(getTag(tag.getName()).getBlogEntries());
       243    }
       244
       245  }

SofCheck Inspector Build Version : 2.22510

tagindex.java | 2010-Jun-25 19:40:32
tagindex.class | 2010-Jul-19 20:23:38