searchindex.java

### File Source: searchindex.java

             /*
        P/P   *  Method: net.sourceforge.pebble.index.SearchIndex__static_init
              *
              *  Postconditions:
              *    init'ed(log)
              */
         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;
             /*
        P/P   *  Method: void net.sourceforge.pebble.index.SearchIndex(Blog)
              *
              *  Postconditions:
              *    this.blog == blog
              *    init'ed(this.blog)
              */
        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    public SearchIndex(Blog blog) {
        74      this.blog = blog;
        75    }
        76
        77    /**
        78     * Clears the index.
        79     */
        80    public void clear() {
        81      File searchDirectory = new File(blog.getSearchIndexDirectory());
        82      if (!searchDirectory.exists()) {
        83        searchDirectory.mkdirs();
        84      }
        85
        86      synchronized (blog) {
        87        try {
                     /*
        P/P           *  Method: void clear()
                      *
                      *  Preconditions:
                      *    this.blog != null
                      *    (soft) this.blog.properties != null
                      *
                      *  Presumptions:
                      *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                      *
                      *  Test Vectors:
                      *    java.io.File:exists(...)@82: {1}, {0}
                      */
        88          Analyzer analyzer = getAnalyzer();
        89          IndexWriter writer = new IndexWriter(searchDirectory, analyzer, true);
        90          writer.close();
        91        } catch (Exception e) {
        92          log.error(e.getMessage(), e);
        93        }
        94      }
        95    }
        96
        97    /**
        98     * Allows a collection of blog entries to be indexed.
        99     */
       100    public void indexBlogEntries(Collection<BlogEntry> blogEntries) {
       101      synchronized (blog) {
       102        try {
                     /*
        P/P           *  Method: void indexBlogEntries(Collection)
                      *
                      *  Preconditions:
                      *    (soft) blogEntries != null
                      *    (soft) net.sourceforge.pebble.domain.State__static_init.new State(State__static_init#1).name != null
                      *    (soft) net.sourceforge.pebble.domain.State__static_init.new State(State__static_init#5).name != null
                      *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                      *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                      *    (soft) this.blog != null
                      *    (soft) this.blog.properties != null
                      *
                      *  Presumptions:
                      *    blogEntry.blog.rootCategory@106 != null
                      *    blogEntry.blog@106 != null
                      *    blogEntry.comments@106 != null
                      *    blogEntry.state@106 != null
                      *    blogEntry.tagsAsList@106 != null
                      *    ...
                      *
                      *  Test Vectors:
                      *    java.util.Iterator:hasNext(...)@106: {1}, {0}
                      */
       103          Analyzer analyzer = getAnalyzer();
       104          IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
       105
       106          for (BlogEntry blogEntry : blogEntries) {
       107            index(blogEntry, writer);
       108          }
       109
       110          writer.close();
       111        } catch (Exception e) {
       112          log.error(e.getMessage(), e);
       113        }
       114      }
       115    }
       116
       117    /**
       118     * Allows a collection of static pages to be indexed.
       119     */
       120    public void indexStaticPages(Collection<StaticPage> staticPages) {
       121      synchronized (blog) {
       122        try {
                     /*
        P/P           *  Method: void indexStaticPages(Collection)
                      *
                      *  Preconditions:
                      *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                      *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                      *    (soft) staticPages != null
                      *    (soft) this.blog != null
                      *    (soft) this.blog.properties != null
                      *
                      *  Presumptions:
                      *    java.util.Iterator:next(...)@126 != null
                      *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                      *    staticPage.blog@126 != null
                      *
                      *  Test Vectors:
                      *    java.util.Iterator:hasNext(...)@126: {1}, {0}
                      */
       123          Analyzer analyzer = getAnalyzer();
       124          IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
       125
       126          for (StaticPage staticPage : staticPages) {
       127            index(staticPage, writer);
       128          }
       129
       130          writer.close();
       131        } catch (Exception e) {
       132          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    public void index(BlogEntry blogEntry) {
       145      try {
       146        synchronized (blog) {
       147          // first delete the blog entry from the index (if it was there)
       148          unindex(blogEntry);
       149
                     /*
        P/P           *  Method: void index(BlogEntry)
                      *
                      *  Preconditions:
                      *    (soft) blogEntry != null
                      *    (soft) init'ed(blogEntry.author)
                      *    (soft) blogEntry.blog != null
                      *    (soft) init'ed(blogEntry.blog.id)
                      *    (soft) blogEntry.blog.rootCategory != null
                      *    (soft) init'ed(blogEntry.blog.rootCategory...parent)
                      *    (soft) init'ed(blogEntry.blog.rootCategory...tagsAsList)
                      *    (soft) init'ed(blogEntry.blog.rootCategory.parent)
                      *    (soft) init'ed(blogEntry.blog.rootCategory.tagsAsList)
                      *    (soft) init'ed(blogEntry.body)
                      *    ...
                      *
                      *  Presumptions:
                      *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                      *
                      *  Postconditions:
                      *    possibly_updated(blogEntry.permalink)
                      */
       150          Analyzer analyzer = getAnalyzer();
       151          IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
       152          index(blogEntry, writer);
       153          writer.close();
       154        }
       155      } catch (Exception e) {
       156        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    public void index(StaticPage staticPage) {
       168      try {
       169        synchronized (blog) {
       170          // first delete the static page from the index (if it was there)
       171          unindex(staticPage);
       172
                     /*
        P/P           *  Method: void index(StaticPage)
                      *
                      *  Preconditions:
                      *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                      *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                      *    (soft) staticPage != null
                      *    (soft) init'ed(staticPage.author)
                      *    (soft) staticPage.blog != null
                      *    (soft) init'ed(staticPage.blog.id)
                      *    (soft) init'ed(staticPage.body)
                      *    (soft) init'ed(staticPage.date)
                      *    (soft) init'ed(staticPage.excerpt)
                      *    (soft) init'ed(staticPage.id)
                      *    ...
                      *
                      *  Presumptions:
                      *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                      *
                      *  Postconditions:
                      *    possibly_updated(staticPage.permalink)
                      */
       173          Analyzer analyzer = getAnalyzer();
       174          IndexWriter writer = new IndexWriter(blog.getSearchIndexDirectory(), analyzer, false);
       175          index(staticPage, writer);
       176          writer.close();
       177        }
       178      } catch (Exception e) {
       179        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    private Analyzer getAnalyzer() throws Exception {
                 /*
        P/P       *  Method: Analyzer getAnalyzer()
                  *
                  *  Preconditions:
                  *    this.blog != null
                  *    this.blog.properties != null
                  *
                  *  Presumptions:
                  *    java.lang.Class:forName(...)@190 != null
                  *
                  *  Postconditions:
                  *    return_value != null
                  */
       190      Class c = Class.forName(blog.getLuceneAnalyzer());
       191      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    public void unindex(BlogEntry blogEntry) {
       200      try {
       201        synchronized (blog) {
       202          log.debug("Attempting to delete index for " + blogEntry.getTitle());
                     /*
        P/P           *  Method: void unindex(BlogEntry)
                      *
                      *  Preconditions:
                      *    (soft) blogEntry != null
                      *    (soft) init'ed(blogEntry.id)
                      *    (soft) init'ed(blogEntry.title)
                      *    (soft) this.blog != null
                      *
                      *  Presumptions:
                      *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                      *    org.apache.lucene.index.IndexReader:open(...)@203 != null
                      */
       203          IndexReader reader = IndexReader.open(blog.getSearchIndexDirectory());
       204          Term term = new Term("id", blogEntry.getId());
       205          log.debug("Deleted " + reader.delete(term) + " document(s) from the index");
       206          reader.close();
       207        }
       208      } catch (Exception e) {
       209        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    public void unindex(StaticPage staticPage) {
       219      try {
       220        synchronized (blog) {
       221          log.debug("Attempting to delete index for " + staticPage.getTitle());
                     /*
        P/P           *  Method: void unindex(StaticPage)
                      *
                      *  Preconditions:
                      *    (soft) staticPage != null
                      *    (soft) init'ed(staticPage.id)
                      *    (soft) init'ed(staticPage.title)
                      *    (soft) this.blog != null
                      *
                      *  Presumptions:
                      *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                      *    org.apache.lucene.index.IndexReader:open(...)@222 != null
                      */
       222          IndexReader reader = IndexReader.open(blog.getSearchIndexDirectory());
       223          Term term = new Term("id", staticPage.getId());
       224          log.debug("Deleted " + reader.delete(term) + " document(s) from the index");
       225          reader.close();
       226        }
       227      } catch (Exception e) {
       228        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    private void index(BlogEntry blogEntry, IndexWriter writer) {
                 /*
        P/P       *  Method: void index(BlogEntry, IndexWriter)
                  *
                  *  Preconditions:
                  *    blogEntry != null
                  *    blogEntry.state != null
                  *    (soft) init'ed(blogEntry.author)
                  *    (soft) blogEntry.blog != null
                  *    (soft) init'ed(blogEntry.blog.id)
                  *    (soft) blogEntry.blog.rootCategory != null
                  *    (soft) init'ed(blogEntry.blog.rootCategory...parent)
                  *    (soft) init'ed(blogEntry.blog.rootCategory...tagsAsList)
                  *    (soft) init'ed(blogEntry.blog.rootCategory.parent)
                  *    (soft) init'ed(blogEntry.blog.rootCategory.tagsAsList)
                  *    ...
                  *
                  *  Presumptions:
                  *    comment.state@287 != null
                  *    java.util.Iterator:next(...)@276 != null
                  *    java.util.Iterator:next(...)@280 != null
                  *    java.util.Iterator:next(...)@287 != null
                  *    java.util.Iterator:next(...)@295 != null
                  *    ...
                  *
                  *  Postconditions:
                  *    possibly_updated(blogEntry.permalink)
                  *
                  *  Test Vectors:
                  *    blogEntry.author: Addr_Set{null}, Inverse{null}
                  *    blogEntry.body: Addr_Set{null}, Inverse{null}
                  *    blogEntry.title: Addr_Set{null}, Inverse{null}
                  *    java.util.Iterator:hasNext(...)@276: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@280: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@286: {1}, {0}
                  *    java.util.Iterator:hasNext(...)@294: {1}, {0}
                  *    net.sourceforge.pebble.util.StringUtils:truncate(...)@101: Addr_Set{null}, Inverse{null}
                  */
       239      if (!blogEntry.isPublished()) {
       240        return;
       241      }
       242
       243      try {
       244        log.debug("Indexing " + blogEntry.getTitle());
       245        Document document = new Document();
       246        document.add(Field.Keyword("id", blogEntry.getId()));
       247        if (blogEntry.getTitle() != null) {
       248          document.add(Field.Text("title", blogEntry.getTitle()));
       249        } else {
       250          document.add(Field.Text("title", ""));
       251        }
       252        document.add(Field.Keyword("permalink", blogEntry.getPermalink()));
       253        document.add(Field.UnIndexed("date", DateField.dateToString(blogEntry.getDate())));
       254        if (blogEntry.getBody() != null) {
       255          document.add(Field.UnStored("body", blogEntry.getBody()));
       256        } else {
       257          document.add(Field.UnStored("body", ""));
       258        }
       259        if (blogEntry.getTruncatedContent() != null) {
       260          document.add(Field.Text("truncatedBody", blogEntry.getTruncatedContent()));
       261        } else {
       262          document.add(Field.Text("truncatedBody", ""));
       263        }
       264
       265        if (blogEntry.getAuthor() != null) {
       266          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        StringBuffer searchableContent = new StringBuffer();
       272        searchableContent.append(blogEntry.getTitle());
       273        searchableContent.append(" ");
       274        searchableContent.append(blogEntry.getBody());
       275
       276        for (Category category : blogEntry.getCategories()) {
       277          document.add(Field.Text("category", category.getId()));
       278        }
       279
       280        for (Tag tag : blogEntry.getAllTags()) {
       281          document.add(Field.Text("tag", tag.getName()));
       282        }
       283
       284        searchableContent.append(" ");
       285        Iterator it = blogEntry.getComments().iterator();
       286        while (it.hasNext()) {
       287          Comment comment = (Comment)it.next();
       288          if (comment.isApproved()) {
       289            searchableContent.append(comment.getBody());
       290            searchableContent.append(" ");
       291          }
       292        }
       293        it = blogEntry.getTrackBacks().iterator();
       294        while (it.hasNext()) {
       295          TrackBack trackBack = (TrackBack)it.next();
       296          if (trackBack.isApproved()) {
       297            searchableContent.append(trackBack.getExcerpt());
       298            searchableContent.append(" ");
       299          }
       300        }
       301
       302        // join the title and body together to make searching on them both easier
       303        document.add(Field.UnStored("blogEntry", searchableContent.toString()));
       304
       305        writer.addDocument(document);
       306      } catch (Exception e) {
       307        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    private void index(StaticPage staticPage, IndexWriter writer) {
       317      try {
                   /*
        P/P         *  Method: void index(StaticPage, IndexWriter)
                    *
                    *  Preconditions:
                    *    (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
                    *    (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
                    *    (soft) staticPage != null
                    *    (soft) init'ed(staticPage.author)
                    *    (soft) staticPage.blog != null
                    *    (soft) init'ed(staticPage.blog.id)
                    *    (soft) init'ed(staticPage.body)
                    *    (soft) init'ed(staticPage.date)
                    *    (soft) init'ed(staticPage.excerpt)
                    *    (soft) init'ed(staticPage.id)
                    *    ...
                    *
                    *  Presumptions:
                    *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                    *
                    *  Postconditions:
                    *    possibly_updated(staticPage.permalink)
                    *
                    *  Test Vectors:
                    *    staticPage.author: Addr_Set{null}, Inverse{null}
                    *    staticPage.body: Addr_Set{null}, Inverse{null}
                    *    staticPage.title: Addr_Set{null}, Inverse{null}
                    *    net.sourceforge.pebble.util.StringUtils:truncate(...)@101: Addr_Set{null}, Inverse{null}
                    */
       318        log.debug("Indexing " + staticPage.getTitle());
       319        Document document = new Document();
       320        document.add(Field.Keyword("id", staticPage.getId()));
       321        if (staticPage.getTitle() != null) {
       322          document.add(Field.Text("title", staticPage.getTitle()));
       323        } else {
       324          document.add(Field.Text("title", ""));
       325        }
       326        document.add(Field.Keyword("permalink", staticPage.getPermalink()));
       327        document.add(Field.UnIndexed("date", DateField.dateToString(staticPage.getDate())));
       328        if (staticPage.getBody() != null) {
       329          document.add(Field.UnStored("body", staticPage.getBody()));
       330        } else {
       331          document.add(Field.UnStored("body", ""));
       332        }
       333        if (staticPage.getTruncatedContent() != null) {
       334          document.add(Field.Text("truncatedBody", staticPage.getTruncatedContent()));
       335        } else {
       336          document.add(Field.Text("truncatedBody", ""));
       337        }
       338
       339        if (staticPage.getAuthor() != null) {
       340          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        StringBuffer searchableContent = new StringBuffer();
       346        searchableContent.append(staticPage.getTitle());
       347        searchableContent.append(" ");
       348        searchableContent.append(staticPage.getBody());
       349
       350        // join the title and body together to make searching on them both easier
       351        document.add(Field.UnStored("blogEntry", searchableContent.toString()));
       352
       353        writer.addDocument(document);
       354      } catch (Exception e) {
       355        log.error(e.getMessage(), e);
       356      }
       357    }
       358
       359    public SearchResults search(String queryString) throws SearchException {
       360
       361      log.debug("Performing search : " + queryString);
       362
       363      SearchResults searchResults = new SearchResults();
       364      searchResults.setQuery(queryString);
       365
       366      if (queryString != null && queryString.length() > 0) {
                   /*
        P/P         *  Method: SearchResults search(String)
                    *
                    *  Preconditions:
                    *    (soft) this.blog != null
                    *    (soft) this.blog.properties != null
                    *
                    *  Presumptions:
                    *    org.apache.commons.logging.LogFactory:getLog(...)@69 != null
                    *    org.apache.lucene.search.Hits:doc(...)@375 != null
                    *    org.apache.lucene.search.Searcher:search(...)@372 != null
                    *
                    *  Postconditions:
                    *    return_value == &new SearchResults(search#2)
                    *    new SearchResults(search#2) num objects == 1
                    *
                    *  Test Vectors:
                    *    queryString: Addr_Set{null}, Inverse{null}
                    *    java.lang.String:length(...)@366: {0}, {1..232-1}
                    */
       367        Searcher searcher = null;
       368
       369        try {
       370          searcher = new IndexSearcher(blog.getSearchIndexDirectory());
       371          Query query = QueryParser.parse(queryString, "blogEntry", getAnalyzer());
       372          Hits hits = searcher.search(query);
       373
       374          for (int i = 0; i < hits.length(); i++) {
       375            Document doc = hits.doc(i);
       376            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            searchResults.add(result);
       385          }
       386        } catch (ParseException pe) {
       387          pe.printStackTrace();
       388          searchResults.setMessage("Sorry, but there was an error. Please try another search");
       389        } catch (Exception e) {
       390          e.printStackTrace();
       391          throw new SearchException(e.getMessage());
       392        } finally {
    +  393          if (searcher != null) {
       394            try {
       395              searcher.close();
       396            } catch (IOException e) {
       397              // can't do much now! ;-)
       398            }
       399          }
       400        }
       401      }
       402
       403      return searchResults;
       404    }
       405
       406  }
       407

SofCheck Inspector Build Version : 2.22510

searchindex.java | 2010-Jun-25 19:40:32
searchindex.class | 2010-Jul-19 20:23:38