latin1seopermalinkprovider.java

### File Source: latin1seopermalinkprovider.java

         1  package net.sourceforge.pebble.permalink;
         2
         3  import net.sourceforge.pebble.api.permalink.PermalinkProvider;
         4  import net.sourceforge.pebble.domain.*;
         5
         6  import java.text.SimpleDateFormat;
         7  import java.util.HashMap;
         8  import java.util.Iterator;
         9  import java.util.List;
        10
        11  /**
        12   * Generates permalinks based upon the blog entry title. This implementation
        13   * retains characters from the latin1 character by converting
        14   * them to suitable "url-friendly" counterparts.
        15   *
        16   * It also uses dashes instead of underscores for whitespace as this is
        17   * what Google recommends.
        18
        19   * For titles without characters from the latin1 character set
        20   * the blog entry ID is used for the permalink instead.
        21   *
        22   * @author Mattias Reichel
        23   */
             /*
        P/P   *  Method: void net.sourceforge.pebble.permalink.Latin1SeoPermalinkProvider()
              */
        24  public class Latin1SeoPermalinkProvider implements PermalinkProvider {
        25
        26      /** the regex used to check for a day request */
        27      private static final String DAY_PERMALINK_REGEX = "/\\d\\d\\d\\d/\\d\\d/\\d\\d";
        28
        29      /** the regex used to check for a monthly blog request */
        30      private static final String MONTH_PERMALINK_REGEX = "/\\d\\d\\d\\d/\\d\\d";
        31
        32      /** the regex used to check for a blog entry permalink */
        33      private static final String BLOG_ENTRY_PERMALINK_REGEX = "/[\\w-]*";
        34
        35      /** the Blog associated with this provider instance */
        36      private Blog blog;
        37
        38      /**
        39       * Gets the blog associated with this provider instance.
        40       *
        41       * @return  a Blog instance
        42       */
        43      public Blog getBlog() {
                   /*
        P/P         *  Method: Blog getBlog()
                    *
                    *  Preconditions:
                    *    init'ed(this.blog)
                    *
                    *  Postconditions:
                    *    return_value == this.blog
                    *    init'ed(return_value)
                    */
        44        return this.blog;
        45      }
        46
        47      /**
        48       * Sets the blog associated with this provider instance.
        49       *
        50       * @param blog    a Blog instance
        51       */
        52      public void setBlog(Blog blog) {
                   /*
        P/P         *  Method: void setBlog(Blog)
                    *
                    *  Postconditions:
                    *    this.blog == blog
                    *    init'ed(this.blog)
                    */
        53        this.blog = blog;
        54      }
        55
        56      /**
        57       * Gets the permalink for a blog entry.
        58       *
        59       * @return  a URI as a String
        60       */
        61      public synchronized String getPermalink(BlogEntry blogEntry) {
                     /*
        P/P           *  Method: String getPermalink(BlogEntry)
                      *
                      *  Presumptions:
                      *    net.sourceforge.pebble.domain.Blog:getBlogEntries(...)@66 != null
                      *    net.sourceforge.pebble.domain.BlogEntry:getTitle(...)@62 != null
                      *    net.sourceforge.pebble.domain.BlogEntry:getTitle(...)@71 != null
                      *    net.sourceforge.pebble.domain.BlogService:getBlogEntry(...)@70 != null
                      *
                      *  Preconditions:
                      *    blogEntry != null
                      *    (soft) this.blog != null
                      *
                      *  Presumptions:
                      *    java.util.List:get(...)@70 != null
                      *    java.util.List:indexOf(...)@68 - java.util.List:size(...)@68 in -232..6_442_450_942
                      *    java.util.List:size(...)@68 >= -231+1
                      *
                      *  Postconditions:
                      *    return_value != null
                      *
                      *  Test Vectors:
                      *    net.sourceforge.pebble.domain.BlogEntry:getTitle(...)@62: Addr_Set{null}, Inverse{null}
                      *    java.lang.String:equals(...)@71: {0}, {1}
                      *    java.lang.String:length(...)@62: {1..232-1}, {0}
                      */
        62          if (blogEntry.getTitle() == null || blogEntry.getTitle().length() == 0) {
        63              return buildPermalink(blogEntry);
        64          } else {
        65              BlogService service = new BlogService();
        66              List entries = getBlog().getBlogEntries();
        67              int count = 0;
        68              for (int i = entries.size() - 1; i > entries.indexOf(blogEntry.getId()); i--) {
        69                  try {
        70                      BlogEntry entry = service.getBlogEntry(getBlog(), "" + ((BlogEntry)entries.get(i)).getId());
        71                      if (entry.getTitle().equals(blogEntry.getTitle())) {
        72                          count++;
        73                      }
        74                  } catch (BlogServiceException e) {
        75                      // do nothing
        76                  }
        77              }
        78
        79              if (count == 1) {
        80                  return buildPermalink(blogEntry);
        81              } else {
        82                  return buildPermalink(blogEntry) + "_" + blogEntry.getId();
        83              }
        84          }
        85      }
        86
        87      private String buildPermalink(BlogEntry blogEntry) {
                     /*
        P/P           *  Method: String buildPermalink(BlogEntry)
                      *
                      *  Test Vectors:
                      *    net.sourceforge.pebble.domain.BlogEntry:getTitle(...)@88: Addr_Set{null}, Inverse{null}
                      *
                      *  Preconditions:
                      *    blogEntry != null
                      *
                      *  Postconditions:
                      *    return_value != null
                      *
                      *  Test Vectors:
                      *    java.lang.String:length(...)@104: {1..232-1}, {0}
                      *    java.lang.String:length(...)@89: {1..232-1}, {0}
                      *    java.util.Iterator:hasNext(...)@94: {1}, {0}
                      */
        88          String title = blogEntry.getTitle();
        89          if (title == null || title.length() == 0) {
        90              title = "" + blogEntry.getId();
        91          } else {
        92              title = title.toLowerCase();
        93              title = title.replaceAll("[\\. ,;/\\\\_]", "-"); // Change whitespace and punctuation marks to dashes
        94              for(String search : characterSubstitutions.keySet()) {
        95                  title = title.replaceAll(search, characterSubstitutions.get(search));
        96              }
        97              title = title.replaceAll("[^a-z0-9-]", "");
        98              title = title.replaceAll("-+", "-");
        99              title = title.replaceAll("^-*", "");
       100              title = title.replaceAll("-*$", "");
       101          }
       102
       103          // if the title has been blanked out, use the blog entry instead
       104          if (title == null || title.length() == 0) {
       105              title = "" + blogEntry.getId();
       106          }
       107
       108          return "/" + title;
       109      }
       110
       111
       112      public boolean isBlogEntryPermalink(String uri) {
                     /*
        P/P           *  Method: bool isBlogEntryPermalink(String)
                      *
                      *  Postconditions:
                      *    init'ed(return_value)
                      *
                      *  Test Vectors:
                      *    uri: Addr_Set{null}, Inverse{null}
                      */
       113          if(uri != null) {
       114              return uri.matches(BLOG_ENTRY_PERMALINK_REGEX);
       115          } else {
       116              return false;
       117          }
       118      }
       119
       120      public BlogEntry getBlogEntry(String uri) {
                     /*
        P/P           *  Method: BlogEntry getBlogEntry(String)
                      *
                      *  Presumptions:
                      *    net.sourceforge.pebble.domain.Blog:getBlogEntries(...)@122 != null
                      *    net.sourceforge.pebble.domain.BlogEntry:getLocalPermalink(...)@128 != null
                      *    net.sourceforge.pebble.domain.BlogService:getBlogEntry(...)@125 != null
                      *
                      *  Preconditions:
                      *    this.blog != null
                      *
                      *  Presumptions:
                      *    java.util.Iterator:next(...)@125 != null
                      *
                      *  Postconditions:
                      *    init'ed(return_value)
                      *
                      *  Test Vectors:
                      *    java.lang.String:endsWith(...)@128: {0}, {1}
                      *    java.util.Iterator:hasNext(...)@123: {1}, {0}
                      */
       121          BlogService service = new BlogService();
       122          Iterator it = getBlog().getBlogEntries().iterator();
       123          while(it.hasNext()) {
       124              try {
       125                  BlogEntry blogEntry = service.getBlogEntry(getBlog(), "" + ((BlogEntry)it.next()).getId());
       126                  // use the local permalink, just in case the entry has been aggregated
       127                  // and an original permalink assigned
       128                  if (blogEntry.getLocalPermalink().endsWith(uri)) {
       129                      return blogEntry;
       130                  }
       131              } catch (BlogServiceException e) {
       132                  // do nothing
       133              }
       134          }
       135
       136          return null;
       137      }
       138
       139      /**
       140       * Gets the permalink for a monthly blog.
       141       *
       142       * @param month a Month instance
       143       * @return a URI as a String
       144       */
       145      public String getPermalink(Month month) {
                   /*
        P/P         *  Method: String getPermalink(Month)
                    *
                    *  Preconditions:
                    *    month != null
                    *    this.blog != null
                    *
                    *  Postconditions:
                    *    init'ed(return_value)
                    */
       146        SimpleDateFormat format = new SimpleDateFormat("'/'yyyy'/'MM");
       147        format.setTimeZone(blog.getTimeZone());
       148        return format.format(month.getDate());
       149      }
       150
       151      /**
       152       * Determines whether the specified URI is a monthly blog permalink.
       153       *
       154       * @param uri   a relative URI
       155       * @return      true if the URI represents a permalink to a monthly blog,
       156       *              false otherwise
       157       */
       158      public boolean isMonthPermalink(String uri) {
                   /*
        P/P         *  Method: bool isMonthPermalink(String)
                    *
                    *  Postconditions:
                    *    init'ed(return_value)
                    *
                    *  Test Vectors:
                    *    uri: Addr_Set{null}, Inverse{null}
                    */
       159        if (uri != null) {
       160          return uri.matches(MONTH_PERMALINK_REGEX);
       161        } else {
       162          return false;
       163        }
       164      }
       165
       166      /**
       167       * Gets the monthly blog referred to by the specified URI.
       168       *
       169       * @param uri   a relative URI
       170       * @return  a Month instance, or null if one can't be found
       171       */
       172      public Month getMonth(String uri) {
                   /*
        P/P         *  Method: Month getMonth(String)
                    *
                    *  Postconditions:
                    *    init'ed(return_value)
                    *
                    *  Preconditions:
                    *    this.blog != null
                    *    uri != null
                    */
       173        String year = uri.substring(1, 5);
       174        String month = uri.substring(6, 8);
       175
       176        return getBlog().getBlogForMonth(Integer.parseInt(year), Integer.parseInt(month));
       177      }
       178
       179      /**
       180       * Gets the permalink for a day.
       181       *
       182       * @param day a Day instance
       183       * @return a URI as a String
       184       */
       185      public String getPermalink(Day day) {
                   /*
        P/P         *  Method: String getPermalink(Day)
                    *
                    *  Preconditions:
                    *    day != null
                    *    this.blog != null
                    *
                    *  Postconditions:
                    *    init'ed(return_value)
                    */
       186        SimpleDateFormat format = new SimpleDateFormat("'/'yyyy'/'MM'/'dd");
       187        format.setTimeZone(blog.getTimeZone());
       188        return format.format(day.getDate());
       189      }
       190
       191      /**
       192       * Determines whether the specified URI is a day permalink.
       193       *
       194       * @param uri   a relative URI
       195       * @return      true if the URI represents a permalink to a day,
       196       *              false otherwise
       197       */
       198      public boolean isDayPermalink(String uri) {
                   /*
        P/P         *  Method: bool isDayPermalink(String)
                    *
                    *  Postconditions:
                    *    init'ed(return_value)
                    *
                    *  Test Vectors:
                    *    uri: Addr_Set{null}, Inverse{null}
                    */
       199        if (uri != null) {
       200          return uri.matches(DAY_PERMALINK_REGEX);
       201        } else {
       202          return false;
       203        }
       204      }
       205
       206      /**
       207       * Gets the day referred to by the specified URI.
       208       *
       209       * @param uri   a relative URI
       210       * @return  a Day instance, or null if one can't be found
       211       */
       212      public Day getDay(String uri) {
                   /*
        P/P         *  Method: Day getDay(String)
                    *
                    *  Postconditions:
                    *    init'ed(return_value)
                    *
                    *  Preconditions:
                    *    this.blog != null
                    *    uri != null
                    */
       213        String year = uri.substring(1, 5);
       214        String month = uri.substring(6, 8);
       215        String day = uri.substring(9, 11);
       216
       217        return getBlog().getBlogForDay(Integer.parseInt(year),
       218           Integer.parseInt(month), Integer.parseInt(day));
       219      }
       220
       221
       222      /** the List of characters that will be substituted */
       223      private static final HashMap<String,String> characterSubstitutions;
       224      static {
       225
                     /*
        P/P           *  Method: net.sourceforge.pebble.permalink.Latin1SeoPermalinkProvider__static_init
                      *
                      *  Postconditions:
                      *    characterSubstitutions == &new HashMap(Latin1SeoPermalinkProvider__static_init#1)
                      *    new HashMap(Latin1SeoPermalinkProvider__static_init#1) num objects == 1
                      */
       226          characterSubstitutions = new HashMap<String,String>();
       227
       228          characterSubstitutions.put("\u00B2", "2");
       229          characterSubstitutions.put("\u00B3", "3");
       230
       231          characterSubstitutions.put("\u00C0", "A");
       232          characterSubstitutions.put("\u00C1", "A");
       233          characterSubstitutions.put("\u00C2", "A");
       234          characterSubstitutions.put("\u00C3", "A");
       235          characterSubstitutions.put("\u00C4", "A");
       236          characterSubstitutions.put("\u00C5", "A");
       237          characterSubstitutions.put("\u00C6", "AE");
       238          characterSubstitutions.put("\u00C7", "C");
       239          characterSubstitutions.put("\u00C8", "E");
       240          characterSubstitutions.put("\u00C9", "E");
       241          characterSubstitutions.put("\u00CA", "E");
       242          characterSubstitutions.put("\u00CB", "E");
       243          characterSubstitutions.put("\u00CC", "I");
       244          characterSubstitutions.put("\u00CD", "I");
       245          characterSubstitutions.put("\u00CE", "I");
       246          characterSubstitutions.put("\u00CF", "I");
       247
       248          characterSubstitutions.put("\u00D0", "D");
       249          characterSubstitutions.put("\u00D1", "N");
       250          characterSubstitutions.put("\u00D2", "O");
       251          characterSubstitutions.put("\u00D3", "O");
       252          characterSubstitutions.put("\u00D4", "O");
       253          characterSubstitutions.put("\u00D5", "O");
       254          characterSubstitutions.put("\u00D6", "O");
       255          characterSubstitutions.put("\u00D7", "x");
       256          characterSubstitutions.put("\u00D8", "O");
       257          characterSubstitutions.put("\u00D9", "U");
       258          characterSubstitutions.put("\u00DA", "U");
       259          characterSubstitutions.put("\u00DB", "U");
       260          characterSubstitutions.put("\u00DC", "U");
       261          characterSubstitutions.put("\u00DD", "Y");
       262          characterSubstitutions.put("\u00DE", "P");
       263          characterSubstitutions.put("\u00DF", "ss");
       264
       265          characterSubstitutions.put("\u00E0", "a");
       266          characterSubstitutions.put("\u00E1", "a");
       267          characterSubstitutions.put("\u00E2", "a");
       268          characterSubstitutions.put("\u00E3", "a");
       269          characterSubstitutions.put("\u00E4", "a");
       270          characterSubstitutions.put("\u00E5", "a");
       271          characterSubstitutions.put("\u00E6", "ae");
       272          characterSubstitutions.put("\u00E7", "c");
       273          characterSubstitutions.put("\u00E8", "e");
       274          characterSubstitutions.put("\u00E9", "e");
       275          characterSubstitutions.put("\u00EA", "e");
       276          characterSubstitutions.put("\u00EB", "e");
       277          characterSubstitutions.put("\u00EC", "i");
       278          characterSubstitutions.put("\u00ED", "i");
       279          characterSubstitutions.put("\u00EE", "i");
       280          characterSubstitutions.put("\u00EF", "i");
       281
       282          characterSubstitutions.put("\u00F0", "d");
       283          characterSubstitutions.put("\u00F1", "n");
       284          characterSubstitutions.put("\u00F2", "o");
       285          characterSubstitutions.put("\u00F3", "o");
       286          characterSubstitutions.put("\u00F4", "o");
       287          characterSubstitutions.put("\u00F5", "o");
       288          characterSubstitutions.put("\u00F6", "o");
       289          //"\u00F7", // division sign (ignore)
       290          characterSubstitutions.put("\u00F8", "o");
       291          characterSubstitutions.put("\u00F9", "u");
       292          characterSubstitutions.put("\u00FA", "u");
       293          characterSubstitutions.put("\u00FB", "u");
       294          characterSubstitutions.put("\u00FC", "u");
       295          characterSubstitutions.put("\u00FD", "y");
       296          characterSubstitutions.put("\u00FE", "p");
       297          characterSubstitutions.put("\u00FF", "y");
       298      }
       299  }

SofCheck Inspector Build Version : 2.22510

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