File Source: staticpageindex.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.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
/*
P/P * Method: net.sourceforge.pebble.index.StaticPageIndex__static_init
*
* Postconditions:
* init'ed(log)
*/
49 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 private Map<String,String> index = new HashMap<String,String>();
61 private int lockAttempts = 0;
62
/*
P/P * Method: void net.sourceforge.pebble.index.StaticPageIndex(Blog)
*
* Preconditions:
* blog != null
*
* Postconditions:
* this.blog == blog
* this.blog != null
* this.index == &new HashMap(StaticPageIndex#1)
* init'ed(this.lockAttempts)
* new HashMap(StaticPageIndex#1) num objects == 1
*
* Test Vectors:
* java.io.File:exists(...)@68: {1}, {0}
*/
63 public StaticPageIndex(Blog blog) {
64 this.blog = blog;
65
66 // create the directory structure if it doesn't exist
67 File indexDirectory = new File(blog.getIndexesDirectory(), PAGES_INDEX_DIRECTORY_NAME);
68 if (!indexDirectory.exists()) {
69 indexDirectory.mkdirs();
70 }
71
72 readIndex();
73 }
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) {
/*
P/P * Method: void reindex(Collection)
*
* Preconditions:
* this.blog != null
* (soft) this.lockAttempts <= 232-2
* (soft) staticPages != null
*
* Presumptions:
* java.util.Iterator:next(...)@84 != null
*
* Postconditions:
* this.index == One-of{old this.index, &new HashMap(reindex#1)}
* this.lockAttempts == One-of{old this.lockAttempts, old this.lockAttempts + 1, 0}
* init'ed(this.lockAttempts)
* new HashMap(reindex#1) num objects <= 1
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@84: {1}, {0}
*/
81 if (lock()) {
82 // clear the index and add all static pages
83 index = new HashMap<String,String>();
84 for (StaticPage staticPage : staticPages) {
85 index.put(staticPage.getName(), staticPage.getId());
86 }
87
88 // and finally, write the index
89 writeIndex();
90 unlock();
91 }
92 }
93
94 /**
95 * Indexes a single page.
96 *
97 * @param staticPage a Page instance
98 */
99 public synchronized void index(StaticPage staticPage) {
/*
P/P * Method: void index(StaticPage)
*
* Preconditions:
* this.blog != null
* (soft) this.lockAttempts <= 232-2
* (soft) staticPage != null
* (soft) init'ed(staticPage.name)
* (soft) this.index != null
*
* Presumptions:
* java.util.Map:get(...)@107 != null
* java.util.Map:keySet(...)@104 != null
*
* Postconditions:
* init'ed(this.lockAttempts)
*
* Test Vectors:
* java.lang.String:equals(...)@108: {0}, {1}
* java.util.Iterator:hasNext(...)@105: {1}, {0}
*/
100 if (lock()) {
101 readIndex();
102
103 // remove the old entry for this static page
104 Iterator it = index.keySet().iterator();
105 while (it.hasNext()) {
106 String key = (String)it.next();
107 String value = index.get(key);
108 if (value.equals(staticPage.getId())) {
109 it.remove();
110 }
111 }
112
113 // and now add the new entry for this page
114 index.put(staticPage.getName(), staticPage.getId());
115 writeIndex();
116 unlock();
117 } else {
118 if (lockAttempts <= MAXIMUM_LOCK_ATTEMPTS) {
119 try {
120 Thread.sleep(1000);
121 } catch (InterruptedException ie) {
122 // ignore
123 }
124 index(staticPage);
125 } else {
126 blog.error("Could not index static page - try <a href=\"utilities.secureaction?action=buildIndexes\">rebuilding the indexes</a>.");
127 }
128 }
129 }
130
131 /**
132 * Unindexes a single page.
133 *
134 * @param staticPage a Page instance
135 */
136 public synchronized void unindex(StaticPage staticPage) {
/*
P/P * Method: void unindex(StaticPage)
*
* Preconditions:
* this.blog != null
* (soft) this.lockAttempts <= 232-2
* (soft) staticPage != null
* (soft) init'ed(staticPage.name)
* (soft) this.index != null
*
* Postconditions:
* init'ed(this.lockAttempts)
*
* Preconditions:
* (soft) net/sourceforge/pebble/dao/DAOFactory.configuredFactory != null
* (soft) net/sourceforge/pebble/dao/DAOFactory.configuredFactory.staticPageDAO != null
* (soft) net/sourceforge/pebble/domain/AbstractBlog.log != null
* (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
* (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
* (soft) this...lockAttempts <= 232-2
* (soft) this.blog.messages != null
* (soft) this...blog != null
* (soft) this.blog...properties != null
* (soft) this.blog.searchIndex != null
* ...
*
* Presumptions:
* net/sourceforge/pebble/dao/DAOFactory.configuredFactory.staticPageDAO@145 != null
* net/sourceforge/pebble/dao/DAOFactory.configuredFactory@145 != null
* net/sourceforge/pebble/domain/AbstractBlog.log@145 != null
* net/sourceforge/pebble/domain/BlogManager.instance@145 != null
*
* Postconditions:
* possibly_updated(this...index)
* (soft) init'ed(this...lockAttempts)
* init'ed(this.blog.messages)
* new HashMap(reindex#1) num objects <= 1
*/
137 if (lock()) {
138 readIndex();
139 index.remove(staticPage.getName());
140 writeIndex();
141 unlock();
142 } else {
143 if (lockAttempts <= MAXIMUM_LOCK_ATTEMPTS) {
144 try {
145 Thread.sleep(1000);
146 } catch (InterruptedException ie) {
147 // ignore
148 }
149 unindex(staticPage);
150 } else {
151 blog.reindexStaticPages();
152 }
153 }
154 }
155
156 /**
157 * Helper method to load the index.
158 */
159 private void readIndex() {
/*
P/P * Method: void readIndex()
*
* Preconditions:
* this.blog != null
* (soft) this.index != null
*
* Presumptions:
* org.apache.commons.logging.LogFactory:getLog(...)@49 != null
* parts.length@167 >= 2
*
* Test Vectors:
* java.io.File:exists(...)@162: {0}, {1}
*/
160 log.info("Reading index from disk");
161 File indexFile = getIndexFile();
162 if (indexFile.exists()) {
163 try {
164 BufferedReader reader = new BufferedReader(new FileReader(indexFile));
165 String indexEntry = reader.readLine();
166 while (indexEntry != null) {
167 String[] parts = indexEntry.split("=");
168 index.put(parts[0], parts[1]);
169
170 indexEntry = reader.readLine();
171 }
172
173 reader.close();
174 } catch (Exception e) {
175 log.error("Error while reading index", e);
176 }
177 }
178 }
179
180 /**
181 * Helper method to write out the index to disk.
182 */
183 private void writeIndex() {
184 try {
/*
P/P * Method: void writeIndex()
*
* Preconditions:
* (soft) this.blog != null
* (soft) this.index != null
*
* Presumptions:
* java.util.Map:keySet(...)@188 != null
* org.apache.commons.logging.LogFactory:getLog(...)@49 != null
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@188: {1}, {0}
*/
185 File indexFile = getIndexFile();
186 BufferedWriter writer = new BufferedWriter(new FileWriter(indexFile));
187
188 for (String name : index.keySet()) {
189 writer.write(name + "=" + index.get(name));
190 writer.newLine();
191 }
192
193 writer.flush();
194 writer.close();
195 } catch (Exception e) {
196 log.error("Error while writing index", e);
197 }
198 }
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) {
/*
P/P * Method: String getStaticPage(String)
*
* Preconditions:
* this.index != null
*
* Postconditions:
* init'ed(return_value)
*/
208 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() {
/*
P/P * Method: List getStaticPages()
*
* Preconditions:
* this.index != null
*
* Postconditions:
* return_value == &new LinkedList(getStaticPages#1)
* new LinkedList(getStaticPages#1) num objects == 1
*/
217 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) {
/*
P/P * Method: bool contains(String)
*
* Preconditions:
* this.index != null
*
* Postconditions:
* init'ed(return_value)
*/
227 return index.containsKey(name);
228 }
229
230 /**
231 * Gets the number of static pages.
232 *
233 * @return an int
234 */
235 public int getNumberOfStaticPages() {
/*
P/P * Method: int getNumberOfStaticPages()
*
* Preconditions:
* this.index != null
*
* Postconditions:
* init'ed(return_value)
*/
236 return index.size();
237 }
238
239 private File getIndexFile() {
/*
P/P * Method: File getIndexFile()
*
* Preconditions:
* this.blog != null
*
* Postconditions:
* return_value == &new File(getIndexFile#2)
* new File(getIndexFile#2) num objects == 1
*/
240 File indexDirectory = new File(blog.getIndexesDirectory(), PAGES_INDEX_DIRECTORY_NAME);
241 return new File(indexDirectory, NAME_TO_ID_INDEX_FILE_NAME);
242 }
243
244 private boolean lock() {
/*
P/P * Method: bool lock()
*
* Preconditions:
* this.blog != null
* (soft) this.lockAttempts <= 232-2
*
* Presumptions:
* org.apache.commons.logging.LogFactory:getLog(...)@49 != null
*
* Postconditions:
* init'ed(return_value)
* this.lockAttempts == One-of{old this.lockAttempts, old this.lockAttempts + 1}
* (soft) init'ed(this.lockAttempts)
*
* Test Vectors:
* java.io.File:createNewFile(...)@248: {1}, {0}
*/
245 File lockFile = new File(blog.getIndexesDirectory(), LOCK_FILE_NAME);
246 boolean success = false;
247 try {
248 success = lockFile.createNewFile();
249 if (!success) {
250 lockAttempts++;
251 }
252 } catch (IOException ioe) {
253 log.warn("Error while creating lock file", ioe);
254 }
255
256 return success;
257 }
258
259 private void unlock() {
/*
P/P * Method: void unlock()
*
* Preconditions:
* this.blog != null
*
* Postconditions:
* this.lockAttempts == 0
*/
260 File lockFile = new File(blog.getIndexesDirectory(), LOCK_FILE_NAME);
261 lockFile.delete();
262 lockAttempts = 0;
263 }
264
265 }
SofCheck Inspector Build Version : 2.22510
| staticpageindex.java |
2010-Jun-25 19:40:32 |
| staticpageindex.class |
2010-Jul-19 20:23:38 |