blogentry.java

### File Source: blogentry.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.domain;
        33
        34  import net.sourceforge.pebble.api.event.blogentry.BlogEntryEvent;
        35  import net.sourceforge.pebble.api.event.comment.CommentEvent;
        36  import net.sourceforge.pebble.api.event.trackback.TrackBackEvent;
        37  import net.sourceforge.pebble.comparator.ResponseByDateComparator;
        38  import net.sourceforge.pebble.web.validation.ValidationContext;
        39  import net.sourceforge.pebble.trackback.TrackBackTokenManager;
        40  import org.apache.commons.logging.Log;
        41  import org.apache.commons.logging.LogFactory;
        42
        43  import java.util.*;
        44
        45  /**
        46   * Represents a blog entry.
        47   *
        48   * @author Simon Brown
        49   */
        50  public class BlogEntry extends PageBasedContent {
        51
        52    /**
        53     * the log used by this class
        54     */
               /*
        P/P     *  Method: net.sourceforge.pebble.domain.BlogEntry__static_init
                *
                *  Postconditions:
                *    init'ed(log)
                */
        55    private static Log log = LogFactory.getLog(BlogEntry.class);
        56
        57    public static final String EXCERPT_PROPERTY = "excerpt";
        58    public static final String COMMENTS_ENABLED_PROPERTY = "commentsEnabed";
        59    public static final String TRACKBACKS_ENABLED_PROPERTY = "trackBacksEnabled";
        60    public static final String ATTACHMENT_PROPERTY = "attachment";
        61    public static final String CATEGORIES_PROPERTY = "categories";
        62
        63    /** the permalink */
        64    private String permalink;
        65
        66    /**
        67     * the category that the blog entry falls into
        68     */
        69    private Set categories = new HashSet();
        70
        71    /**
        72     * the excerpt of the blog entry
        73     */
        74    private String excerpt = "";
        75
        76    /**
        77     * a flag to indicate whether comments are enabled for this entry
        78     */
        79    private boolean commentsEnabled = true;
        80
        81    /**
        82     * a flag to indicate whether TrackBacks are enabled for this entry
        83     */
        84    private boolean trackBacksEnabled = true;
        85
        86    /**
        87     * the collection of comments for the blog entry
        88     */
        89    private List comments = new ArrayList();
        90
        91    /**
        92     * the collection of trackbacks for the blog entry
        93     */
        94    private List trackBacks = new ArrayList();
        95
        96    /** the attachment for this blog entry, if applicable */
        97    private Attachment attachment;
        98
        99    /** the timezone that this entry was posted in */
       100    private String timeZoneId;
       101
       102    /**
       103     * Creates a new blog entry.
       104     *
       105     * @param blog    the owning Blog
       106     */
       107    public BlogEntry(Blog blog) {
                 /*
        P/P       *  Method: void net.sourceforge.pebble.domain.BlogEntry(Blog)
                  *
                  *  Postconditions:
                  *    this.author == &""
                  *    this.body == &""
                  *    this.excerpt == &""
                  *    this.subtitle == &""
                  *    this.tags == &""
                  *    this.tagsAsCommaSeparated == &""
                  *    this.title == &""
                  *    this.blog == blog
                  *    init'ed(this.blog)
                  *    this.categories == &new HashSet(BlogEntry#1)
                  *    ...
                  */
       108      super(blog);
       109      setPublished(false);
       110    }
       111
       112    /**
       113     * Sets the title of this blog entry.
       114     *
       115     * @param newTitle  the title as a String
       116     */
       117    public void setTitle(String newTitle) {
                 /*
        P/P       *  Method: void setTitle(String)
                  *
                  *  Preconditions:
                  *    init'ed(this.title)
                  *    this.propertyChangeSupport != null
                  *
                  *  Postconditions:
                  *    this.permalink == null
                  *    this.title == newTitle
                  *    init'ed(this.title)
                  */
       118      super.setTitle(newTitle);
       119
       120      // and cause the permalink to be re-generated
       121      this.permalink = null;
       122    }
       123
       124    /**
       125     * Gets the category of this blog entry.
       126     *
       127     * @return the category as a String
       128     */
       129    public Set<Category> getCategories() {
                 /*
        P/P       *  Method: Set getCategories()
                  *
                  *  Preconditions:
                  *    init'ed(this.categories)
                  *
                  *  Postconditions:
                  *    return_value == &new HashSet(getCategories#1)
                  *    new HashSet(getCategories#1) num objects == 1
                  */
       130      return new HashSet<Category>(categories);
       131    }
       132
       133    /**
       134     * Gets a list of all tags.
       135     *
       136     * @return  a List of tags
       137     */
       138    public List<Tag> getAllTags() {
                 /*
        P/P       *  Method: List getAllTags()
                  *
                  *  Preconditions:
                  *    init'ed(this.categories)
                  *    this.tagsAsList != null
                  *    (soft) this.blog != null
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@144 != null
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getAllTags#1)
                  *    new ArrayList(getAllTags#1) num objects == 1
                  *
                  *  Preconditions:
                  *    (soft) this.blog.rootCategory != null
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@148: {1}, {0}
                  *
                  *  Preconditions:
                  *    (soft) init'ed(this.blog.rootCategory...parent)
                  *    (soft) init'ed(this.blog.rootCategory...tagsAsList)
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@158: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@167: {1}, {0}
                  *    java.util.List:contains(...)@150: {1}, {0}
                  *
                  *  Preconditions:
                  *    (soft) init'ed(this.blog.rootCategory.parent)
                  *
                  *  Test Vectors:
                  *    java.util.List:contains(...)@160: {1}, {0}
                  *
                  *  Preconditions:
                  *    (soft) init'ed(this.blog.rootCategory.tagsAsList)
                  *
                  *  Test Vectors:
                  *    java.util.List:contains(...)@169: {1}, {0}
                  *    java.util.Set:size(...)@141: {-231..0}, {1..232-1}
                  */
       139      List<Tag> list = new ArrayList<Tag>();
       140
       141      if (getCategories().size() > 0) {
       142        Iterator it = getCategories().iterator();
       143        while (it.hasNext()) {
       144          Category category = (Category)it.next();
       145          List tagsForCategory = category.getAllTags();
       146          Collections.reverse(tagsForCategory);
       147          Iterator jt = tagsForCategory.iterator();
       148          while (jt.hasNext()) {
       149            Tag tag = (Tag)jt.next();
       150            if (!list.contains(tag)) {
       151              list.add(tag);
       152            }
       153          }
       154        }
       155      } else {
       156        List tagsForCategory = getBlog().getRootCategory().getAllTags();
       157        Iterator it = tagsForCategory.iterator();
       158        while (it.hasNext()) {
       159          Tag tag = (Tag)it.next();
       160          if (!list.contains(tag)) {
       161            list.add(tag);
       162          }
       163        }
       164      }
       165
       166      Iterator it = getTagsAsList().iterator();
       167      while (it.hasNext()) {
       168        Tag tag = (Tag)it.next();
       169        if (!list.contains(tag)) {
       170          list.add(tag);
       171        }
       172      }
       173
       174      Collections.sort(list);
       175      return list;
       176    }
       177
       178    /**
       179     * Sets the category of this blog entry.
       180     *
       181     * @param category the category as a String
       182     */
       183    public synchronized void addCategory(Category category) {
                 /*
        P/P       *  Method: void addCategory(Category)
                  *
                  *  Preconditions:
                  *    (soft) this.categories != null
                  *    (soft) this.propertyChangeSupport != null
                  *
                  *  Test Vectors:
                  *    category: Addr_Set{null}, Inverse{null}
                  *    java.util.Set:contains(...)@184: {1}, {0}
                  */
       184      if (category != null && !categories.contains(category)) {
       185        Set oldCategories = new HashSet(categories);
       186        categories.add(category);
       187        Set newCategories = new HashSet(categories);
       188        propertyChangeSupport.firePropertyChange(CATEGORIES_PROPERTY, oldCategories, newCategories);
       189      }
       190    }
       191
       192    /**
       193     * Removes all categories from this blog entry.
       194     */
       195    public synchronized void removeAllCategories() {
                 /*
        P/P       *  Method: void removeAllCategories()
                  *
                  *  Preconditions:
                  *    this.categories != null
                  *    this.propertyChangeSupport != null
                  */
       196      propertyChangeSupport.firePropertyChange(CATEGORIES_PROPERTY, new HashSet(categories), new HashSet());
       197      categories.clear();
       198    }
       199
       200    /**
       201     * Sets the categories for this blog entry.
       202     *
       203     * @param newCategories   a Collection of Category instances
       204     */
       205    public synchronized void setCategories(Collection newCategories) {
                 /*
        P/P       *  Method: void setCategories(Collection)
                  *
                  *  Preconditions:
                  *    (soft) this.categories != null
                  *    (soft) this.propertyChangeSupport != null
                  *
                  *  Test Vectors:
                  *    newCategories: Addr_Set{null}, Inverse{null}
                  *    java.util.Iterator:hasNext(...)@210: {1}, {0}
                  */
       206      if (newCategories != null) {
       207        Set oldCategories = new HashSet(categories);
       208        categories.clear();
       209        Iterator it = newCategories.iterator();
       210        while (it.hasNext()) {
       211          categories.add(it.next());
       212        }
       213        propertyChangeSupport.firePropertyChange(CATEGORIES_PROPERTY, oldCategories, new HashSet(newCategories));
       214      }
       215    }
       216
       217    /**
       218     * Determines whether this blog entry is in the specified category.
       219     *
       220     * @param category a Category instance
       221     * @return true if this entry is in the specified category,
       222     *         false otherwise
       223     */
       224    public boolean inCategory(Category category) {
                 /*
        P/P       *  Method: bool inCategory(Category)
                  *
                  *  Preconditions:
                  *    (soft) category.id != null
                  *    (soft) this.categories != null
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@228 != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    category: Addr_Set{null}, Inverse{null}
                  *    java.util.Iterator:hasNext(...)@227: {1}, {0}
                  */
       225      if (category != null) {
       226        Iterator it = categories.iterator();
       227        while (it.hasNext()) {
       228          Category c = (Category)it.next();
       229          if (c.equals(category) || c.hasParent(category)) {
       230            return true;
       231          }
       232        }
       233
       234        return false;
       235      } else {
       236        return true;
       237      }
       238    }
       239
       240    /**
       241     * Determines whether this blog entry has the specified tag.
       242     *
       243     * @param s   a String
       244     * @return true if this entry has the specified tag,
       245     *         false otherwise
       246     */
       247    public boolean hasTag(String s) {
                 /*
        P/P       *  Method: bool hasTag(String)
                  *
                  *  Preconditions:
                  *    (soft) this.blog != null
                  *    (soft) init'ed(this.categories)
                  *    (soft) this.tagsAsList != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Preconditions:
                  *    (soft) this.blog.rootCategory != null
                  *    (soft) init'ed(this.blog.rootCategory...parent)
                  *    (soft) init'ed(this.blog.rootCategory...tagsAsList)
                  *
                  *  Test Vectors:
                  *    s: Addr_Set{null}, Inverse{null}
                  *
                  *  Preconditions:
                  *    (soft) init'ed(this.blog.rootCategory.parent)
                  *    (soft) init'ed(this.blog.rootCategory.tagsAsList)
                  */
       248      if (s != null) {
       249        return getAllTags().contains(new Tag(s, getBlog()));
       250      } else {
       251        return false;
       252      }
       253    }
       254
       255    /**
       256     * Gets the content of this response.
       257     *
       258     * @return a String
       259     */
       260    public String getContent() {
                 /*
        P/P       *  Method: String getContent()
                  *
                  *  Preconditions:
                  *    init'ed(this.excerpt)
                  *    (soft) init'ed(this.body)
                  *
                  *  Postconditions:
                  *    return_value == One-of{this.excerpt, this.body}
                  *    (soft) init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    this.excerpt: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:length(...)@261: {0}, {1..232-1}
                  */
       261      if (excerpt != null && excerpt.length() > 0) {
       262        return excerpt;
       263      } else {
       264        return getBody();
       265      }
       266    }
       267
       268    /**
       269     * Gets the excerpt of this blog entry.
       270     *
       271     * @return the excerpt as a String
       272     */
       273    public String getExcerpt() {
                 /*
        P/P       *  Method: String getExcerpt()
                  *
                  *  Preconditions:
                  *    init'ed(this.excerpt)
                  *
                  *  Postconditions:
                  *    return_value == this.excerpt
                  *    init'ed(return_value)
                  */
       274      return excerpt;
       275    }
       276
       277    /**
       278     * Sets the excerpt of this blog entry.
       279     *
       280     * @param newExcerpt    the excerpt as a String
       281     */
       282    public void setExcerpt(String newExcerpt) {
                 /*
        P/P       *  Method: void setExcerpt(String)
                  *
                  *  Preconditions:
                  *    init'ed(this.excerpt)
                  *    this.propertyChangeSupport != null
                  *
                  *  Postconditions:
                  *    init'ed(this.excerpt)
                  *
                  *  Test Vectors:
                  *    newExcerpt: Addr_Set{null}, Inverse{null}
                  */
       283      if (newExcerpt != null) {
       284        newExcerpt = newExcerpt.trim();
       285      }
       286      propertyChangeSupport.firePropertyChange(EXCERPT_PROPERTY, excerpt, newExcerpt);
       287      this.excerpt = newExcerpt;
       288    }
       289
       290    /**
       291     * Gets the date that this blog entry was last updated.
       292     *
       293     * @return  a Date instance representing the time of the last comment/TrackBack
       294     */
       295    public Date getLastModified() {
                 /*
        P/P       *  Method: Date getLastModified()
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *    init'ed(this.date)
                  *    this.trackBacks != null
                  *
                  *  Presumptions:
                  *    comment.date@300 != null
                  *    java.util.Iterator:next(...)@300 != null
                  *    java.util.Iterator:next(...)@308 != null
                  *    trackBack.date@308 != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    java.util.Date:after(...)@301: {0}, {1}
                  *    java.util.Date:after(...)@309: {0}, {1}
                  *    java.util.Iterator:hasNext(...)@299: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@307: {1}, {0}
                  */
       296      Date date = getDate();
       297
       298      Iterator it = comments.iterator();
       299      while (it.hasNext()) {
       300        Comment comment = (Comment)it.next();
       301        if (comment.getDate().after(date)) {
       302          date = comment.getDate();
       303        }
       304      }
       305
       306      it = trackBacks.iterator();
       307      while (it.hasNext()) {
       308        TrackBack trackBack = (TrackBack)it.next();
       309        if (trackBack.getDate().after(date)) {
       310          date = trackBack.getDate();
       311        }
       312      }
       313
       314      return date;
       315    }
       316
       317    /**
       318     * Sets the date that this blog entry was created.
       319     *
       320     * @param newDate a java.util.Date instance
       321     */
       322    public void setDate(Date newDate) {
                 /*
        P/P       *  Method: void setDate(Date)
                  *
                  *  Preconditions:
                  *    newDate != null
                  *    init'ed(this.date)
                  *    this.propertyChangeSupport != null
                  *
                  *  Postconditions:
                  *    this.date == newDate
                  *    this.date != null
                  *    this.id != null
                  *    this.permalink == null
                  */
       323      super.setDate(newDate);
       324
       325      // and cause the permalink to be re-generated
       326      this.permalink = null;
       327    }
       328
       329    /**
       330     * Gets a permalink for this blog entry that is local to the blog. In other
       331     * words, it doesn't take into account the original permalink for
       332     * aggregated content.
       333     *
       334     * @return an absolute URL as a String
       335     */
       336    public String getLocalPermalink() {
                 /*
        P/P       *  Method: String getLocalPermalink()
                  *
                  *  Preconditions:
                  *    init'ed(this.permalink)
                  *    (soft) this.blog != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *    this.permalink == return_value
                  *
                  *  Test Vectors:
                  *    this.permalink: Inverse{null}, Addr_Set{null}
                  *    getPermalink(...)@338: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:length(...)@339: {0}, {1..232-1}
                  *
                  *  Preconditions:
                  *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                  *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                  *    (soft) init'ed(this.blog.id)
                  *    (soft) this.blog.permalinkProvider != null
                  */
       337      if (this.permalink == null) {
       338        String s = getBlog().getPermalinkProvider().getPermalink(this);
       339        if (s != null && s.length() > 0) {
       340          this.permalink = getBlog().getUrl() + s.substring(1);
       341        }
       342      }
       343
       344      return permalink;
       345    }
       346
       347    /**
       348     * Gets the attachment associated with this blog entry.
       349     *
       350     * @return  an Attachment instance, or null if one doesn't exist
       351     */
       352    public Attachment getAttachment() {
                 /*
        P/P       *  Method: Attachment getAttachment()
                  *
                  *  Preconditions:
                  *    init'ed(this.attachment)
                  *
                  *  Postconditions:
                  *    return_value == this.attachment
                  *    init'ed(return_value)
                  */
       353      return attachment;
       354    }
       355
       356    /**
       357     * Sets the attachment associated with thie blog entry.
       358     *
       359     * @param newAttachment    an Attachment instance
       360     */
       361    public void setAttachment(Attachment newAttachment) {
                 /*
        P/P       *  Method: void setAttachment(Attachment)
                  *
                  *  Preconditions:
                  *    init'ed(this.attachment)
                  *    this.propertyChangeSupport != null
                  *
                  *  Postconditions:
                  *    this.attachment == newAttachment
                  *    init'ed(this.attachment)
                  */
       362      propertyChangeSupport.firePropertyChange(ATTACHMENT_PROPERTY, attachment, newAttachment);
       363      this.attachment = newAttachment;
       364    }
       365
       366    /**
       367     * Determines whether comments are enabled for this blog entry.
       368     *
       369     * @return true if comments are enabled, false otherwise
       370     */
       371    public boolean isCommentsEnabled() {
                 /*
        P/P       *  Method: bool isCommentsEnabled()
                  *
                  *  Preconditions:
                  *    init'ed(this.commentsEnabled)
                  *
                  *  Postconditions:
                  *    return_value == this.commentsEnabled
                  *    init'ed(return_value)
                  */
       372      return this.commentsEnabled;
       373    }
       374
       375    /**
       376     * Sets whether comments are enabled for this blog entry.
       377     *
       378     * @param newCommentsEnabled true if comments should be enabled,
       379     *                        false otherwise
       380     */
       381    public void setCommentsEnabled(boolean newCommentsEnabled) {
                 /*
        P/P       *  Method: void setCommentsEnabled(bool)
                  *
                  *  Preconditions:
                  *    init'ed(this.commentsEnabled)
                  *    this.propertyChangeSupport != null
                  *
                  *  Postconditions:
                  *    this.commentsEnabled == newCommentsEnabled
                  *    init'ed(this.commentsEnabled)
                  */
       382      propertyChangeSupport.firePropertyChange(COMMENTS_ENABLED_PROPERTY, commentsEnabled, newCommentsEnabled);
       383      this.commentsEnabled = newCommentsEnabled;
       384    }
       385
       386    /**
       387     * Gets a link to the comments for this blog entry.
       388     *
       389     * @return an absolute URL as a String
       390     */
       391    public String getCommentsLink() {
                 /*
        P/P       *  Method: String getCommentsLink()
                  *
                  *  Preconditions:
                  *    init'ed(this.permalink)
                  *    (soft) this.blog != null
                  *
                  *  Postconditions:
                  *    return_value != null
                  *    init'ed(this.permalink)
                  *
                  *  Preconditions:
                  *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                  *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                  *    (soft) init'ed(this.blog.id)
                  *    (soft) this.blog.permalinkProvider != null
                  */
       392      return getLocalPermalink() + "#comments";
       393    }
       394
       395    /**
       396     * Determines whether TrackBacks are enabled for this blog entry.
       397     *
       398     * @return true if TrackBacks are enabled, false otherwise
       399     */
       400    public boolean isTrackBacksEnabled() {
                 /*
        P/P       *  Method: bool isTrackBacksEnabled()
                  *
                  *  Preconditions:
                  *    init'ed(this.trackBacksEnabled)
                  *
                  *  Postconditions:
                  *    return_value == this.trackBacksEnabled
                  *    init'ed(return_value)
                  */
       401      return this.trackBacksEnabled;
       402    }
       403
       404    /**
       405     * Sets whether TrackBacks are enabled for this blog entry.
       406     *
       407     * @param newTrackBacksEnabled true if TrackBacks should be enabled,
       408     *                          false otherwise
       409     */
       410    public void setTrackBacksEnabled(boolean newTrackBacksEnabled) {
                 /*
        P/P       *  Method: void setTrackBacksEnabled(bool)
                  *
                  *  Preconditions:
                  *    init'ed(this.trackBacksEnabled)
                  *    this.propertyChangeSupport != null
                  *
                  *  Postconditions:
                  *    this.trackBacksEnabled == newTrackBacksEnabled
                  *    init'ed(this.trackBacksEnabled)
                  */
       411      propertyChangeSupport.firePropertyChange(TRACKBACKS_ENABLED_PROPERTY, trackBacksEnabled, newTrackBacksEnabled);
       412      this.trackBacksEnabled = newTrackBacksEnabled;
       413    }
       414
       415    /**
       416     * Gets a link to the trackbacks for this blog entry.
       417     *
       418     * @return an absolute URL as a String
       419     */
       420    public String getTrackBacksLink() {
                 /*
        P/P       *  Method: String getTrackBacksLink()
                  *
                  *  Preconditions:
                  *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                  *    init'ed(this.permalink)
                  *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                  *    (soft) this.blog != null
                  *    (soft) init'ed(this.blog.id)
                  *
                  *  Postconditions:
                  *    return_value != null
                  *    init'ed(this.permalink)
                  *
                  *  Preconditions:
                  *    (soft) this.blog.permalinkProvider != null
                  */
       421      return getLocalPermalink() + "#trackbacks";
       422    }
       423
       424    /**
       425     * Gets the link that blogs can send TrackBacks too.
       426      */
       427    public String getTrackBackLink() {
                 /*
        P/P       *  Method: String getTrackBackLink()
                  *
                  *  Preconditions:
                  *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                  *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                  *    (soft) init'ed(this.blog.id)
                  *    this.blog != null
                  *    init'ed(this.id)
                  *
                  *  Presumptions:
                  *    net.sourceforge.pebble.trackback.TrackBackTokenManager:getInstance(...)@433 != null
                  *
                  *  Postconditions:
                  *    return_value != null
                  */
       428      StringBuffer link = new StringBuffer();
       429      link.append(getBlog().getUrl());
       430      link.append("addTrackBack.action?entry=");
       431      link.append(getId());
       432      link.append("&token=");
       433      link.append(TrackBackTokenManager.getInstance().generateToken());
       434
       435      return link.toString();
       436    }
       437
       438    /**
       439     * Gets a list of all comments and TrackBacks.
       440     *
       441     * @return  a List of all Response instances
       442     */
       443    public List<Response> getResponses() {
                 /*
        P/P       *  Method: List getResponses()
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *    init'ed(this.trackBacks)
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getResponses#1)
                  *    new ArrayList(getResponses#1) num objects == 1
                  */
       444      List<Response> responses = new ArrayList();
       445      responses.addAll(getComments());
       446      responses.addAll(getTrackBacks());
       447      Collections.sort(responses, new ResponseByDateComparator());
       448      return responses;
       449    }
       450
       451    /**
       452     * Gets a collection of all comments.
       453     *
       454     * @return a List of Comment instances
       455     */
       456    public List<Comment> getComments() {
                 /*
        P/P       *  Method: List getComments()
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@460 != null
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getComments#1)
                  *    new ArrayList(getComments#1) num objects == 1
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@459: {1}, {0}
                  */
       457      List<Comment> allComments = new ArrayList();
       458      Iterator it = comments.iterator();
       459      while (it.hasNext()) {
       460        allComments.addAll(getComments((Comment)it.next()));
       461      }
       462
       463      return allComments;
       464    }
       465
       466    private List<Comment> getComments(Comment comment) {
                 /*
        P/P       *  Method: List getComments(Comment)
                  *
                  *  Preconditions:
                  *    comment != null
                  *    init'ed(comment.comments)
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@471 != null
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getComments#1)
                  *    new ArrayList(getComments#1) num objects == 1
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@470: {1}, {0}
                  */
       467      List<Comment> allComments = new ArrayList();
       468      allComments.add(comment);
       469      Iterator it = comment.getComments().iterator();
       470      while (it.hasNext()) {
       471        allComments.addAll(getComments((Comment)it.next()));
       472      }
       473
       474      return allComments;
       475    }
       476
       477    /**
       478     * Gets the number of comments that have been left for this blog entry.
       479     *
       480     * @return the number of comments as a int
       481     */
       482    public int getNumberOfComments() {
                 /*
        P/P       *  Method: int getNumberOfComments()
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
       483      return getComments().size();
       484    }
       485
       486    /**
       487     * Gets a collection of all trackbacks.
       488     *
       489     * @return a List of TrackBack instances
       490     */
       491    public List<TrackBack> getTrackBacks() {
                 /*
        P/P       *  Method: List getTrackBacks()
                  *
                  *  Preconditions:
                  *    init'ed(this.trackBacks)
                  *
                  *  Postconditions:
                  *    return_value == &new ArrayList(getTrackBacks#1)
                  *    new ArrayList(getTrackBacks#1) num objects == 1
                  */
       492      return new ArrayList<TrackBack>(trackBacks);
       493    }
       494
       495    /**
       496     * Gets the number of trackbacks that have been left for this blog entry.
       497     *
       498     * @return the number of trackbacks as a int
       499     */
       500    public int getNumberOfTrackBacks() {
                 /*
        P/P       *  Method: int getNumberOfTrackBacks()
                  *
                  *  Preconditions:
                  *    this.trackBacks != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
       501      return trackBacks.size();
       502    }
       503
       504    /**
       505     * Gets the number of responses that have been left for this blog entry.
       506     *
       507     * @return the number of responses as a int
       508     */
       509    public int getNumberOfResponses() {
                 /*
        P/P       *  Method: int getNumberOfResponses()
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *    init'ed(this.trackBacks)
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
       510      return getResponses().size();
       511    }
       512
       513    /**
       514     * Creates a new comment for this blog entry. This method doesn't actually
       515     * <b>add</b> the comment too.
       516     *
       517     * @param title     the title of the comment
       518     * @param body      the body of the comment
       519     * @param author    the author of the comment
       520     * @param email     the author's e-mail address
       521     * @param website   the author's website
       522     * @param ipAddress the IP address of the author
       523     * @param date      the date that the comment was created
       524     * @param state     the state of the comment
       525     * @return a new Comment instance with the specified properties
       526     */
       527    public Comment createComment(String title, String body, String author, String email, String website, String ipAddress, Date date, State state) {
                 /*
        P/P       *  Method: Comment createComment(String, String, String, String, String, String, Date, State)
                  *
                  *  Postconditions:
                  *    return_value == &new Comment(createComment#1)
                  *    new ArrayList(Comment#1) num objects == 1
                  *    new ArrayList(Content#1) num objects == 1
                  *    new ArrayList(Content#3) num objects == 1
                  *    new Comment(createComment#1) num objects == 1
                  *    new PropertyChangeSupport(Content#2) num objects == 1
                  *    init'ed(return_value.authenticated)
                  *    return_value.author == One-of{&"Anonymous", author}
                  *    return_value.author != null
                  *    return_value.blogEntry == this
                  *    ...
                  */
       528      return new Comment(title, body, author, email, website, ipAddress, date, state, this);
       529    }
       530
       531    /**
       532     * Creates a new comment for this blog entry, with a creation date of now.
       533     * This method doesn't actually <b>add</b> the comment too.
       534     *
       535     * @param title   the title of the comment
       536     * @param body    the body of the comment
       537     * @param author  the author of the comment
       538     * @param email   the author's e-mail address
       539     * @param website the author's website
       540     * @param ipAddress the IP address of the author
       541     * @return a new Comment instance with the specified properties
       542     */
       543    public Comment createComment(String title, String body, String author, String email, String website, String ipAddress) {
                 /*
        P/P       *  Method: Comment createComment(String, String, String, String, String, String)
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *
                  *  Presumptions:
                  *    net.sourceforge.pebble.domain.Blog:getCalendar(...)@544 != null
                  *
                  *  Postconditions:
                  *    return_value == &new Comment(createComment#1*)
                  *    new ArrayList(Comment#1) num objects == 1
                  *    new ArrayList(Content#1) num objects == 1
                  *    new ArrayList(Content#3) num objects == 1
                  *    new Comment(createComment#1*) num objects == 1
                  *    new PropertyChangeSupport(Content#2) num objects == 1
                  *    init'ed(return_value.authenticated)
                  *    return_value.author == One-of{&"Anonymous", author}
                  *    return_value.author != null
                  *    return_value.blogEntry == this
                  *    ...
                  */
       544      Calendar cal = getBlog().getCalendar();
       545      return createComment(title, body, author, email, website, ipAddress, cal.getTime(), State.APPROVED);
       546    }
       547
       548    /**
       549     * Adds the specified comment.
       550     *
       551     * @param comment a Comment instance
       552     */
       553    public synchronized void addComment(Comment comment) {
                 /*
        P/P       *  Method: void addComment(Comment)
                  *
                  *  Preconditions:
                  *    (soft) comment...date != null
                  *    (soft) comment.blogEntry != null
                  *    (soft) comment.date != null
                  *    (soft) init'ed(comment.parent)
                  *    (soft) this.comments != null
                  *    (soft) this.events != null
                  *    (soft) init'ed(this.eventsEnabled)
                  *
                  *  Presumptions:
                  *    getParent(...).date@558 != null
                  *    java.util.Calendar:getTime(...)@187 != null
                  *    java.util.Date:getTime(...)@562 <= 264-2
                  *    parent.comments@568 != null
                  *
                  *  Postconditions:
                  *    (soft) comment.blogEntry != null
                  *    possibly_updated(comment.date)
                  *    possibly_updated(comment.eventsEnabled)
                  *    init'ed(comment.parent)
                  *
                  *  Test Vectors:
                  *    comment: Inverse{null}, Addr_Set{null}
                  *    comment.parent: Addr_Set{null}, Inverse{null}
                  *    this.eventsEnabled: {0}, {1}
                  */
       554      if (comment == null) {
       555        return;
       556      }
       557
       558      Comment existingComment = getComment(comment.getId());
       559      if (existingComment != null && existingComment != comment) {
       560        // there is an existing comment with the same ID, but it's
       561        // not the same instance
       562        comment.setDate(new Date(comment.getDate().getTime() + 1));
       563        addComment(comment);
       564      } else if (existingComment != null) {
       565        return;
       566      } else {
       567        if (comment.getParent() != null) {
       568          Comment parent = getComment(comment.getParent().getId());
       569          if (parent != null) {
       570            parent.addComment(comment);
       571          } else {
       572            comments.add(comment);
       573          }
       574        } else {
       575          comments.add(comment);
       576        }
       577        comment.setBlogEntry(this);
       578
       579        if (areEventsEnabled()) {
       580          addEvent(new CommentEvent(comment, CommentEvent.COMMENT_ADDED));
       581          comment.setEventsEnabled(true);
       582        }
       583      }
       584    }
       585
       586    /**
       587     * Creates a new trackback for this blog entry. This method doesn't actually
       588     * <b>add</b> the trackback too.
       589     *
       590     * @param title    the title of the entry
       591     * @param excerpt  the excerpt of the entry
       592     * @param url      the url (permalink) of the entry
       593     * @param blogName the name of the blog
       594     * @param ipAddress   the IP address of the author
       595     * @param date     the date the trackback was received
       596     * @return a new TrackBack instance with the specified properties
       597     */
       598    public TrackBack createTrackBack(String title, String excerpt, String url, String blogName, String ipAddress, Date date, State state) {
                 /*
        P/P       *  Method: TrackBack createTrackBack(String, String, String, String, String, Date, State)
                  *
                  *  Postconditions:
                  *    return_value == &new TrackBack(createTrackBack#1)
                  *    new ArrayList(Content#1) num objects == 1
                  *    new ArrayList(Content#3) num objects == 1
                  *    new PropertyChangeSupport(Content#2) num objects == 1
                  *    new TrackBack(createTrackBack#1) num objects == 1
                  *    return_value.blogEntry == this
                  *    return_value.blogEntry != null
                  *    return_value.blogName == One-of{blogName, &""}
                  *    return_value.blogName != null
                  *    init'ed(return_value.date)
                  *    ...
                  */
       599      return new TrackBack(title, excerpt, url, blogName, ipAddress, date, state, this);
       600    }
       601
       602    /**
       603     * Creates a new trackback for this blog entry with a date of now.
       604     * This method doesn't actually <b>add</b> the trackback too.
       605     *
       606     * @param title       the title of the entry
       607     * @param excerpt     the excerpt of the entry
       608     * @param url         the url (permalink) of the entry
       609     * @param blogName    the name of the blog
       610     * @param ipAddress   the IP address of the author
       611     * @return a new Comment instance with the specified properties
       612     */
       613    public TrackBack createTrackBack(String title, String excerpt, String url, String blogName, String ipAddress) {
                 /*
        P/P       *  Method: TrackBack createTrackBack(String, String, String, String, String)
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *
                  *  Presumptions:
                  *    net.sourceforge.pebble.domain.Blog:getCalendar(...)@614 != null
                  *
                  *  Postconditions:
                  *    return_value == &new TrackBack(createTrackBack#1*)
                  *    new ArrayList(Content#1) num objects == 1
                  *    new ArrayList(Content#3) num objects == 1
                  *    new PropertyChangeSupport(Content#2) num objects == 1
                  *    new TrackBack(createTrackBack#1*) num objects == 1
                  *    return_value.blogEntry == this
                  *    return_value.blogEntry != null
                  *    return_value.blogName == One-of{blogName, &""}
                  *    return_value.blogName != null
                  *    init'ed(return_value.date)
                  *    ...
                  */
       614      Calendar cal = getBlog().getCalendar();
       615      return createTrackBack(title, excerpt, url, blogName, ipAddress, cal.getTime(), State.APPROVED);
       616    }
       617
       618    /**
       619     * Adds the specified trackback.
       620     *
       621     * @param trackBack a TrackBack instance
       622     */
       623    public synchronized void addTrackBack(TrackBack trackBack) {
                 /*
        P/P       *  Method: void addTrackBack(TrackBack)
                  *
                  *  Preconditions:
                  *    (soft) this.events != null
                  *    (soft) init'ed(this.eventsEnabled)
                  *    (soft) this.trackBacks != null
                  *
                  *  Postconditions:
                  *    possibly_updated(trackBack.eventsEnabled)
                  *
                  *  Test Vectors:
                  *    this.eventsEnabled: {0}, {1}
                  *    trackBack: Addr_Set{null}, Inverse{null}
                  *    java.util.List:contains(...)@624: {0}, {1}
                  */
       624      if (trackBack == null || trackBacks.contains(trackBack)) {
       625        return;
       626      }
       627
       628      trackBacks.add(trackBack);
       629
       630      if (areEventsEnabled()) {
       631        addEvent(new TrackBackEvent(trackBack, TrackBackEvent.TRACKBACK_ADDED));
       632        trackBack.setEventsEnabled(true);
       633      }
       634    }
       635
       636    /**
       637     * Removes the specified comment.
       638     *
       639     * @param id    the id of the comment to be removed
       640     */
       641    public synchronized void removeComment(long id) {
                 /*
        P/P       *  Method: void removeComment(long)
                  *
                  *  Preconditions:
                  *    (soft) log != null
                  *    (soft) this.comments != null
                  *    (soft) this.events != null
                  *    (soft) init'ed(this.eventsEnabled)
                  *
                  *  Presumptions:
                  *    child.blogEntry@646 != null
                  *    child.comments@646 != null
                  *    comment.blogEntry@646 != null
                  *    comment.blogEntry@647 != null
                  *    comment.comments@646 != null
                  *    ...
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@646: {1}, {0}
                  */
       642      Comment comment = getComment(id);
       643      if (comment != null) {
       644
       645        // get all children and delete them
       646        for (Comment child : comment.getComments()) {
       647          comment.removeComment(child);
       648        }
       649
       650        if (comment.getParent() != null) {
       651          comment.getParent().removeComment(comment);
       652        } else {
       653          comments.remove(comment);
       654        }
       655
       656        if (areEventsEnabled()) {
       657          addEvent(new CommentEvent(comment, CommentEvent.COMMENT_REMOVED));
       658        }
       659      } else {
       660        log.warn("A comment with id=" + id + " could not be found - " +
       661          "perhaps it has been removed already.");
       662      }
       663    }
       664
       665    /**
       666     * Gets the specified comment.
       667     *
       668     * @param id    the id of the comment
       669     */
       670    public Comment getComment(long id) {
                 /*
        P/P       *  Method: Comment getComment(long)
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *
                  *  Presumptions:
                  *    comment.date@673 != null
                  *    java.util.Iterator:next(...)@673 != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@672: {1}, {0}
                  */
       671      Iterator it = getComments().iterator();
       672      while (it.hasNext()) {
       673        Comment comment = (Comment) it.next();
       674        if (comment.getId() == id) {
       675          return comment;
       676        }
       677      }
       678
       679      return null;
       680    }
       681
       682    /**
       683     * Gets the specified TrackBack.
       684     *
       685     * @param id    the id of the TrackBack
       686     */
       687    public TrackBack getTrackBack(long id) {
                 /*
        P/P       *  Method: TrackBack getTrackBack(long)
                  *
                  *  Preconditions:
                  *    init'ed(this.trackBacks)
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@690 != null
                  *    trackBack.date@690 != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@689: {1}, {0}
                  */
       688      Iterator it = getTrackBacks().iterator();
       689      while (it.hasNext()) {
       690        TrackBack trackBack = (TrackBack)it.next();
       691        if (trackBack.getId() == id) {
       692          return trackBack;
       693        }
       694      }
       695
       696      return null;
       697    }
       698
       699    /**
       700     * Gets the response specified by the guid.
       701     *
       702     * @param guid    the response guid
       703     * @return  a Response object, or null if no response exists
       704     */
       705    public Response getResponse(String guid) {
                 /*
        P/P       *  Method: Response getResponse(String)
                  *
                  *  Preconditions:
                  *    guid != null
                  *    (soft) this.comments != null
                  *    (soft) init'ed(this.trackBacks)
                  *
                  *  Presumptions:
                  *    java.lang.String:lastIndexOf(...)@706 <= 232-2
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    java.lang.String:startsWith(...)@707: {0}, {1}
                  */
       706      long id = Long.parseLong(guid.substring(guid.lastIndexOf("/")+1));
       707      if (guid.startsWith("c")) {
       708        return getComment(id);
       709      } else {
       710        return getTrackBack(id);
       711      }
       712    }
       713
       714    /**
       715     * Removes the specified TrackBack.
       716     *
       717     * @param id    the id of the TrackBack to be removed
       718     */
       719    public synchronized void removeTrackBack(long id) {
                 /*
        P/P       *  Method: void removeTrackBack(long)
                  *
                  *  Preconditions:
                  *    (soft) log != null
                  *    (soft) this.events != null
                  *    (soft) init'ed(this.eventsEnabled)
                  *    (soft) this.trackBacks != null
                  *
                  *  Test Vectors:
                  *    this.eventsEnabled: {0}, {1}
                  */
       720      TrackBack trackBack = getTrackBack(id);
       721      if (trackBack != null) {
       722        trackBacks.remove(trackBack);
       723
       724        if (areEventsEnabled()) {
       725          addEvent(new TrackBackEvent(trackBack, TrackBackEvent.TRACKBACK_REMOVED));
       726        }
       727      } else {
       728        log.warn("A TrackBack with id=" + id + " could not be found - " +
       729            "perhaps it has been removed already.");
       730      }
       731    }
       732
       733    /**
       734     * Removes the specified comment or TrackBack.
       735     *
       736     * @param response    the Response to be removed
       737     */
       738    public void removeResponse(Response response) {
                 /*
        P/P       *  Method: void removeResponse(Response)
                  *
                  *  Preconditions:
                  *    (soft) log != null
                  *    (soft) response.date != null
                  *    (soft) this.comments != null
                  *    (soft) this.events != null
                  *    (soft) init'ed(this.eventsEnabled)
                  *    (soft) this.trackBacks != null
                  */
       739      if (response instanceof Comment) {
       740        removeComment(response.getId());
       741      } else if (response instanceof TrackBack) {
       742        removeTrackBack(response.getId());
       743      }
       744    }
       745
       746    /**
       747     * Returns the blog entry that was posted before this one.
       748     *
       749     * @return  a BlogEntry instance, or null if this is the first entry
       750     */
       751    public BlogEntry getPreviousBlogEntry() {
                 /*
        P/P       *  Method: BlogEntry getPreviousBlogEntry()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    init'ed(this.blog.blogEntryIndex)
                  *    init'ed(this.date)
                  *    init'ed(this.id)
                  *    (soft) init'ed(this.blog.blogEntryIndex.indexEntries)
                  *    (soft) this.blog.properties != null
                  *    (soft) this.blog.years != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
       752      return getBlog().getPreviousBlogEntry(this);
       753    }
       754
       755    /**
       756     * Returns the blog entry that was posted after this one.
       757     *
       758     * @return  a BlogEntry instance, or null is this is the last entry
       759     */
       760    public BlogEntry getNextBlogEntry() {
                 /*
        P/P       *  Method: BlogEntry getNextBlogEntry()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    this.blog.properties != null
                  *    this.blog.years != null
                  *    init'ed(this.date)
                  *    init'ed(this.id)
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
       761      return getBlog().getNextBlogEntry(this);
       762    }
       763
       764    public void validate(ValidationContext context) {
               /*
        P/P     *  Method: void validate(ValidationContext)
                */
       765    }
       766
       767    /**
       768     * Indicates whether some other object is "equal to" this one.
       769     *
       770     * @param o   the reference object with which to compare.
       771     * @return <code>true</code> if this object is the same as the obj
       772     *         argument; <code>false</code> otherwise.
       773     * @see #hashCode()
       774     * @see java.util.Hashtable
       775     */
       776    public boolean equals(Object o) {
                 /*
        P/P       *  Method: bool equals(Object)
                  *
                  *  Preconditions:
                  *    (soft) o.blog != null
                  *    (soft) init'ed(o.id)
                  *    (soft) this.blog != null
                  *    (soft) init'ed(this.id)
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    this == o: {0}, {1}
                  *
                  *  Preconditions:
                  *    (soft) init'ed(o.blog.id)
                  *    (soft) init'ed(this.blog.id)
                  */
       777      if (this == o) {
       778        return true;
       779      }
       780
       781      if (!(o instanceof BlogEntry)) {
       782        return false;
       783      }
       784
       785      BlogEntry blogEntry = (BlogEntry)o;
       786      return getGuid().equals(blogEntry.getGuid());
       787    }
       788
       789    public String getGuid() {
                 /*
        P/P       *  Method: String getGuid()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    init'ed(this.id)
                  *
                  *  Postconditions:
                  *    return_value != null
                  *
                  *  Preconditions:
                  *    init'ed(this.blog.id)
                  */
       790      return "blogEntry/" + getBlog().getId() + "/" + getId();
       791    }
       792
       793    public int hashCode() {
                 /*
        P/P       *  Method: int hashCode()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    init'ed(this.id)
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Preconditions:
                  *    init'ed(this.blog.id)
                  */
       794      return getGuid().hashCode();
       795    }
       796
       797    /**
       798     * Creates and returns a copy of this object.
       799     *
       800     * @return a clone of this instance.
       801     * @see Cloneable
       802     */
       803    public Object clone() {
                 /*
        P/P       *  Method: Object clone()
                  *
                  *  Preconditions:
                  *    init'ed(this.attachment)
                  *    init'ed(this.author)
                  *    init'ed(this.blog)
                  *    init'ed(this.body)
                  *    this.categories != null
                  *    this.comments != null
                  *    init'ed(this.commentsEnabled)
                  *    this.date != null
                  *    init'ed(this.excerpt)
                  *    init'ed(this.originalPermalink)
                  *    ...
                  *
                  *  Presumptions:
                  *    comment.blogEntry@835 != null
                  *    java.util.Calendar:getTime(...)@187 != null
                  *    java.util.Iterator:next(...)@835 != null
                  *    java.util.Iterator:next(...)@843 != null
                  *    trackBack.blogEntry@843 != null
                  *
                  *  Postconditions:
                  *    return_value == &new BlogEntry(clone#1)
                  *    new ArrayList(BlogEntry#2) num objects == 1
                  *    new ArrayList(BlogEntry#3) num objects == 1
                  *    new ArrayList(parse#1) num objects == 1
                  *    new BlogEntry(clone#1) num objects == 1
                  *    new Date(PageBasedContent#2) num objects == 1
                  *    new HashSet(BlogEntry#1) num objects == 1
                  *    new LinkedList(PageBasedContent#1) num objects == 1
                  *    new ArrayList(Content#1) num objects >= 1
                  *    new ArrayList(Content#3) num objects >= 1
                  *    ...
                  *
                  *  Test Vectors:
                  *    this.attachment: Addr_Set{null}, Inverse{null}
                  *    java.util.Iterator:hasNext(...)@826: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@834: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@842: {1}, {0}
                  */
       804      BlogEntry entry = new BlogEntry(getBlog());
       805      entry.setEventsEnabled(false);
       806      entry.setPersistent(isPersistent());
       807      entry.setPublished(isPublished());
       808      entry.setTitle(getTitle());
       809      entry.setSubtitle(getSubtitle());
       810      entry.setExcerpt(getExcerpt());
       811      entry.setBody(getBody());
       812      entry.setDate(getDate());
       813      entry.setTimeZoneId(timeZoneId);
       814      entry.setState(getState());
       815      entry.setAuthor(getAuthor());
       816      entry.setOriginalPermalink(getOriginalPermalink());
       817      entry.setCommentsEnabled(commentsEnabled);
       818      entry.setTrackBacksEnabled(trackBacksEnabled);
       819
       820      if (attachment != null) {
       821        entry.setAttachment((Attachment)attachment.clone());
       822      }
       823
       824      // copy the categories
       825      Iterator it = categories.iterator();
       826      while (it.hasNext()) {
       827        entry.addCategory((Category)it.next());
       828      }
       829
       830      entry.setTags(getTags());
       831
       832      // also copy the comments
       833      it = getComments().iterator();
       834      while (it.hasNext()) {
       835        Comment comment = (Comment)it.next();
       836        Comment clonedComment = (Comment)comment.clone();
       837        entry.addComment(clonedComment);
       838      }
       839
       840      // and TrackBacks
       841      it = getTrackBacks().iterator();
       842      while (it.hasNext()) {
       843        TrackBack trackBack = (TrackBack)it.next();
       844        TrackBack clonedTrackBack = (TrackBack)trackBack.clone();
       845        clonedTrackBack.setBlogEntry(entry);
       846        entry.addTrackBack(clonedTrackBack);
       847      }
       848
       849      return entry;
       850    }
       851
       852    /**
       853     * Sets whether events are enabled.
       854     *
       855     * @param b   true to enable events, false otherwise
       856     */
       857    void setEventsEnabled(boolean b) {
                 /*
        P/P       *  Method: void setEventsEnabled(bool)
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *    init'ed(this.trackBacks)
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@861 != null
                  *
                  *  Postconditions:
                  *    init'ed(this.eventsEnabled)
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@861: {1}, {0}
                  */
       858      super.setEventsEnabled(b);
       859
       860      // and cascade
       861      for (Response response : getResponses()) {
       862        response.setEventsEnabled(b);
       863      }
       864    }
       865
       866    public void clearEvents() {
                 /*
        P/P       *  Method: void clearEvents()
                  *
                  *  Preconditions:
                  *    this.comments != null
                  *    init'ed(this.trackBacks)
                  *
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@869 != null
                  *
                  *  Postconditions:
                  *    this.events != null
                  *    new ArrayList(clearEvents#1*) num objects >= 1
                  *
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@869: {1}, {0}
                  */
       867      super.clearEvents();
       868
       869      for (Response response : getResponses()) {
       870        response.clearEvents();
       871      }
       872    }
       873
       874    /**
       875     * Sets the state of this blog entry.
       876     */
       877    void setState(State state) {
                 /*
        P/P       *  Method: void setState(State)
                  *
                  *  Preconditions:
                  *    init'ed(this.state)
                  *    init'ed(this.eventsEnabled)
                  *    (soft) net.sourceforge.pebble.domain.State__static_init.new State(State__static_init#4).name != null
                  *    (soft) net.sourceforge.pebble.domain.State__static_init.new State(State__static_init#5).name != null
                  *    (soft) state != null
                  *    (soft) init'ed(state.name)
                  *    (soft) this.events != null
                  *
                  *  Postconditions:
                  *    this.state == state
                  *    (soft) this.state != null
                  *
                  *  Test Vectors:
                  *    this.eventsEnabled: {0}, {1}
                  */
       878      State previousState = getState();
       879      super.setState(state);
       880
       881      if (areEventsEnabled()) {
       882        if (isPublished() && previousState == State.UNPUBLISHED) {
       883          addEvent(new BlogEntryEvent(this, BlogEntryEvent.BLOG_ENTRY_PUBLISHED));
       884        } else if (isUnpublished() && previousState == State.PUBLISHED) {
       885          addEvent(new BlogEntryEvent(this, BlogEntryEvent.BLOG_ENTRY_UNPUBLISHED));
       886        }
       887      }
       888    }
       889
       890    public String toString() {
                 /*
        P/P       *  Method: String toString()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    init'ed(this.id)
                  *
                  *  Postconditions:
                  *    return_value != null
                  *
                  *  Preconditions:
                  *    init'ed(this.blog.id)
                  */
       891      return getGuid() + ":" + super.hashCode();
       892    }
       893
       894    public TimeZone getTimeZone() {
                 /*
        P/P       *  Method: TimeZone getTimeZone()
                  *
                  *  Preconditions:
                  *    init'ed(this.timeZoneId)
                  *    (soft) this.blog != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
       895      return TimeZone.getTimeZone(getTimeZoneId());
       896    }
       897
       898    public String getTimeZoneId() {
                 /*
        P/P       *  Method: String getTimeZoneId()
                  *
                  *  Preconditions:
                  *    init'ed(this.timeZoneId)
                  *    (soft) this.blog != null
                  *
                  *  Postconditions:
                  *    init'ed(return_value)
                  *
                  *  Test Vectors:
                  *    this.timeZoneId: Addr_Set{null}, Inverse{null}
                  */
       899      if (this.timeZoneId != null) {
       900        return timeZoneId;
       901      } else {
       902        return getBlog().getTimeZoneId();
       903      }
       904    }
       905
       906    public void setTimeZoneId(String timeZoneId) {
                 /*
        P/P       *  Method: void setTimeZoneId(String)
                  *
                  *  Postconditions:
                  *    this.timeZoneId == timeZoneId
                  *    init'ed(this.timeZoneId)
                  */
       907      this.timeZoneId = timeZoneId;
       908    }
       909
       910  }

SofCheck Inspector Build Version : 2.22510

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