Coverage Report - net.sourceforge.pebble.index.StaticPageIndex
 
Classes in this File Line Coverage Branch Coverage Complexity
StaticPageIndex
41%
39/94
26%
7/26
2.385
 
 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  
 package net.sourceforge.pebble.index;
 33  
 
 34  
 import net.sourceforge.pebble.domain.Blog;
 35  
 import net.sourceforge.pebble.domain.StaticPage;
 36  
 import org.apache.commons.logging.Log;
 37  
 import org.apache.commons.logging.LogFactory;
 38  
 
 39  
 import java.io.*;
 40  
 import java.util.*;
 41  
 
 42  
 /**
 43  
  * Maintains an index of all static pages
 44  
  *
 45  
  * @author    Simon Brown
 46  
  */
 47  
 public class StaticPageIndex {
 48  
 
 49  4
   private static final Log log = LogFactory.getLog(StaticPageIndex.class);
 50  
 
 51  
   private static final String PAGES_INDEX_DIRECTORY_NAME = "pages";
 52  
   private static final String NAME_TO_ID_INDEX_FILE_NAME = "name.index";
 53  
   private static final String LOCK_FILE_NAME = "pages.lock";
 54  
   private static final int MAXIMUM_LOCK_ATTEMPTS = 3;
 55  
 
 56  
   /** the owning blog */
 57  
   private Blog blog;
 58  
 
 59  
   /** the collection of all static pages */
 60  2720
   private Map<String,String> index = new HashMap<String,String>();
 61  2720
   private int lockAttempts = 0;
 62  
 
 63  2720
   public StaticPageIndex(Blog blog) {
 64  2720
     this.blog = blog;
 65  
 
 66  
     // create the directory structure if it doesn't exist
 67  2720
     File indexDirectory = new File(blog.getIndexesDirectory(), PAGES_INDEX_DIRECTORY_NAME);
 68  2720
     if (!indexDirectory.exists()) {
 69  2688
       indexDirectory.mkdirs();
 70  
     }
 71  
 
 72  2720
     readIndex();
 73  2720
   }
 74  
 
 75  
   /**
 76  
    * Indexes one or more blog entries.
 77  
    *
 78  
    * @param staticPages   a List of Page instances
 79  
    */
 80  
   public synchronized void reindex(Collection<StaticPage> staticPages) {
 81  36
     if (lock()) {
 82  
       // clear the index and add all static pages
 83  36
       index = new HashMap<String,String>();
 84  36
       for (StaticPage staticPage : staticPages) {
 85  0
         index.put(staticPage.getName(), staticPage.getId());
 86  
       }
 87  
 
 88  
       // and finally, write the index
 89  36
       writeIndex();
 90  36
       unlock();
 91  
     }
 92  36
   }
 93  
 
 94  
   /**
 95  
    * Indexes a single page.
 96  
    *
 97  
    * @param staticPage    a Page instance
 98  
    */
 99  
   public synchronized void index(StaticPage staticPage) {
 100  0
     if (lock()) {
 101  0
       readIndex();
 102  
 
 103  
       // remove the old entry for this static page
 104  0
       Iterator it = index.keySet().iterator();
 105  0
       while (it.hasNext()) {
 106  0
         String key = (String)it.next();
 107  0
         String value = index.get(key);
 108  0
         if (value.equals(staticPage.getId())) {
 109  0
           it.remove();
 110  
         }
 111  0
       }
 112  
 
 113  
       // and now add the new entry for this page
 114  0
       index.put(staticPage.getName(), staticPage.getId());
 115  0
       writeIndex();
 116  0
       unlock();
 117  0
     } else {
 118  0
       if (lockAttempts <= MAXIMUM_LOCK_ATTEMPTS) {
 119  
         try {
 120  0
           Thread.sleep(1000);
 121  0
         } catch (InterruptedException ie) {
 122  
           // ignore
 123  0
         }
 124  0
         index(staticPage);
 125  
       } else {
 126  0
         blog.error("Could not index static page - try <a href=\"utilities.secureaction?action=buildIndexes\">rebuilding the indexes</a>.");
 127  
       }
 128  
     }
 129  0
   }
 130  
 
 131  
   /**
 132  
    * Unindexes a single page.
 133  
    *
 134  
    * @param staticPage    a Page instance
 135  
    */
 136  
   public synchronized void unindex(StaticPage staticPage) {
 137  0
     if (lock()) {
 138  0
       readIndex();
 139  0
       index.remove(staticPage.getName());
 140  0
       writeIndex();
 141  0
       unlock();
 142  
     } else {
 143  0
       if (lockAttempts <= MAXIMUM_LOCK_ATTEMPTS) {
 144  
         try {
 145  0
           Thread.sleep(1000);
 146  0
         } catch (InterruptedException ie) {
 147  
           // ignore
 148  0
         }
 149  0
         unindex(staticPage);
 150  
       } else {
 151  0
         blog.reindexStaticPages();
 152  
       }
 153  
     }
 154  0
   }
 155  
 
 156  
   /**
 157  
    * Helper method to load the index.
 158  
    */
 159  
   private void readIndex() {
 160  2720
     log.info("Reading index from disk");
 161  2720
     File indexFile = getIndexFile();
 162  2720
     if (indexFile.exists()) {
 163  
       try {
 164  0
         BufferedReader reader = new BufferedReader(new FileReader(indexFile));
 165  0
         String indexEntry = reader.readLine();
 166  0
         while (indexEntry != null) {
 167  0
           String[] parts = indexEntry.split("=");
 168  0
           index.put(parts[0], parts[1]);
 169  
 
 170  0
           indexEntry = reader.readLine();
 171  0
         }
 172  
 
 173  0
         reader.close();
 174  0
       } catch (Exception e) {
 175  0
         log.error("Error while reading index", e);
 176  0
       }
 177  
     }
 178  2720
   }
 179  
 
 180  
   /**
 181  
    * Helper method to write out the index to disk.
 182  
    */
 183  
   private void writeIndex() {
 184  
     try {
 185  36
       File indexFile = getIndexFile();
 186  36
       BufferedWriter writer = new BufferedWriter(new FileWriter(indexFile));
 187  
 
 188  36
       for (String name : index.keySet()) {
 189  0
         writer.write(name + "=" + index.get(name));
 190  0
         writer.newLine();
 191  
       }
 192  
 
 193  36
       writer.flush();
 194  36
       writer.close();
 195  0
     } catch (Exception e) {
 196  0
       log.error("Error while writing index", e);
 197  36
     }
 198  36
   }
 199  
 
 200  
   /**
 201  
    * Gets the page ID for the specified named page.
 202  
    *
 203  
    * @param name    a String
 204  
    * @return  a String instance, or null if no page exists
 205  
    *          with the specified name
 206  
    */
 207  
   public String getStaticPage(String name) {
 208  0
     return index.get(name);
 209  
   }
 210  
 
 211  
   /**
 212  
    * Gets the list of static page IDs.
 213  
    *
 214  
    * @return    a List<String>
 215  
    */
 216  
   public List<String> getStaticPages() {
 217  0
     return new LinkedList<String>(index.values());
 218  
   }
 219  
 
 220  
   /**
 221  
    * Determines whether a page with the specified permalink exists.
 222  
    *
 223  
    * @param name   the name as a String
 224  
    * @return  true if the page exists, false otherwise
 225  
    */
 226  
   public boolean contains(String name) {
 227  0
     return index.containsKey(name);
 228  
   }
 229  
 
 230  
   /**
 231  
    * Gets the number of static pages.
 232  
    *
 233  
    * @return  an int
 234  
    */
 235  
   public int getNumberOfStaticPages() {
 236  0
     return index.size();
 237  
   }
 238  
 
 239  
   private File getIndexFile() {
 240  2756
     File indexDirectory = new File(blog.getIndexesDirectory(), PAGES_INDEX_DIRECTORY_NAME);
 241  2756
     return new File(indexDirectory, NAME_TO_ID_INDEX_FILE_NAME);
 242  
   }
 243  
 
 244  
   private boolean lock() {
 245  36
     File lockFile = new File(blog.getIndexesDirectory(), LOCK_FILE_NAME);
 246  36
     boolean success = false;
 247  
     try {
 248  36
       success = lockFile.createNewFile();
 249  36
       if (!success) {
 250  0
         lockAttempts++;
 251  
       }
 252  0
     } catch (IOException ioe) {
 253  0
       log.warn("Error while creating lock file", ioe);
 254  36
     }
 255  
 
 256  36
     return success;
 257  
   }
 258  
 
 259  
   private void unlock() {
 260  36
     File lockFile = new File(blog.getIndexesDirectory(), LOCK_FILE_NAME);
 261  36
     lockFile.delete();
 262  36
     lockAttempts = 0;
 263  36
   }
 264  
 
 265  
 }