KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > Yasna > forum > database > DbQuery


1 /**
2  * Copyright (C) 2001 Yasna.com. All rights reserved.
3  *
4  * ===================================================================
5  * The Apache Software License, Version 1.1
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  * if any, must include the following acknowledgment:
21  * "This product includes software developed by
22  * Yasna.com (http://www.yasna.com)."
23  * Alternately, this acknowledgment may appear in the software itself,
24  * if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Yazd" and "Yasna.com" must not be used to
27  * endorse or promote products derived from this software without
28  * prior written permission. For written permission, please
29  * contact yazd@yasna.com.
30  *
31  * 5. Products derived from this software may not be called "Yazd",
32  * nor may "Yazd" appear in their name, without prior written
33  * permission of Yasna.com.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL YASNA.COM OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of Yasna.com. For more information
51  * on Yasna.com, please see <http://www.yasna.com>.
52  */

53
54 /**
55  * Copyright (C) 2000 CoolServlets.com. All rights reserved.
56  *
57  * ===================================================================
58  * The Apache Software License, Version 1.1
59  *
60  * Redistribution and use in source and binary forms, with or without
61  * modification, are permitted provided that the following conditions
62  * are met:
63  *
64  * 1. Redistributions of source code must retain the above copyright
65  * notice, this list of conditions and the following disclaimer.
66  *
67  * 2. Redistributions in binary form must reproduce the above copyright
68  * notice, this list of conditions and the following disclaimer in
69  * the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3. The end-user documentation included with the redistribution,
73  * if any, must include the following acknowledgment:
74  * "This product includes software developed by
75  * CoolServlets.com (http://www.coolservlets.com)."
76  * Alternately, this acknowledgment may appear in the software itself,
77  * if and wherever such third-party acknowledgments normally appear.
78  *
79  * 4. The names "Jive" and "CoolServlets.com" must not be used to
80  * endorse or promote products derived from this software without
81  * prior written permission. For written permission, please
82  * contact webmaster@coolservlets.com.
83  *
84  * 5. Products derived from this software may not be called "Jive",
85  * nor may "Jive" appear in their name, without prior written
86  * permission of CoolServlets.com.
87  *
88  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
89  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
90  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
91  * DISCLAIMED. IN NO EVENT SHALL COOLSERVLETS.COM OR
92  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
93  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
94  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
95  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
96  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
97  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
98  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99  * SUCH DAMAGE.
100  * ====================================================================
101  *
102  * This software consists of voluntary contributions made by many
103  * individuals on behalf of CoolServlets.com. For more information
104  * on CoolServlets.com, please see <http://www.coolservlets.com>.
105  */

106
107 package com.Yasna.forum.database;
108
109 import java.util.Date JavaDoc;
110 import java.util.Iterator JavaDoc;
111 import java.io.IOException JavaDoc;
112 import java.io.File JavaDoc;
113
114 import org.apache.lucene.analysis.*;
115 import org.apache.lucene.analysis.standard.*;
116 import org.apache.lucene.document.*;
117 import org.apache.lucene.store.*;
118 import org.apache.lucene.search.*;
119 import org.apache.lucene.queryParser.*;
120 import org.apache.lucene.index.*;
121
122 import com.Yasna.forum.*;
123
124 /**
125  * Database implementation of the Query interface using Lucene.
126  */

127 public class DbQuery implements com.Yasna.forum.Query {
128
129     /**
130      * The query String to use for searching. Set it the empty String by
131      * default so that if the user fails to set a query String, there won't
132      * be errors.
133      */

134     private String JavaDoc queryString = "";
135     private java.util.Date JavaDoc beforeDate = null;
136     private java.util.Date JavaDoc afterDate = null;
137     private User user = null;
138     private ForumThread thread = null;
139
140     /**
141      * The results of the query as an array of message ID's.
142      */

143     private int [] results = null;
144
145     private Forum forum;
146     private DbForumFactory factory;
147
148     /**
149      * The maximum number of results to return with a search.
150      */

151     private static final int MAX_RESULTS_SIZE = 500;
152
153     private static String JavaDoc indexPath = null;
154     private static IndexReader reader;
155     private static Searcher searcher;
156     private static Directory searchDirectory = null;
157     private static long indexLastModified;
158     private static Analyzer analyzer = new StandardAnalyzer();
159
160     public DbQuery(Forum forum, DbForumFactory factory){
161         this.forum = forum;
162         this.factory = factory;
163     }
164     public DbQuery(DbForumFactory factory){
165         this.factory = factory;
166         this.forum = null;
167     }
168
169     public void setQueryString(String JavaDoc queryString) {
170         this.queryString = queryString;
171         //reset results
172
results = null;
173     }
174
175     public String JavaDoc getQueryString() {
176         return queryString;
177     }
178
179     public void setBeforeDate(java.util.Date JavaDoc beforeDate) {
180         this.beforeDate = beforeDate;
181         //reset results
182
results = null;
183     }
184
185     public java.util.Date JavaDoc getBeforeDate() {
186         return beforeDate;
187     }
188
189     public void setAfterDate(java.util.Date JavaDoc afterDate){
190         this.afterDate = afterDate;
191         //reset results
192
results = null;
193     }
194
195     public java.util.Date JavaDoc getAfterDate(){
196         return afterDate;
197     }
198
199     public User getFilteredUser() {
200         return user;
201     }
202
203     public void filterOnUser(User user) {
204         this.user = user;
205         results = null;
206     }
207
208     public ForumThread getFilteredThread() {
209         return thread;
210     }
211
212     public void filterOnThread(ForumThread thread) {
213         this.thread = thread;
214         results = null;
215     }
216
217     public int resultCount() {
218         if (results == null) {
219             executeQuery();
220         }
221         return results.length;
222     }
223
224     public Iterator JavaDoc results() {
225         if (results == null) {
226             executeQuery();
227         }
228         return new DbQueryIterator(results, factory);
229     }
230
231     public Iterator JavaDoc results(int startIndex, int numResults){
232         if (results == null) {
233             executeQuery();
234         }
235         return new DbQueryIterator(results, factory, startIndex, numResults);
236     }
237
238     /**
239      * Execute the query and store the results in the results array.
240      */

241     private void executeQuery() {
242         try {
243             Searcher searcher = getSearcher();
244             if (searcher == null) {
245                 //Searcher can be null if the index doesn't exist.
246
results = new int[0];
247                 return;
248             }
249
250             org.apache.lucene.search.Query bodyQuery =
251                 QueryParser.parse(queryString, "body", analyzer);
252
253             org.apache.lucene.search.Query subjectQuery =
254                 QueryParser.parse(queryString, "subject", analyzer);
255
256
257             BooleanQuery comboQuery = new BooleanQuery();
258             comboQuery.add(subjectQuery,false,false);
259             comboQuery.add(bodyQuery,false,false);
260
261             MultiFilter multiFilter = new MultiFilter(2);
262             // This is added in case the Lucene is used to index other material.
263
multiFilter.add(new FieldFilter("Indexer", "FORUMS"));
264
265             if(forum!=null){ // if no forum specified, search all forums
266
//Forum filter
267
String JavaDoc forumID = Integer.toString(forum.getID());
268                 multiFilter.add(new FieldFilter("forumID", forumID));
269             }
270
271             //Date filter
272
if (beforeDate != null || afterDate != null) {
273                 if (beforeDate != null && afterDate != null) {
274                     multiFilter.add(new DateFilter("creationDate", beforeDate, afterDate));
275                 }
276                 else if (beforeDate == null) {
277                     multiFilter.add(DateFilter.After("creationDate", afterDate));
278                 }
279                 else {
280                     multiFilter.add(DateFilter.Before("creationDate", beforeDate));
281                 }
282             }
283
284             //User filter
285
if (user != null) {
286                 String JavaDoc userID = Integer.toString(user.getID());
287                 multiFilter.add(new FieldFilter("userID", userID));
288             }
289
290             //Thread filter
291
if (thread != null) {
292                 String JavaDoc threadID = Integer.toString(thread.getID());
293                 multiFilter.add(new FieldFilter("threadID", threadID));
294             }
295
296             Hits hits = searcher.search(comboQuery, multiFilter);
297             //Don't return more search results than the maximum number allowed.
298
int numResults = hits.length() < MAX_RESULTS_SIZE ?
299                     hits.length() : MAX_RESULTS_SIZE;
300             int [] messages = new int[numResults];
301             for (int i=0; i<numResults; i++) {
302                 messages[i] = Integer.parseInt( ((Document)hits.doc(i)).get("messageID") );
303             }
304             results = messages;
305         }
306         catch (Exception JavaDoc e) {
307             e.printStackTrace();
308             results = new int[0];
309         }
310     }
311
312     /**
313      * Returns a Lucene Searcher that can be used to execute queries. Lucene
314      * can handle index reading even while updates occur. However, in order
315      * for index changes to be reflected in search results, the reader must
316      * be re-opened whenever the modifiedDate changes.<p>
317      *
318      * The location of the index is the "search" subdirectory in [yazdHome]. If
319      * yazdHome is not set correctly, this method will fail.
320      *
321      * @return a Searcher that can be used to execute queries.
322      */

323     private static Searcher getSearcher() throws IOException JavaDoc {
324         if (indexPath == null) {
325             //Get path of where search index should be. It should be
326
//the search subdirectory of [yazdHome].
327
String JavaDoc yazdHome = PropertyManager.getProperty("yazdHome");
328             if (yazdHome == null) {
329                 System.err.println("ERROR: the yazdHome property is not set.");
330                 throw new IOException JavaDoc("Unable to open index for searching " +
331                         "because yazdHome was not set.");
332             }
333             indexPath = yazdHome + File.separator + "search";
334         }
335
336         if (searcher == null) {
337             //Acquire a lock -- analyzer is a convenient object to do this on.
338
synchronized(analyzer) {
339                 if (searcher == null) {
340                     if (indexExists(indexPath)) {
341                         searchDirectory = FSDirectory.getDirectory(indexPath, false);
342                         reader = IndexReader.open(searchDirectory);
343                         indexLastModified = reader.lastModified(searchDirectory);
344                         searcher = new IndexSearcher(reader);
345                     }
346                     //Otherwise, the index doesn't exist, so return null.
347
else {
348                         return null;
349                     }
350                 }
351             }
352         }
353         if (reader.lastModified(searchDirectory) > indexLastModified) {
354             synchronized (analyzer) {
355                 if (reader.lastModified(searchDirectory) > indexLastModified) {
356                     if (indexExists(indexPath)) {
357                         indexLastModified = reader.lastModified(searchDirectory);
358                         //We need to close the indexReader because it has changed.
359
//Re-opening it will make changes visible.
360
reader.close();
361
362                         searchDirectory = FSDirectory.getDirectory(indexPath, false);
363                         reader = IndexReader.open(searchDirectory);
364                         searcher = new IndexSearcher(reader);
365                     }
366                     //Otherwise, the index doesn't exist, so return null.
367
else {
368                         return null;
369                     }
370                 }
371             }
372         }
373         return searcher;
374     }
375
376     /**
377      * Returns true if the search index exists at the specified path.
378      *
379      * @param indexPath the path to check for the search index at.
380      */

381     private static boolean indexExists(String JavaDoc indexPath) {
382         //Lucene always creates a file called "segments" -- if it exists, we
383
//assume that the search index exists.
384
File JavaDoc segments = new File JavaDoc(indexPath + File.separator + "segments");
385         return segments.exists();
386     }
387 }
388
Popular Tags