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