Clover Coverage Report - Pebble 2.5-SNAPSHOT
Coverage timestamp: Sat Jun 12 2010 09:39:29 EST
../../../../img/srcFileCovDistChart6.png 36% of files have more coverage
148   407   42   12,33
34   266   0,28   12
12     3,5  
1    
This report was generated with an evaluation server license. Purchase Clover or configure your license.
 
  SearchIndex       Line # 66 148 0% 42 79 59,3% 0.5927835
 
  (88)
 
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.*;
35    import net.sourceforge.pebble.search.SearchException;
36    import net.sourceforge.pebble.search.SearchHit;
37    import net.sourceforge.pebble.search.SearchResults;
38    import org.apache.commons.logging.Log;
39    import org.apache.commons.logging.LogFactory;
40    import org.apache.lucene.analysis.Analyzer;
41    import org.apache.lucene.document.DateField;
42    import org.apache.lucene.document.Document;
43    import org.apache.lucene.document.Field;
44    import org.apache.lucene.index.IndexReader;
45    import org.apache.lucene.index.IndexWriter;
46    import org.apache.lucene.index.Term;
47    import org.apache.lucene.queryParser.ParseException;
48    import org.apache.lucene.queryParser.QueryParser;
49    import org.apache.lucene.search.Hits;
50    import org.apache.lucene.search.IndexSearcher;
51    import org.apache.lucene.search.Query;
52    import org.apache.lucene.search.Searcher;
53   
54    import java.io.File;
55    import java.io.IOException;
56    import java.util.Iterator;
57    import java.util.List;
58    import java.util.Collection;
59   
60    /**
61    * Wraps up the functionality to index blog entries. This is really just
62    * a convenient wrapper around Lucene.
63    *
64    * @author Simon Brown
65    */
 
66    public class SearchIndex {
67   
68    /** the log used by this class */
69    private static final Log log = LogFactory.getLog(SearchIndex.class);
70   
71    private final Blog blog;
72   
 
73  1344 toggle public SearchIndex(Blog blog) {
74  1344 this.blog = blog;
75    }
76   
77    /**
78    * Clears the index.
79    */
 
80  28 toggle public void clear() {
81  28 File searchDirectory = new File(blog.getSearchIndexDirectory());
82  28 if (!searchDirectory.exists()) {
83  26 searchDirectory.mkdirs();
84    }
85   
86  28 synchronized (blog) {
87  28 try {
88  28 Analyzer analyzer = getAnalyzer();
89  28 IndexWriter writer = new IndexWriter(searchDirectory, analyzer, true);
90  28 writer.close();
91    } catch (Exception e) {
92  0 log.error(e.getMessage(), e);
93    }
94    }
95    }
96   
97    /**
98    * Allows a collection of blog entries to be indexed.
99    */
 
100  18 toggle public void indexBlogEntries(Collection<BlogEntry> blogEntries) {
101  18 synchronized (blog) {
102  18 try {
103  18 Analyzer analyzer = getAnalyzer();
104  18 IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
105   
106  18 for (BlogEntry blogEntry : blogEntries) {
107  18 index(blogEntry, writer);
108    }
109   
110  18 writer.close();
111    } catch (Exception e) {
112  0 log.error(e.getMessage(), e);
113    }
114    }
115    }
116   
117    /**
118    * Allows a collection of static pages to be indexed.
119    */
 
120  18 toggle public void indexStaticPages(Collection<StaticPage> staticPages) {
121  18 synchronized (blog) {
122  18 try {
123  18 Analyzer analyzer = getAnalyzer();
124  18 IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
125   
126  18 for (StaticPage staticPage : staticPages) {
127  0 index(staticPage, writer);
128    }
129   
130  18 writer.close();
131    } catch (Exception e) {
132  0 log.error(e.getMessage(), e);
133    }
134    }
135    }
136   
137    /**
138    * Allows a single blog entry to be (re)indexed. If the entry is already
139    * indexed, this method deletes the previous index before adding the new
140    * one.
141    *
142    * @param blogEntry the BlogEntry instance to index
143    */
 
144  114 toggle public void index(BlogEntry blogEntry) {
145  114 try {
146  114 synchronized (blog) {
147    // first delete the blog entry from the index (if it was there)
148  114 unindex(blogEntry);
149   
150  114 Analyzer analyzer = getAnalyzer();
151  114 IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
152  16 index(blogEntry, writer);
153  16 writer.close();
154    }
155    } catch (Exception e) {
156  98 log.error(e.getMessage(), e);
157    }
158    }
159   
160    /**
161    * Allows a single static page to be (re)indexed. If the page is already
162    * indexed, this method deletes the previous index before adding the new
163    * one.
164    *
165    * @param staticPage the StaticPage instance to index
166    */
 
167  0 toggle public void index(StaticPage staticPage) {
168  0 try {
169  0 synchronized (blog) {
170    // first delete the static page from the index (if it was there)
171  0 unindex(staticPage);
172   
173  0 Analyzer analyzer = getAnalyzer();
174  0 IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
175  0 index(staticPage, writer);
176  0 writer.close();
177    }
178    } catch (Exception e) {
179  0 log.error(e.getMessage(), e);
180    }
181    }
182   
183    /**
184    * Gets the Analyzer implementation to use.
185    *
186    * @return an Analyzer instance
187    * @throws Exception
188    */
 
189  206 toggle private Analyzer getAnalyzer() throws Exception {
190  206 Class c = Class.forName(blog.getLuceneAnalyzer());
191  206 return (Analyzer)c.newInstance();
192    }
193   
194    /**
195    * Removes the index for a single blog entry to be removed.
196    *
197    * @param blogEntry the BlogEntry instance to be removed
198    */
 
199  138 toggle public void unindex(BlogEntry blogEntry) {
200  138 try {
201  138 synchronized (blog) {
202  138 log.debug("Attempting to delete index for " + blogEntry.getTitle());
203  138 IndexReader reader = IndexReader.open(blog.getSearchIndexDirectory());
204  18 Term term = new Term("id", blogEntry.getId());
205  18 log.debug("Deleted " + reader.delete(term) + " document(s) from the index");
206  18 reader.close();
207    }
208    } catch (Exception e) {
209  120 log.error(e.getMessage(), e);
210    }
211    }
212   
213    /**
214    * Removes the index for a single blog entry to be removed.
215    *
216    * @param staticPage the StaticPage instance to be removed
217    */
 
218  0 toggle public void unindex(StaticPage staticPage) {
219  0 try {
220  0 synchronized (blog) {
221  0 log.debug("Attempting to delete index for " + staticPage.getTitle());
222  0 IndexReader reader = IndexReader.open(blog.getSearchIndexDirectory());
223  0 Term term = new Term("id", staticPage.getId());
224  0 log.debug("Deleted " + reader.delete(term) + " document(s) from the index");
225  0 reader.close();
226    }
227    } catch (Exception e) {
228  0 log.error(e.getMessage(), e);
229    }
230    }
231   
232    /**
233    * Helper method to index an individual blog entry.
234    *
235    * @param blogEntry the BlogEntry instance to index
236    * @param writer the IndexWriter to index with
237    */
 
238  34 toggle private void index(BlogEntry blogEntry, IndexWriter writer) {
239  34 if (!blogEntry.isPublished()) {
240  0 return;
241    }
242   
243  34 try {
244  34 log.debug("Indexing " + blogEntry.getTitle());
245  34 Document document = new Document();
246  34 document.add(Field.Keyword("id", blogEntry.getId()));
247  34 if (blogEntry.getTitle() != null) {
248  34 document.add(Field.Text("title", blogEntry.getTitle()));
249    } else {
250  0 document.add(Field.Text("title", ""));
251    }
252  34 document.add(Field.Keyword("permalink", blogEntry.getPermalink()));
253  34 document.add(Field.UnIndexed("date", DateField.dateToString(blogEntry.getDate())));
254  34 if (blogEntry.getBody() != null) {
255  34 document.add(Field.UnStored("body", blogEntry.getBody()));
256    } else {
257  0 document.add(Field.UnStored("body", ""));
258    }
259  34 if (blogEntry.getTruncatedContent() != null) {
260  34 document.add(Field.Text("truncatedBody", blogEntry.getTruncatedContent()));
261    } else {
262  0 document.add(Field.Text("truncatedBody", ""));
263    }
264   
265  34 if (blogEntry.getAuthor() != null) {
266  34 document.add(Field.Text("author", blogEntry.getAuthor()));
267    }
268   
269    // build up one large string with all searchable content
270    // i.e. entry title, entry body and all response bodies
271  34 StringBuffer searchableContent = new StringBuffer();
272  34 searchableContent.append(blogEntry.getTitle());
273  34 searchableContent.append(" ");
274  34 searchableContent.append(blogEntry.getBody());
275   
276  34 for (Category category : blogEntry.getCategories()) {
277  6 document.add(Field.Text("category", category.getId()));
278    }
279   
280  34 for (Tag tag : blogEntry.getAllTags()) {
281  0 document.add(Field.Text("tag", tag.getName()));
282    }
283   
284  34 searchableContent.append(" ");
285  34 Iterator it = blogEntry.getComments().iterator();
286  46 while (it.hasNext()) {
287  12 Comment comment = (Comment)it.next();
288  12 if (comment.isApproved()) {
289  6 searchableContent.append(comment.getBody());
290  6 searchableContent.append(" ");
291    }
292    }
293  34 it = blogEntry.getTrackBacks().iterator();
294  34 while (it.hasNext()) {
295  0 TrackBack trackBack = (TrackBack)it.next();
296  0 if (trackBack.isApproved()) {
297  0 searchableContent.append(trackBack.getExcerpt());
298  0 searchableContent.append(" ");
299    }
300    }
301   
302    // join the title and body together to make searching on them both easier
303  34 document.add(Field.UnStored("blogEntry", searchableContent.toString()));
304   
305  34 writer.addDocument(document);
306    } catch (Exception e) {
307  0 log.error(e.getMessage(), e);
308    }
309    }
310    /**
311    * Helper method to index an individual blog entry.
312    *
313    * @param staticPage the Page instance instance to index
314    * @param writer the IndexWriter to index with
315    */
 
316  0 toggle private void index(StaticPage staticPage, IndexWriter writer) {
317  0 try {
318  0 log.debug("Indexing " + staticPage.getTitle());
319  0 Document document = new Document();
320  0 document.add(Field.Keyword("id", staticPage.getId()));
321  0 if (staticPage.getTitle() != null) {
322  0 document.add(Field.Text("title", staticPage.getTitle()));
323    } else {
324  0 document.add(Field.Text("title", ""));
325    }
326  0 document.add(Field.Keyword("permalink", staticPage.getPermalink()));
327  0 document.add(Field.UnIndexed("date", DateField.dateToString(staticPage.getDate())));
328  0 if (staticPage.getBody() != null) {
329  0 document.add(Field.UnStored("body", staticPage.getBody()));
330    } else {
331  0 document.add(Field.UnStored("body", ""));
332    }
333  0 if (staticPage.getTruncatedContent() != null) {
334  0 document.add(Field.Text("truncatedBody", staticPage.getTruncatedContent()));
335    } else {
336  0 document.add(Field.Text("truncatedBody", ""));
337    }
338   
339  0 if (staticPage.getAuthor() != null) {
340  0 document.add(Field.Text("author", staticPage.getAuthor()));
341    }
342   
343    // build up one large string with all searchable content
344    // i.e. entry title, entry body and all response bodies
345  0 StringBuffer searchableContent = new StringBuffer();
346  0 searchableContent.append(staticPage.getTitle());
347  0 searchableContent.append(" ");
348  0 searchableContent.append(staticPage.getBody());
349   
350    // join the title and body together to make searching on them both easier
351  0 document.add(Field.UnStored("blogEntry", searchableContent.toString()));
352   
353  0 writer.addDocument(document);
354    } catch (Exception e) {
355  0 log.error(e.getMessage(), e);
356    }
357    }
358   
 
359  28 toggle public SearchResults search(String queryString) throws SearchException {
360   
361  28 log.debug("Performing search : " + queryString);
362   
363  28 SearchResults searchResults = new SearchResults();
364  28 searchResults.setQuery(queryString);
365   
366  28 if (queryString != null && queryString.length() > 0) {
367  28 Searcher searcher = null;
368   
369  28 try {
370  28 searcher = new IndexSearcher(blog.getSearchIndexDirectory());
371  28 Query query = QueryParser.parse(queryString, "blogEntry", getAnalyzer());
372  28 Hits hits = searcher.search(query);
373   
374  42 for (int i = 0; i < hits.length(); i++) {
375  14 Document doc = hits.doc(i);
376  14 SearchHit result = new SearchHit(
377    blog,
378    doc.get("id"),
379    doc.get("permalink"),
380    doc.get("title"),
381    doc.get("truncatedBody"),
382    DateField.stringToDate(doc.get("date")),
383    hits.score(i));
384  14 searchResults.add(result);
385    }
386    } catch (ParseException pe) {
387  0 pe.printStackTrace();
388  0 searchResults.setMessage("Sorry, but there was an error. Please try another search");
389    } catch (Exception e) {
390  0 e.printStackTrace();
391  0 throw new SearchException(e.getMessage());
392    } finally {
393  28 if (searcher != null) {
394  28 try {
395  28 searcher.close();
396    } catch (IOException e) {
397    // can't do much now! ;-)
398    }
399    }
400    }
401    }
402   
403  28 return searchResults;
404    }
405   
406    }
407