KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > roller > presentation > velocity > SearchServlet


1 package org.roller.presentation.velocity;
2
3 import java.io.IOException JavaDoc;
4 import java.io.UnsupportedEncodingException JavaDoc;
5 import java.util.Date JavaDoc;
6 import java.util.Map JavaDoc;
7 import java.util.Set JavaDoc;
8 import java.util.TreeMap JavaDoc;
9 import java.util.TreeSet JavaDoc;
10
11 import javax.servlet.ServletException JavaDoc;
12 import javax.servlet.http.HttpServletRequest JavaDoc;
13 import javax.servlet.http.HttpServletResponse JavaDoc;
14 import javax.servlet.jsp.JspFactory JavaDoc;
15 import javax.servlet.jsp.PageContext JavaDoc;
16
17 import org.apache.commons.collections.comparators.ReverseComparator;
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.apache.lucene.document.Document;
21 import org.apache.lucene.search.Hits;
22 import org.apache.velocity.Template;
23 import org.apache.velocity.context.Context;
24 import org.roller.RollerException;
25 import org.roller.business.search.FieldConstants;
26 import org.roller.business.search.operations.SearchOperation;
27 import org.roller.config.RollerConfig;
28 import org.roller.model.IndexManager;
29 import org.roller.model.Roller;
30 import org.roller.model.UserManager;
31 import org.roller.model.WeblogManager;
32 import org.roller.pojos.WeblogCategoryData;
33 import org.roller.pojos.WeblogEntryComparator;
34 import org.roller.pojos.WeblogEntryData;
35 import org.roller.pojos.WebsiteData;
36 import org.roller.presentation.RollerContext;
37 import org.roller.presentation.RollerRequest;
38 import org.roller.util.DateUtil;
39 import org.roller.util.StringUtils;
40
41
42 /**
43  * This servlet retrieves (and displays) search results.
44  *
45  * @web.servlet name="SearchServlet" load-on-startup="5"
46  * @web.servlet-init-param name="properties" value="/WEB-INF/velocity.properties"
47  * @web.servlet-mapping url-pattern="/search/*"
48  */

49 public class SearchServlet extends BasePageServlet
50 {
51     //~ Static fields/initializers =============================================
52
static final long serialVersionUID = -2150090108300585670L;
53
54     private static Log mLogger =
55         LogFactory.getFactory().getInstance(SearchServlet.class);
56     
57     /* How many results to display */
58     private static int LIMIT = 10;
59     
60     /* Where to start fetching results */
61     private static int OFFSET = 0;
62     
63     /* is searching enabled? */
64     private boolean searchEnabled = true;
65     
66
67     //~ Methods ================================================================
68

69     public Template handleRequest(HttpServletRequest JavaDoc request,
70                         HttpServletResponse JavaDoc response, Context JavaDoc ctx) throws Exception JavaDoc
71     {
72         String JavaDoc enabled = RollerConfig.getProperty("search.enabled");
73         if("false".equalsIgnoreCase(enabled))
74             this.searchEnabled = false;
75         
76         if(! this.searchEnabled) {
77             Template outty = null;
78             Exception JavaDoc pageException = null;
79             try {
80                 ContextLoader.setupContext(
81                         ctx, RollerRequest.getRollerRequest(request), response );
82                 outty = getTemplate( "searchdisabled.vm", "UTF-8" );
83             } catch (Exception JavaDoc e) {
84                 pageException = e;
85                 response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
86             }
87             
88             if (pageException != null) {
89                 mLogger.error("EXCEPTION: in RollerServlet", pageException);
90                 request.setAttribute("DisplayException", pageException);
91             }
92             return outty;
93         }
94         
95          // set request Charcter Encoding here, because the SearchServlet
96
// is not preceeded by the RequestFilter
97
mLogger.debug("handleRequest()");
98         try
99         {
100             // insure that incoming data is parsed as UTF-8
101
request.setCharacterEncoding("UTF-8");
102         }
103         catch (UnsupportedEncodingException JavaDoc e)
104         {
105             throw new ServletException JavaDoc("Can't set incoming encoding to UTF-8");
106         }
107                 
108         ctx.put("term", "");
109         ctx.put("hits", new Integer JavaDoc(0));
110         ctx.put("searchResults", new TreeMap JavaDoc());
111         // to enable better unit testing
112
request.setAttribute("zzz_VelocityContext_zzz", ctx);
113         
114         mLogger.debug("q = "+request.getParameter("q"));
115         
116         // do no work if query term is empty
117
if (StringUtils.isEmpty(request.getParameter("q")))
118         {
119             return generalSearchResults(request, response, ctx);
120         }
121
122         boolean userSpecificSearch = checkForUser(request);
123         try
124         {
125             RollerRequest rreq = getRollerRequest(request, response);
126             
127             SearchOperation search =
128                 new SearchOperation(rreq.getRoller().getIndexManager());
129             search.setTerm(request.getParameter("q"));
130             ctx.put("term", request.getParameter("q"));
131
132             WebsiteData website = null;
133             if (userSpecificSearch)
134             {
135                 website = rreq.getWebsite();
136                 search.setUsername(rreq.getUser().getUserName());
137                 ctx.put("username", rreq.getUser().getUserName());
138             }
139             
140             if (StringUtils.isNotEmpty(request.getParameter("c")))
141             {
142                 search.setCategory(request.getParameter("c"));
143             }
144
145             // execute search
146
executeSearch(rreq.getRoller(), search);
147
148             Map JavaDoc searchResults = new TreeMap JavaDoc();
149             if (search.getResultsCount() == -1)
150             {
151                 // this means there has been a parsing (or IO) error
152
//ctx.put("errorMessage", search.getParseError());
153
ctx.put("errorMessage", "There was a problem with your search.");
154             }
155             else
156             {
157                 // Convert the Hits into WeblogEntryData instances.
158
Hits hits = search.getResults();
159                 searchResults = convertHitsToEntries(rreq, website, hits);
160                 ctx.put("offset", request.getAttribute("offset"));
161                 ctx.put("limit", request.getAttribute("limit"));
162                 
163                 if (request.getAttribute("categories") != null)
164                 {
165                     Set JavaDoc cats = (Set JavaDoc)request.getAttribute("categories");
166                     if (cats.size() > 0)
167                     {
168                         ctx.put("categories", cats);
169                     }
170                 }
171             }
172             ctx.put("searchResults", searchResults);
173             ctx.put("hits", new Integer JavaDoc(search.getResultsCount()));
174         }
175         catch (Exception JavaDoc e)
176         {
177             mLogger.error("EXCEPTION: in SearchServlet", e);
178             request.setAttribute("DisplayException", e);
179             response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
180         }
181
182         if (userSpecificSearch)
183         {
184             return super.handleRequest(request, response, ctx);
185         }
186
187         return generalSearchResults(request, response, ctx);
188     }
189
190     /**
191      * execute search
192      * @param search
193      */

194     private void executeSearch(Roller roller, SearchOperation search)
195     throws RollerException
196     {
197         IndexManager indexMgr = roller.getIndexManager();
198         indexMgr.executeIndexOperationNow(search);
199         if (mLogger.isDebugEnabled())
200         {
201             mLogger.debug("numresults = " + search.getResultsCount());
202         }
203     }
204
205     /**
206      * Iterate over Hits and build sets of WeblogEntryData
207      * objects, placed into Date buckets (in reverse order).
208      *
209      * @param rreq
210      * @param website
211      * @param hits
212      * @throws RollerException
213      * @throws IOException
214      */

215     private TreeMap JavaDoc convertHitsToEntries(
216         RollerRequest rreq, WebsiteData website, Hits hits)
217         throws RollerException, IOException JavaDoc
218     {
219         // determine offset (starting point)
220
int offset = useOffset(rreq.getRequest());
221         if (offset >= hits.length()) offset = OFFSET;
222         rreq.getRequest().setAttribute("offset", new Integer JavaDoc(offset));
223         
224         // determine limit (number of results to display)
225
int limit = useLimit(rreq.getRequest());
226         rreq.getRequest().setAttribute("limit", new Integer JavaDoc(limit));
227         if (offset + limit > hits.length()) limit = hits.length()-offset;
228         
229         boolean userSpecificSearch = checkForUser(rreq.getRequest());
230         TreeMap JavaDoc searchResults = new TreeMap JavaDoc(new ReverseComparator());
231         TreeSet JavaDoc categories = new TreeSet JavaDoc();
232         UserManager userMgr =
233             RollerContext.getRoller(rreq.getRequest()).getUserManager();
234         WeblogManager weblogMgr =
235             RollerContext.getRoller(rreq.getRequest()).getWeblogManager();
236         WeblogEntryData entry;
237         Document doc = null;
238         String JavaDoc username = null;
239         for (int i = offset; i < offset+limit; i++)
240         {
241             entry = null; // reset for each iteration
242

243             doc = hits.doc(i);
244             username =
245                 doc.getField(FieldConstants.USERNAME).stringValue();
246             
247             if (userSpecificSearch && website != null)
248             {
249                 // "wrong user" results have been reported
250
if (username.equals(rreq.getUser().getUserName()))
251                 {
252                     //entry = buildSearchEntry(website, doc);
253

254                     // get real entry for display on user's site
255
entry = weblogMgr.retrieveWeblogEntry(
256                         doc.getField(FieldConstants.ID).stringValue() );
257                 }
258             }
259             else
260             {
261                 website = userMgr.getWebsite(username);
262                 // if user is not enabled, website will be null
263
if (website != null)
264                 {
265                     entry = buildSearchEntry(website, doc);
266                     if (doc.getField(FieldConstants.CATEGORY) != null)
267                     {
268                         categories.add(
269                             doc.getField(FieldConstants.CATEGORY)
270                                 .stringValue());
271                     }
272                 }
273             }
274             
275             // maybe null if search result returned inactive user
276
// or entry's user is not the requested user.
277
if (entry != null)
278             {
279                 addToSearchResults(searchResults, entry);
280             }
281         }
282         rreq.getRequest().setAttribute("categories", categories);
283         return searchResults;
284     }
285
286     /**
287      * @param request
288      * @return
289      */

290     private int useOffset(HttpServletRequest JavaDoc request)
291     {
292         int offset = OFFSET;
293         if (request.getParameter("o") != null)
294         {
295             try
296             {
297                 offset = Integer.valueOf(request.getParameter("o")).intValue();
298             }
299             catch (NumberFormatException JavaDoc e)
300             {
301                 // Not a valid Integer
302
}
303         }
304         return offset;
305     }
306
307     /**
308      * @param request
309      * @return
310      */

311     private int useLimit(HttpServletRequest JavaDoc request)
312     {
313         int limit = LIMIT;
314         if (request.getParameter("n") != null)
315         {
316             try
317             {
318                 limit = Integer.valueOf(request.getParameter("n")).intValue();
319             }
320             catch (NumberFormatException JavaDoc e)
321             {
322                 // Not a valid Integer
323
}
324         }
325         return limit;
326     }
327
328     /**
329      * @param request
330      * @param response
331      * @return
332      */

333     private RollerRequest getRollerRequest(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
334     {
335         PageContext JavaDoc pageContext =
336             JspFactory.getDefaultFactory()
337                 .getPageContext(this, request, response, "", true, 8192, true);
338         
339         // Needed to init request attributes, etc.
340
return RollerRequest.getRollerRequest(pageContext);
341     }
342
343     /**
344      * @param searchResults
345      * @param entry
346      */

347     private void addToSearchResults(TreeMap JavaDoc searchResults, WeblogEntryData entry)
348     {
349         // convert entry's each date to midnight (00m 00h 00s)
350
Date JavaDoc midnight = DateUtil.getStartOfDay( entry.getPubTime() );
351         
352         // ensure we do not get duplicates from Lucene by
353
// using a Set Collection. Entries sorted by pubTime.
354
TreeSet JavaDoc set = (TreeSet JavaDoc) searchResults.get(midnight);
355         if (set == null)
356         {
357             // date is not mapped yet, so we need a new Set
358
set = new TreeSet JavaDoc( new WeblogEntryComparator() );
359             searchResults.put(midnight, set);
360         }
361         set.add(entry);
362     }
363
364     /**
365      * @param website
366      * @param doc
367      * @return
368      */

369     private WeblogEntryData buildSearchEntry(WebsiteData website, Document doc)
370     {
371         String JavaDoc pubTimeStr = doc.getField(FieldConstants.PUBLISHED).stringValue();
372         WeblogEntryData entry = new WeblogEntryData();
373         entry.setWebsite(website);
374         entry.setTitle(doc.getField(FieldConstants.TITLE).stringValue());
375         entry.setAnchor(doc.getField(FieldConstants.ANCHOR).stringValue());
376         entry.setPubTime( DateUtil.parseTimestampFromFormats(pubTimeStr) );
377         entry.setText( doc.getField(FieldConstants.CONTENT_STORED).stringValue() );
378         if (doc.getField(FieldConstants.CATEGORY) != null)
379         {
380             WeblogCategoryData category = new WeblogCategoryData();
381             category.setWebsite(website);
382             category.setName(doc.getField(FieldConstants.CATEGORY).stringValue());
383             entry.setCategory( category );
384         }
385         return entry;
386     }
387
388     /**
389      * If this is not a user-specific search, we need to display the
390      * "generic" search results list.
391      *
392      * @param request
393      * @param response
394      * @param ctx
395      * @return
396      */

397     private Template generalSearchResults(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Context JavaDoc ctx)
398     {
399         Template outty = null;
400         Exception JavaDoc pageException = null;
401         try
402         {
403             ContextLoader.setupContext(
404                 ctx, RollerRequest.getRollerRequest(request), response );
405             outty = getTemplate( "searchresults.vm", "UTF-8" );
406         }
407         catch (Exception JavaDoc e)
408         {
409             pageException = e;
410             response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
411         }
412
413         if (pageException != null)
414         {
415             mLogger.error("EXCEPTION: in RollerServlet", pageException);
416             request.setAttribute("DisplayException", pageException);
417         }
418         return outty;
419     }
420
421     /**
422      * Look in PathInfo so req.getRemoteUser() doesn't interfere.
423      *
424      * @param request
425      * @return
426      */

427     private boolean checkForUser(HttpServletRequest JavaDoc request)
428     {
429         if (StringUtils.isNotEmpty(
430                 request.getParameter(RollerRequest.USERNAME_KEY)))
431         {
432             return true;
433         }
434         
435         String JavaDoc pathInfoStr = request.getPathInfo();
436         pathInfoStr = (pathInfoStr!=null) ? pathInfoStr : "";
437         
438         String JavaDoc[] pathInfo = StringUtils.split(pathInfoStr,"/");
439         if ( pathInfo.length > 0 )
440         {
441             return true; // is a user page
442
}
443         return false;
444     }
445
446 }
447
Popular Tags