Coverage Report - net.sourceforge.pebble.dao.file.FileBlogEntryDAO
 
Classes in this File Line Coverage Branch Coverage Complexity
FileBlogEntryDAO
75%
183/243
72%
29/40
3.333
 
 1  
 /*
 2  
  * Copyright (c) 2003-2011, Simon Brown
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions are met:
 7  
  *
 8  
  *   - Redistributions of source code must retain the above copyright
 9  
  *     notice, this list of conditions and the following disclaimer.
 10  
  *
 11  
  *   - Redistributions in binary form must reproduce the above copyright
 12  
  *     notice, this list of conditions and the following disclaimer in
 13  
  *     the documentation and/or other materials provided with the
 14  
  *     distribution.
 15  
  *
 16  
  *   - Neither the name of Pebble nor the names of its contributors may
 17  
  *     be used to endorse or promote products derived from this software
 18  
  *     without specific prior written permission.
 19  
  *
 20  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 21  
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  
  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 24  
  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 25  
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 26  
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 27  
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 28  
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 29  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 30  
  * POSSIBILITY OF SUCH DAMAGE.
 31  
  */
 32  
 
 33  
 package net.sourceforge.pebble.dao.file;
 34  
 
 35  
 import net.sourceforge.pebble.dao.BlogEntryDAO;
 36  
 import net.sourceforge.pebble.dao.PersistenceException;
 37  
 import net.sourceforge.pebble.domain.*;
 38  
 import org.apache.commons.logging.Log;
 39  
 import org.apache.commons.logging.LogFactory;
 40  
 import org.w3c.dom.Document;
 41  
 import org.w3c.dom.Element;
 42  
 import org.w3c.dom.Node;
 43  
 import org.xml.sax.helpers.DefaultHandler;
 44  
 
 45  
 import javax.xml.parsers.DocumentBuilder;
 46  
 import javax.xml.parsers.DocumentBuilderFactory;
 47  
 import javax.xml.parsers.SAXParser;
 48  
 import javax.xml.parsers.SAXParserFactory;
 49  
 import javax.xml.transform.*;
 50  
 import javax.xml.transform.dom.DOMSource;
 51  
 import javax.xml.transform.stream.StreamResult;
 52  
 import java.io.*;
 53  
 import java.text.DateFormat;
 54  
 import java.text.SimpleDateFormat;
 55  
 import java.util.*;
 56  
 
 57  
 public class FileBlogEntryDAO implements BlogEntryDAO {
 58  
 
 59  
   /** timezone to use for calculating paths on disk, etc */
 60  4
   private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
 61  
 
 62  
   /**
 63  
    * the log used by this class
 64  
    */
 65  4
   private static Log log = LogFactory.getLog(FileBlogEntryDAO.class);
 66  
 
 67  5032
   public FileBlogEntryDAO() {
 68  5032
   }
 69  
 
 70  
   /** the date/time format used when persisting dates */
 71  
   static final String OLD_PERSISTENT_DATETIME_FORMAT = "dd MMM yyyy HH:mm:ss z";
 72  
   static final String NEW_PERSISTENT_DATETIME_FORMAT = "dd MMM yyyy HH:mm:ss:S Z";
 73  
   static final String REGEX_FOR_YEAR = "\\d\\d\\d\\d";
 74  
 
 75  
   /**
 76  
    * Loads a specific blog entry.
 77  
    *
 78  
    * @param blogEntryId   the blog entry ID
 79  
    * @return a BlogEntry instance
 80  
    * @throws net.sourceforge.pebble.dao.PersistenceException
 81  
    *          if the specified blog entry cannot be loaded
 82  
    */
 83  
   public BlogEntry loadBlogEntry(Blog blog, String blogEntryId) throws PersistenceException {
 84  104
     File path = new File(getPath(blog, blogEntryId, GMT));
 85  104
     File file = new File(path, blogEntryId + ".xml");
 86  104
     return loadBlogEntry(blog, file);
 87  
   }
 88  
 
 89  
   /**
 90  
    * Loads a blog entry from the specified file.
 91  
    *
 92  
    * @param source    the File pointing to the source
 93  
    * @throws net.sourceforge.pebble.dao.PersistenceException
 94  
    *          if the blog entry can't be loaded
 95  
    */
 96  
   private BlogEntry loadBlogEntry(Blog blog, File source) throws PersistenceException {
 97  140
     if (source.exists()) {
 98  108
       log.debug("Loading " + source.getAbsolutePath());
 99  108
       BlogEntry blogEntry = new BlogEntry(blog);
 100  
 
 101  
       try {
 102  108
         DefaultHandler handler = new BlogEntryHandler(blogEntry);
 103  108
         SAXParserFactory saxFactory = SAXParserFactory.newInstance();
 104  108
         saxFactory.setValidating(false);
 105  108
         saxFactory.setNamespaceAware(true);
 106  108
         SAXParser parser = saxFactory.newSAXParser();
 107  108
         parser.parse(source, handler);
 108  
 
 109  0
       } catch (Exception e) {
 110  0
         log.error(e.getMessage() + " while loading blog enty from " + source.getAbsolutePath(), e);
 111  0
         e.printStackTrace();
 112  0
         throw new PersistenceException(e.getMessage());
 113  108
       }
 114  
 
 115  108
       return blogEntry;
 116  
     } else {
 117  32
       return null;
 118  
     }
 119  
   }
 120  
 
 121  
   /**
 122  
    * Loads all blog entries.
 123  
    *
 124  
    * @param blog the Blog to load all entries for
 125  
    * @return a List of BlogEntry objects
 126  
    * @throws net.sourceforge.pebble.dao.PersistenceException
 127  
    *          if the blog entries cannot be loaded
 128  
    */
 129  
   public Collection<BlogEntry> loadBlogEntries(Blog blog) throws PersistenceException {
 130  36
     List<BlogEntry> list = new ArrayList<BlogEntry>();
 131  
 
 132  36
     File root = new File(blog.getRoot());
 133  36
     File years[] = root.listFiles(new FourDigitFilenameFilter());
 134  72
     for (File year : years) {
 135  36
       File months[] = year.listFiles(new TwoDigitFilenameFilter());
 136  72
       for (File month : months) {
 137  36
         File days[] = month.listFiles(new TwoDigitFilenameFilter());
 138  72
         for (File day : days) {
 139  36
           File blogEntryFiles[] = day.listFiles(new BlogEntryFilenameFilter());
 140  72
           for (File blogEntryFile : blogEntryFiles) {
 141  36
             list.add(loadBlogEntry(blog, blogEntryFile));
 142  
           }
 143  
         }
 144  
       }
 145  
     }
 146  
 
 147  36
     return list;
 148  
   }
 149  
 
 150  
   /**
 151  
    * Stores the specified blog entry.
 152  
    *
 153  
    * @param blogEntry the blog entry to store
 154  
    * @throws PersistenceException if something goes wrong storing the entry
 155  
    */
 156  
   public void storeBlogEntry(BlogEntry blogEntry) throws PersistenceException {
 157  132
     File outputDir = new File(getPath(blogEntry.getBlog(), blogEntry.getId(), GMT));
 158  132
     if (!outputDir.exists()) {
 159  36
       outputDir.mkdirs();
 160  
     }
 161  
 
 162  132
     File outputFile = new File(outputDir, blogEntry.getId() + ".xml");
 163  132
     storeBlogEntry(blogEntry, outputFile);
 164  132
   }
 165  
 
 166  
 
 167  
   /**
 168  
    * Stores a blog entry to the specified file.
 169  
    *
 170  
    * @param blogEntry   the BlogEntry that is being stored
 171  
    * @param destination the File pointing to the destination
 172  
    * @throws PersistenceException if something goes wrong storing the entry
 173  
    */
 174  
   private void storeBlogEntry(BlogEntry blogEntry, File destination) throws PersistenceException {
 175  132
     File backupFile = new File(destination.getParentFile(), destination.getName() + ".bak");
 176  
     try {
 177  132
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 178  132
       factory.setValidating(false);
 179  132
       factory.setNamespaceAware(true);
 180  132
       factory.setIgnoringElementContentWhitespace(true);
 181  132
       factory.setIgnoringComments(true);
 182  
 
 183  132
       DocumentBuilder builder = factory.newDocumentBuilder();
 184  132
       Document doc = builder.newDocument();
 185  
 
 186  132
       Element root = doc.createElement("blogEntry");
 187  132
       doc.appendChild(root);
 188  
 
 189  132
       Element titleNode = doc.createElement("title");
 190  132
       Element subtitleNode = doc.createElement("subtitle");
 191  132
       Element excerptNode = doc.createElement("excerpt");
 192  132
       Element bodyNode = doc.createElement("body");
 193  
       Element categoryNode;
 194  132
       Element tagsNode = doc.createElement("tags");
 195  132
       Element dateNode = doc.createElement("date");
 196  132
       Element timeZoneNode = doc.createElement("timeZone");
 197  132
       Element stateNode = doc.createElement("state");
 198  132
       Element authorNode = doc.createElement("author");
 199  132
       Element staticNameNode = doc.createElement("staticName");
 200  132
       Element commentsEnabledNode = doc.createElement("commentsEnabled");
 201  132
       Element trackBacksEnabledNode = doc.createElement("trackBacksEnabled");
 202  132
       Element attachmentNode = doc.createElement("attachment");
 203  
 
 204  132
       root.appendChild(titleNode);
 205  132
       root.appendChild(subtitleNode);
 206  132
       root.appendChild(excerptNode);
 207  132
       root.appendChild(bodyNode);
 208  132
       root.appendChild(dateNode);
 209  132
       root.appendChild(timeZoneNode);
 210  132
       root.appendChild(stateNode);
 211  132
       root.appendChild(authorNode);
 212  132
       root.appendChild(staticNameNode);
 213  
 
 214  132
       if (blogEntry.isAggregated()) {
 215  0
         Element permalinkNode = doc.createElement("originalPermalink");
 216  0
         permalinkNode.appendChild(createTextNode(doc, blogEntry.getOriginalPermalink()));
 217  0
         root.appendChild(permalinkNode);
 218  
       }
 219  
 
 220  132
       titleNode.appendChild(createTextNode(doc, blogEntry.getTitle()));
 221  132
       subtitleNode.appendChild(createTextNode(doc, blogEntry.getSubtitle()));
 222  132
       bodyNode.appendChild(createCDATASection(doc, blogEntry.getBody()));
 223  
 
 224  132
       if (blogEntry.getExcerpt() != null) {
 225  132
         excerptNode.appendChild(createCDATASection(doc, blogEntry.getExcerpt()));
 226  
       }
 227  
 
 228  132
       root.appendChild(commentsEnabledNode);
 229  132
       commentsEnabledNode.appendChild(createTextNode(doc, "" + blogEntry.isCommentsEnabled()));
 230  
 
 231  132
       root.appendChild(trackBacksEnabledNode);
 232  132
       trackBacksEnabledNode.appendChild(createTextNode(doc, "" + blogEntry.isTrackBacksEnabled()));
 233  
 
 234  132
       Iterator it = blogEntry.getCategories().iterator();
 235  
       Category category;
 236  260
       while (it.hasNext()) {
 237  128
         category = (Category) it.next();
 238  128
         categoryNode = doc.createElement("category");
 239  128
         categoryNode.appendChild(createTextNode(doc, category.getId()));
 240  128
         root.appendChild(categoryNode);
 241  
       }
 242  
 
 243  132
       if (blogEntry.getTags() != null) {
 244  132
         root.appendChild(tagsNode);
 245  132
         tagsNode.appendChild(createTextNode(doc, blogEntry.getTags()));
 246  
       }
 247  
 
 248  132
       if (blogEntry.getAuthor() != null) {
 249  132
         authorNode.appendChild(createTextNode(doc, blogEntry.getAuthor()));
 250  
       }
 251  
 
 252  132
       SimpleDateFormat sdf = new SimpleDateFormat(NEW_PERSISTENT_DATETIME_FORMAT, Locale.ENGLISH);
 253  132
       sdf.setTimeZone(GMT);
 254  132
       dateNode.appendChild(createTextNode(doc, sdf.format(blogEntry.getDate())));
 255  
 
 256  132
       timeZoneNode.appendChild(createTextNode(doc, blogEntry.getTimeZoneId()));
 257  
 
 258  132
       stateNode.appendChild(createTextNode(doc, blogEntry.getState().getName()));
 259  
 
 260  132
       Attachment attachment = blogEntry.getAttachment();
 261  132
       if (attachment != null) {
 262  0
         root.appendChild(attachmentNode);
 263  0
         Element attachmentUrlNode = doc.createElement("url");
 264  0
         attachmentUrlNode.appendChild(createTextNode(doc, attachment.getUrl()));
 265  0
         attachmentNode.appendChild(attachmentUrlNode);
 266  0
         Element attachmentSizeNode = doc.createElement("size");
 267  0
         attachmentSizeNode.appendChild(createTextNode(doc, "" + attachment.getSize()));
 268  0
         attachmentNode.appendChild(attachmentSizeNode);
 269  0
         Element attachmentTypeNode = doc.createElement("type");
 270  0
         attachmentTypeNode.appendChild(createTextNode(doc, attachment.getType()));
 271  0
         attachmentNode.appendChild(attachmentTypeNode);
 272  
       }
 273  
 
 274  
       // and now store the comments
 275  132
       it = blogEntry.getComments().iterator();
 276  152
       while (it.hasNext()) {
 277  20
         Comment comment = (Comment) it.next();
 278  20
         storeComment(comment, doc, root);
 279  20
       }
 280  
 
 281  
       // and finally the trackbacks
 282  132
       it = blogEntry.getTrackBacks().iterator();
 283  132
       while (it.hasNext()) {
 284  0
         TrackBack trackBack = (TrackBack) it.next();
 285  0
         storeTrackBack(trackBack, doc, root);
 286  0
       }
 287  
 
 288  
       // write the XMl to a String, and then write this string to a file
 289  
       // (if the XML format fails, we don't corrupt the file)
 290  132
       StringWriter sw = new StringWriter();
 291  132
       Source source = new DOMSource(doc);
 292  132
       Result result = new StreamResult(sw);
 293  132
       Transformer xformer = TransformerFactory.newInstance().newTransformer();
 294  132
       xformer.setOutputProperty(OutputKeys.METHOD, "xml");
 295  132
       xformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
 296  132
       xformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml");
 297  132
       xformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "body");
 298  132
       xformer.setOutputProperty(OutputKeys.INDENT, "yes");
 299  132
       xformer.transform(source, result);
 300  
 
 301  
       // now take a backup of the correct file
 302  132
       if (destination.exists() && destination.length() > 0) {
 303  96
         log.debug("Backing up to " + backupFile.getAbsolutePath());
 304  96
         destination.renameTo(backupFile);
 305  
       }
 306  
 
 307  132
       log.debug("Saving to " + destination.getAbsolutePath());
 308  132
       BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destination), "UTF-8"));
 309  132
       bw.write(sw.toString());
 310  132
       bw.flush();
 311  132
       bw.close();
 312  0
     } catch (Exception e) {
 313  0
       log.error(e.getMessage(), e);
 314  0
       e.printStackTrace();
 315  0
       throw new PersistenceException(e.getMessage());
 316  132
     }
 317  132
   }
 318  
 
 319  
   /**
 320  
    * Helper method to store an individual comment.
 321  
    *
 322  
    * @param comment the Comment being stored
 323  
    * @param doc     the Document into which the comment is to be inserted
 324  
    * @param root    the root Node for the comment
 325  
    * @throws java.lang.Exception if something goes wrong
 326  
    */
 327  
   private void storeComment(Comment comment, Document doc, Node root) throws Exception {
 328  20
     Element commentNode = doc.createElement("comment");
 329  20
     root.appendChild(commentNode);
 330  
 
 331  20
     Element titleNode = doc.createElement("title");
 332  20
     Element bodyNode = doc.createElement("body");
 333  20
     Element authorNode = doc.createElement("author");
 334  20
     Element emailNode = doc.createElement("email");
 335  20
     Element websiteNode = doc.createElement("website");
 336  20
     Element avatarNode = doc.createElement("avatar");
 337  20
     Element ipAddressNode = doc.createElement("ipAddress");
 338  20
     Element dateNode = doc.createElement("date");
 339  20
     Element parentNode = doc.createElement("parent");
 340  20
     Element stateNode = doc.createElement("state");
 341  20
     Element authenticatedNode = doc.createElement("authenticated");
 342  
 
 343  20
     commentNode.appendChild(titleNode);
 344  20
     commentNode.appendChild(bodyNode);
 345  20
     commentNode.appendChild(authorNode);
 346  20
     commentNode.appendChild(emailNode);
 347  20
     commentNode.appendChild(websiteNode);
 348  20
     commentNode.appendChild(avatarNode);
 349  20
     commentNode.appendChild(ipAddressNode);
 350  20
     commentNode.appendChild(dateNode);
 351  20
     commentNode.appendChild(stateNode);
 352  20
     commentNode.appendChild(authenticatedNode);
 353  
 
 354  20
     titleNode.appendChild(createTextNode(doc, comment.getTitle()));
 355  20
     bodyNode.appendChild(createCDATASection(doc, comment.getBody()));
 356  20
     authorNode.appendChild(createTextNode(doc, comment.getAuthor()));
 357  20
     emailNode.appendChild(createTextNode(doc, comment.getEmail()));
 358  20
     websiteNode.appendChild(createTextNode(doc, comment.getWebsite()));
 359  20
     avatarNode.appendChild(createTextNode(doc, comment.getAvatar()));
 360  20
     ipAddressNode.appendChild(createTextNode(doc, comment.getIpAddress()));
 361  20
     SimpleDateFormat sdf = new SimpleDateFormat(NEW_PERSISTENT_DATETIME_FORMAT, Locale.ENGLISH);
 362  20
     sdf.setTimeZone(GMT);
 363  20
     dateNode.appendChild(createTextNode(doc, sdf.format(comment.getDate())));
 364  20
     stateNode.appendChild(createTextNode(doc, comment.getState().getName()));
 365  20
     authenticatedNode.appendChild(createTextNode(doc, "" + comment.isAuthenticated()));
 366  
 
 367  20
     if (comment.getParent() != null) {
 368  0
       commentNode.appendChild(parentNode);
 369  0
       parentNode.appendChild(createTextNode(doc, "" + comment.getParent().getId()));
 370  
     }
 371  20
   }
 372  
 
 373  
   private Node createCDATASection(Document doc, String text) {
 374  284
     if (text != null) {
 375  284
       return doc.createCDATASection(XmlStringFilter.filter(text));
 376  
     } else {
 377  0
       return doc.createCDATASection("");
 378  
     }
 379  
   }
 380  
 
 381  
   private Node createTextNode(Document doc, String text) {
 382  1496
     if (text != null) {
 383  1436
       return doc.createTextNode(XmlStringFilter.filter(text));
 384  
     } else {
 385  60
       return doc.createTextNode("");
 386  
     }
 387  
   }
 388  
 
 389  
   /**
 390  
    * Helper method to store an individual trackback.
 391  
    *
 392  
    * @param trackBack the TrackBack being stored
 393  
    * @param doc       the Document into which the trackback is to be inserted
 394  
    * @param root      the root Node for the comment
 395  
    * @throws java.lang.Exception if something goes wrong
 396  
    */
 397  
   private void storeTrackBack(TrackBack trackBack, Document doc, Node root) throws Exception {
 398  0
     Element commentNode = doc.createElement("trackback");
 399  0
     root.appendChild(commentNode);
 400  
 
 401  0
     Element titleNode = doc.createElement("title");
 402  0
     Element excerptNode = doc.createElement("excerpt");
 403  0
     Element urlNode = doc.createElement("url");
 404  0
     Element blogNameNode = doc.createElement("blogName");
 405  0
     Element ipAddressNode = doc.createElement("ipAddress");
 406  0
     Element dateNode = doc.createElement("date");
 407  0
     Element stateNode = doc.createElement("state");
 408  
 
 409  0
     commentNode.appendChild(titleNode);
 410  0
     commentNode.appendChild(excerptNode);
 411  0
     commentNode.appendChild(urlNode);
 412  0
     commentNode.appendChild(blogNameNode);
 413  0
     commentNode.appendChild(ipAddressNode);
 414  0
     commentNode.appendChild(dateNode);
 415  0
     commentNode.appendChild(stateNode);
 416  
 
 417  0
     titleNode.appendChild(createTextNode(doc, trackBack.getTitle()));
 418  0
     excerptNode.appendChild(createCDATASection(doc, trackBack.getExcerpt()));
 419  0
     urlNode.appendChild(createTextNode(doc, trackBack.getUrl()));
 420  0
     blogNameNode.appendChild(createTextNode(doc, trackBack.getBlogName()));
 421  0
     ipAddressNode.appendChild(createTextNode(doc, trackBack.getIpAddress()));
 422  0
     SimpleDateFormat sdf = new SimpleDateFormat(NEW_PERSISTENT_DATETIME_FORMAT, Locale.ENGLISH);
 423  0
     sdf.setTimeZone(GMT);
 424  0
     dateNode.appendChild(createTextNode(doc, sdf.format(trackBack.getDate())));
 425  0
     stateNode.appendChild(createTextNode(doc, trackBack.getState().getName()));
 426  0
   }
 427  
 
 428  
   /**
 429  
    * Removes the specified blog entry.
 430  
    *
 431  
    * @param blogEntry the blog entry to remove
 432  
    * @throws PersistenceException if something goes wrong removing the entry
 433  
    */
 434  
   public void removeBlogEntry(BlogEntry blogEntry) throws PersistenceException {
 435  0
     File path = new File(getPath(blogEntry.getBlog(), blogEntry.getId(), GMT));
 436  0
     File file = new File(path, blogEntry.getId() + ".xml");
 437  0
     log.debug("Removing " + blogEntry.getGuid());
 438  
 
 439  0
     boolean success = file.delete();
 440  0
     if (!success) {
 441  0
       throw new PersistenceException("Deletion of blog entry " + blogEntry.getGuid() + " failed");
 442  
     }
 443  0
   }
 444  
 
 445  
   /**
 446  
    * Given a blog and blog entry ID, this method determines the path where
 447  
    * that blog entry is stored.
 448  
    *
 449  
    * @param blog    the owning Blog
 450  
    * @param blogEntryId   the ID of the blog entry
 451  
    * @return  a String of the form blogroot/yyyy/MM/dd
 452  
    */
 453  
   public String getPath(Blog blog, String blogEntryId, TimeZone timeZone) {
 454  236
     DateFormat year = new SimpleDateFormat("yyyy");
 455  236
     year.setTimeZone(timeZone);
 456  236
     DateFormat month = new SimpleDateFormat("MM");
 457  236
     month.setTimeZone(timeZone);
 458  236
     DateFormat day = new SimpleDateFormat("dd");
 459  236
     day.setTimeZone(timeZone);
 460  
 
 461  236
     long dateInMillis = Long.parseLong(blogEntryId);
 462  236
     Date date = new Date(dateInMillis);
 463  
 
 464  236
     StringBuffer buf = new StringBuffer();
 465  236
     buf.append(blog.getRoot());
 466  236
     buf.append(File.separator);
 467  236
     buf.append(year.format(date));
 468  236
     buf.append(File.separator);
 469  236
     buf.append(month.format(date));
 470  236
     buf.append(File.separator);
 471  236
     buf.append(day.format(date));
 472  
 
 473  236
     return buf.toString();
 474  
   }
 475  
 
 476  
 }