Save This Page
Home » cocoon-2.1.11-src » org.apache » cocoon » generation » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.cocoon.generation;
   18   
   19   import org.apache.avalon.framework.context.Context;
   20   import org.apache.avalon.framework.context.ContextException;
   21   import org.apache.avalon.framework.context.Contextualizable;
   22   import org.apache.avalon.framework.parameters.Parameters;
   23   import org.apache.avalon.framework.service.ServiceException;
   24   
   25   import org.apache.cocoon.Constants;
   26   import org.apache.cocoon.ProcessingException;
   27   import org.apache.cocoon.components.search.LuceneCocoonHelper;
   28   import org.apache.cocoon.components.search.LuceneCocoonPager;
   29   import org.apache.cocoon.components.search.LuceneCocoonSearcher;
   30   import org.apache.cocoon.components.search.LuceneXMLIndexer;
   31   import org.apache.cocoon.environment.ObjectModelHelper;
   32   import org.apache.cocoon.environment.Request;
   33   import org.apache.cocoon.environment.SourceResolver;
   34   
   35   import org.apache.lucene.analysis.Analyzer;
   36   import org.apache.lucene.document.Document;
   37   import org.apache.lucene.document.Field;
   38   import org.apache.lucene.search.Hits;
   39   import org.apache.lucene.store.Directory;
   40   
   41   import org.xml.sax.SAXException;
   42   import org.xml.sax.helpers.AttributesImpl;
   43   
   44   import java.io.File;
   45   import java.io.IOException;
   46   import java.util.Enumeration;
   47   import java.util.Iterator;
   48   import java.util.List;
   49   import java.util.Map;
   50   
   51   /**
   52    * Generates an XML representation of a search result.
   53    *
   54    * <p>
   55    *  This generator generates xml content representening an XML search.
   56    *  The generated xml content contains the search result,
   57    *  the search query information, and navigation information about the
   58    *  search results.
   59    *  The query is sent to the generator, either via the 'queryString' request parameter
   60    *  or the 'query' SiteMap parameter. The sitemap overides the request.
   61    * </p>
   62    *
   63    * <p>
   64    *  Search xml sample generated by this generator:
   65    * </p>
   66    * <pre><tt>
   67    * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
   68    *
   69    * &lt;search:results date=&quot;1008437081064&quot; query-string=&quot;cocoon&quot;
   70    *     start-index=&quot;0&quot; page-length=&quot;10&quot;
   71    *     xmlns:search=&quot;http://apache.org/cocoon/search/1.0&quot;
   72    *     xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot;&gt;
   73    *   &lt;search:hits total-count=&quot;125&quot; count-of-pages=&quot;13&quot;&gt;
   74    *     &lt;search:hit rank=&quot;0&quot; score=&quot;1.0&quot;
   75    *         uri=&quot;http://localhost:8080/cocoon/documents/hosting.html&quot;&gt;
   76    *       &lt;search:field name="title"&gt;Document Title&lt;search:field/&gt;
   77    *     &lt;search:hit/&gt;
   78    *     ...
   79    *   &lt;/search:hits&gt;
   80    *
   81    *   &lt;search:navigation total-count=&quot;125&quot; count-of-pages=&quot;13&quot;
   82    *       has-next=&quot;true&quot; has-previous=&quot;false&quot; next-index=&quot;10&quot; previous-index=&quot;0&quot;&gt;
   83    *     &lt;search:navigation-page start-index=&quot;0&quot;/&gt;
   84    *     &lt;search:navigation-page start-index=&quot;10&quot;/&gt;
   85    *     ...
   86    *     &lt;search:navigation-page start-index=&quot;120&quot;/&gt;
   87    *   &lt;/search:navigation&gt;
   88    * &lt;/search:results&gt;
   89    * </tt></pre>
   90    *
   91    * @author <a href="mailto:berni_huber@a1.net">Bernhard Huber</a>
   92    * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
   93    * @author <a href="mailto:jeremy@apache.org">Jeremy Quinn</a>
   94    * @author <a href="mailto:conal@nzetc.org">Conal Tuohy</a>
   95    * @version CVS $Id: SearchGenerator.java 465914 2006-10-19 22:38:41Z joerg $
   96    */
   97   public class SearchGenerator extends ServiceableGenerator implements Contextualizable {
   98   
   99       /**
  100        * The XML namespace for the output document.
  101        */
  102       protected final static String NAMESPACE = "http://apache.org/cocoon/search/1.0";
  103   
  104       /**
  105        * The XML namespace prefix for the output document.
  106        */
  107       protected final static String PREFIX = "search";
  108   
  109       /**
  110        * The XML namespace for xlink
  111        */
  112       protected final static String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink";
  113   
  114       /**
  115        * Description of the Field
  116        */
  117       protected final static String CDATA = "CDATA";
  118   
  119       /**
  120        * Name of root element of generated xml content, ie <code>results</code>.
  121        */
  122       protected final static String RESULTS_ELEMENT = "results";
  123   
  124       /**
  125        * Qualified name of root element of generated xml content, ie <code>search:results</code>.
  126        */
  127       protected final static String Q_RESULTS_ELEMENT = PREFIX + ":" + RESULTS_ELEMENT;
  128   
  129       /**
  130        * Attribute <code>date</code> of <code>results</code> element.
  131        * It contains the date a long value, indicating when a search
  132        * generated this xml content.
  133        */
  134       protected final static String DATE_ATTRIBUTE = "date";
  135   
  136       /**
  137        * Attribute <code>query-string</code> of <code>results</code> element.
  138        * Echos the <code>queryString</code> query parameter.
  139        */
  140       protected final static String QUERY_STRING_ATTRIBUTE = "query-string";
  141   
  142       /**
  143        * Attribute <code>start-index</code> of <code>results</code> element.
  144        * Echoes the <code>startIndex</code> query parameter.
  145        */
  146       protected final static String START_INDEX_ATTRIBUTE = "start-index";
  147   
  148       /**
  149        * Attribute <code>page-length</code> of <code>results</code> element.
  150        * Echoes the <code>pageLenth</code> query parameter.
  151        */
  152       protected final static String PAGE_LENGTH_ATTRIBUTE = "page-length";
  153   
  154       /**
  155        * Attribute <code>name</code> of <code>hit</code> element.
  156        */
  157       protected final static String NAME_ATTRIBUTE = "name";
  158   
  159       /**
  160        * Child element of generated xml content, ie <code>hits</code>.
  161        * This element describes all hits.
  162        */
  163       protected final static String HITS_ELEMENT = "hits";
  164   
  165       /**
  166        * QName of child element of generated xml content, ie <code>search:hits</code>.
  167        * This element describes all hits.
  168        */
  169       protected final static String Q_HITS_ELEMENT = PREFIX + ":" + HITS_ELEMENT;
  170   
  171       /**
  172        * Attribute <code>total-count</code> of <code>hits</code> element.
  173        * The value describes total number of hits found by the search engine.
  174        */
  175       protected final static String TOTAL_COUNT_ATTRIBUTE = "total-count";
  176   
  177       /**
  178        * Attribute <code>count-of-pages</code> of <code>hits</code> element.
  179        * The value describes number of pages needed for all hits.
  180        */
  181       protected final static String COUNT_OF_PAGES_ATTRIBUTE = "count-of-pages";
  182   
  183       /**
  184        * Child element of generated xml content, ie <code>hit</code>.
  185        * This element describes a single hit.
  186        */
  187       protected final static String HIT_ELEMENT = "hit";
  188   
  189       /**
  190        * QName of child element of generated xml content, ie <code>search:hit</code>.
  191        * This element describes a single hit.
  192        */
  193       protected final static String Q_HIT_ELEMENT = PREFIX + ":" + HIT_ELEMENT;
  194   
  195       /**
  196        * Attribute <code>rank</code> of <code>hit</code> element.
  197        * The value describes the count index of this hits, ranging between 0, and
  198        * total-count minus 1.
  199        */
  200       protected final static String RANK_ATTRIBUTE = "rank";
  201   
  202       /**
  203        * Attribute <code>score</code> of <code>hit</code> element.
  204        * The value describes the score of this hits, ranging between 0, and 1.0.
  205        */
  206       protected final static String SCORE_ATTRIBUTE = "score";
  207   
  208       /**
  209        * Attribute <code>uri</code> of <code>hit</code> element.
  210        * The value describes the uri of a document matching the search query.
  211        */
  212       protected final static String URI_ATTRIBUTE = "uri";
  213   
  214       /**
  215        * Child element <code>field</code> of the <code>hit</code> element.
  216        * This element contains value of the stored field of a hit.
  217        */
  218       protected final static String FIELD_ELEMENT = "field";
  219   
  220       /**
  221        * QName of child element <code>search:field</code> of the <code>hit</code> element.
  222        */
  223       protected final static String Q_FIELD_ELEMENT = PREFIX + ":" + FIELD_ELEMENT;
  224   
  225       /**
  226        * Child element of generated xml content, ie <code>navigation</code>.
  227        * This element describes some hints for easier navigation.
  228        */
  229       protected final static String NAVIGATION_ELEMENT = "navigation";
  230   
  231       /**
  232        * QName of child element of generated xml content, ie <code>search:navigation</code>.
  233        */
  234       protected final static String Q_NAVIGATION_ELEMENT = PREFIX + ":" + NAVIGATION_ELEMENT;
  235   
  236       /**
  237        * Child element of generated xml content, ie <code>navigation-page</code>.
  238        * This element describes the start-index of page containing hits.
  239        */
  240       protected final static String NAVIGATION_PAGE_ELEMENT = "navigation-page";
  241   
  242       /**
  243        * QName of child element of generated xml content, ie <code>search:navigation-page</code>.
  244        * This element describes the start-index of page containing hits.
  245        */
  246       protected final static String Q_NAVIGATION_PAGE_ELEMENT = PREFIX + ":" + NAVIGATION_PAGE_ELEMENT;
  247   
  248       /**
  249        * Attribute <code>has-next</code> of <code>navigation-page</code> element.
  250        * The value is true if a next navigation control should be presented.
  251        */
  252       protected final static String HAS_NEXT_ATTRIBUTE = "has-next";
  253   
  254       /**
  255        * Attribute <code>has-next</code> of <code>navigation-page</code> element.
  256        * The value is true if a previous navigation control should be presented.
  257        */
  258       protected final static String HAS_PREVIOUS_ATTRIBUTE = "has-previous";
  259   
  260       /**
  261        * Attribute <code>next-index</code> of <code>navigation-page</code> element.
  262        * The value describes the start-index of the next-to-be-presented page.
  263        */
  264       protected final static String NEXT_INDEX_ATTRIBUTE = "next-index";
  265   
  266       /**
  267        * Attribute <code>previous-index</code> of <code>navigation-page</code> element.
  268        * The value describes the start-index of the previous-to-be-presented page.
  269        */
  270       protected final static String PREVIOUS_INDEX_ATTRIBUTE = "previous-index";
  271   
  272       /**
  273        * Setup parameter name of index directory, ie <code>index</code>.
  274        */
  275       protected final static String INDEX_PARAM = "index";
  276   
  277       /**
  278        * Default value of setup parameter <code>index</code>, ie <code>index</code>.
  279        */
  280       protected final static String INDEX_PARAM_DEFAULT = "index";
  281   
  282       /**
  283        * Setup parameter name of analyzer name, ie <code>analyzer</code>.
  284        */
  285       protected final static String ANALYZER_PARAM = "analyzer";
  286   
  287       /**
  288        * Default value of analyzer parameter <code>analyzer</code>, ie <code>org.apache.lucene.analysis.standard.StandardAnalyzer</code>.
  289        */
  290       protected final static String ANALYZER_PARAM_DEFAULT = "org.apache.lucene.analysis.standard.StandardAnalyzer";
  291       
  292       /**
  293        * Setup the actual query from generator parameter,
  294        * ie <code>query</code>.
  295        */
  296       protected final static String QUERY_PARAM = "query";
  297   
  298       /**
  299        * Setup parameter name specifying the name of query-string query parameter,
  300        * ie <code>query-string</code>.
  301        */
  302       protected final static String QUERY_STRING_PARAM = "query-string";
  303   
  304       /**
  305        * Default value of setup parameter <code>query-string</code>, ie <code>queryString</code>.
  306        */
  307       protected final static String QUERY_STRING_PARAM_DEFAULT = "queryString";
  308   
  309       /**
  310        * Setup parameter name specifying the name of start-index query parameter,
  311        * ie <code>start-index</code>.
  312        */
  313       protected final static String START_INDEX_PARAM = "start-index";
  314   
  315       /**
  316        * Default value of setup parameter <code>start-index</code>, ie <code>startIndex</code>.
  317        */
  318       protected final static String START_INDEX_PARAM_DEFAULT = "startIndex";
  319   
  320       /**
  321        * Setup parameter name specifying the name of start-next-index query parameter,
  322        * ie <code>start-next-index</code>.
  323        */
  324       protected final static String START_INDEX_NEXT_PARAM = "start-next-index";
  325   
  326       /**
  327        * Default value of setup parameter <code>start-next-index</code>, ie <code>startNextIndex</code>.
  328        */
  329       protected final static String START_INDEX_NEXT_PARAM_DEFAULT = "startNextIndex";
  330   
  331       /**
  332        * Setup parameter name specifying the name of start-previous-index query parameter,
  333        * ie <code>start-previous-index</code>.
  334        */
  335       protected final static String START_INDEX_PREVIOUS_PARAM = "start-previous-index";
  336   
  337       /**
  338        * Default value of setup parameter <code>start-previous-index</code>, ie <code>startPreviousIndex</code>.
  339        */
  340       protected final static String START_INDEX_PREVIOUS_PARAM_DEFAULT = "startPreviousIndex";
  341   
  342       protected final static int START_INDEX_DEFAULT = 0;
  343   
  344       /**
  345        * Setup parameter name specifying the name of page-length query parameter,
  346        * ie <code>page-length</code>.
  347        */
  348       protected final static String PAGE_LENGTH_PARAM = "page-length";
  349   
  350       protected final static String PAGE_LENGTH_PARAM_DEFAULT = "pageLength";
  351   
  352       protected final static int PAGE_LENGTH_DEFAULT = 10;
  353   
  354       /**
  355        * Default home directory of index directories.
  356        * <p>
  357        *   Releative index directories specified in the setup of this generator are resolved
  358        *   relative to this directory.
  359        * </p>
  360        * <p>
  361        *   By default this directory is set to the <code>WORKING_DIR</code> of Cocoon.
  362        * </p>
  363        */
  364       private File workDir = null;
  365   
  366       /**
  367        * The avalon component to use for searching.
  368        */
  369       private LuceneCocoonSearcher lcs;
  370       
  371       /**
  372        * Analyzer used for searching
  373        */
  374       private String analyzer = null;
  375   
  376       /**
  377        * Absolute filesystem directory of lucene index directory
  378        */
  379       private File index = null;
  380   
  381       /**
  382        * Query-string to search for
  383        */
  384       private String queryString = "";
  385   
  386       /**
  387        * Attributes used when generating xml content.
  388        */
  389       private final AttributesImpl atts = new AttributesImpl();
  390   
  391       /**
  392        * startIndex of query parameter
  393        */
  394       private Integer startIndex = null;
  395   
  396       /**
  397        * pageLength of query parameter
  398        */
  399       private Integer pageLength = null;
  400   
  401       /**
  402        * Contextualize this class.
  403        *
  404        * <p>
  405        *   Especially retrieve the work directory.
  406        *   If the index directory is specified relativly, the working directory is
  407        *   used as home directory of the index directory.
  408        * </p>
  409        *
  410        * @param  context               Context to use
  411        * @exception  ContextException  If contextualizing fails.
  412        */
  413       public void contextualize(Context context) throws ContextException {
  414           // retrieve the working directory, assuming that the index may reside there
  415           workDir = (File) context.get(Constants.CONTEXT_WORK_DIR);
  416       }
  417   
  418       // TODO: parameterize()
  419   
  420       /**
  421        * setup all members of this generator.
  422        */
  423       public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
  424                throws ProcessingException, SAXException, IOException {
  425           super.setup(resolver, objectModel, src, par);
  426   
  427           try {
  428               lcs = (LuceneCocoonSearcher) this.manager.lookup(LuceneCocoonSearcher.ROLE);
  429           } catch (ServiceException e) {
  430               throw new ProcessingException("Unable to lookup " + LuceneCocoonSearcher.ROLE, e);
  431           }
  432   
  433           String param_name;
  434           Request request = ObjectModelHelper.getRequest(objectModel);
  435   
  436           String index_file_name = par.getParameter(INDEX_PARAM, INDEX_PARAM_DEFAULT);
  437           if (request.getParameter(INDEX_PARAM) != null) {
  438               index_file_name = request.getParameter(INDEX_PARAM);
  439           }
  440   
  441           // now set the index
  442           index = new File(index_file_name);
  443           if (!index.isAbsolute()) {
  444               index = new File(workDir, index.toString());
  445           }
  446           
  447           // try to get the analyzer from the sitemap parameter
  448           this.analyzer = par.getParameter(ANALYZER_PARAM, ANALYZER_PARAM_DEFAULT);
  449           if (getLogger().isDebugEnabled()) {
  450               getLogger().debug("Analyzer is set to: " + this.analyzer);
  451           }
  452           
  453           // try getting the queryString from the generator sitemap params
  454   
  455           queryString = par.getParameter(QUERY_PARAM, "");
  456   
  457           // try getting the queryString from the request params
  458           if (queryString.length() == 0) {
  459               param_name = par.getParameter(QUERY_STRING_PARAM, QUERY_STRING_PARAM_DEFAULT);
  460               if (request.getParameter(param_name) != null) {
  461                   queryString = request.getParameter(param_name);
  462               }
  463           }
  464           if (getLogger().isDebugEnabled()) {
  465               getLogger().debug("Search index with query: " + queryString);
  466           }
  467           
  468           // always try lookup the start index from the request params
  469           // get startIndex
  470           startIndex = null;
  471           param_name = par.getParameter(START_INDEX_NEXT_PARAM, START_INDEX_NEXT_PARAM_DEFAULT);
  472           if (request.getParameter(param_name) != null) {
  473               startIndex = createInteger(request.getParameter(param_name));
  474           }
  475   
  476           if (startIndex == null) {
  477               param_name = par.getParameter(START_INDEX_PREVIOUS_PARAM, START_INDEX_PREVIOUS_PARAM_DEFAULT);
  478               if (request.getParameter(param_name) != null) {
  479                   startIndex = createInteger(request.getParameter(param_name));
  480               }
  481           }
  482           if (startIndex == null) {
  483               param_name = par.getParameter(START_INDEX_PARAM, START_INDEX_PARAM_DEFAULT);
  484               if (request.getParameter(param_name) != null) {
  485                   startIndex = createInteger(request.getParameter(param_name));
  486               }
  487           }
  488   
  489           // get pageLength
  490           param_name = par.getParameter(PAGE_LENGTH_PARAM, PAGE_LENGTH_PARAM_DEFAULT);
  491           if (request.getParameter(param_name) != null) {
  492               pageLength = createInteger(request.getParameter(param_name));
  493           }
  494       }
  495   
  496       /**
  497        * Generate xml content describing search results.
  498        * Entry point of the ComposerGenerator.
  499        * The xml content is generated from the hits object.
  500        *
  501        * @exception  IOException       when there is a problem reading the from file system.
  502        * @throws  SAXException         when there is a problem creating the output SAX events.
  503        * @throws  ProcessingException  when there is a problem obtaining the hits
  504        */
  505       public void generate() throws IOException, SAXException, ProcessingException {
  506           // set default parameter value, in case of no values are set yet.
  507           if (startIndex == null) {
  508               startIndex = new Integer(START_INDEX_DEFAULT);
  509           }
  510           if (pageLength == null) {
  511               pageLength = new Integer(PAGE_LENGTH_DEFAULT);
  512           }
  513   
  514           // Start the document and set the namespace.
  515           this.contentHandler.startDocument();
  516           this.contentHandler.startPrefixMapping(PREFIX, NAMESPACE);
  517           this.contentHandler.startPrefixMapping("xlink", XLINK_NAMESPACE);
  518   
  519           generateResults();
  520   
  521           // End the document.
  522           this.contentHandler.endPrefixMapping("xlink");
  523           this.contentHandler.endPrefixMapping(PREFIX);
  524           this.contentHandler.endDocument();
  525       }
  526   
  527       /**
  528        * Create an Integer.
  529        * <p>
  530        *   Create an Integer from String s, if conversion fails return null.
  531        * </p>
  532        *
  533        * @param  s  Converting s to an Integer
  534        * @return    Integer converted value originating from s, or null
  535        */
  536       private Integer createInteger(String s) {
  537           Integer i = null;
  538           try {
  539               i = new Integer(s);
  540           } catch (NumberFormatException nfe) {
  541               // ignore it, write only warning
  542               if (getLogger().isWarnEnabled()) {
  543                   getLogger().warn("Cannot convert " + s + " to Integer", nfe);
  544               }
  545           }
  546           return i;
  547       }
  548   
  549       /**
  550        * Build and generate the search results.
  551        * <p>
  552        *  First build the hits, next generate xml content from the hits,
  553        *  taking page index, and length into account.
  554        * </p>
  555        *
  556        * @throws  SAXException         when there is a problem creating the output SAX events.
  557        * @throws  ProcessingException  when there is a problem obtaining the hits
  558        */
  559       private void generateResults() throws SAXException, ProcessingException, IOException {
  560           // Make the hits
  561           LuceneCocoonPager pager = buildHits();
  562   
  563           // The current date and time.
  564           long time = System.currentTimeMillis();
  565   
  566           atts.clear();
  567           atts.addAttribute("", DATE_ATTRIBUTE, DATE_ATTRIBUTE, CDATA, String.valueOf(time));
  568           if (queryString != null && queryString.length() > 0)
  569               atts.addAttribute("", QUERY_STRING_ATTRIBUTE, QUERY_STRING_ATTRIBUTE, CDATA, String.valueOf(queryString));
  570           atts.addAttribute("", START_INDEX_ATTRIBUTE, START_INDEX_ATTRIBUTE, CDATA, String.valueOf(startIndex));
  571           atts.addAttribute("", PAGE_LENGTH_ATTRIBUTE, PAGE_LENGTH_ATTRIBUTE, CDATA, String.valueOf(pageLength));
  572   
  573           contentHandler.startElement(NAMESPACE, RESULTS_ELEMENT, Q_RESULTS_ELEMENT, atts);
  574   
  575           // build xml from the hits
  576           generateHits(pager);
  577           generateNavigation(pager);
  578   
  579           // End root element.
  580           contentHandler.endElement(NAMESPACE, RESULTS_ELEMENT, Q_RESULTS_ELEMENT);
  581       }
  582   
  583       /**
  584        * Generate the xml content of all hits
  585        *
  586        * @param  pager                 the LuceneContentPager with the search results
  587        * @throws  SAXException         when there is a problem creating the output SAX events.
  588        */
  589       private void generateHits(LuceneCocoonPager pager) throws SAXException {
  590           if (pager != null) {
  591               atts.clear();
  592               atts.addAttribute("", TOTAL_COUNT_ATTRIBUTE, TOTAL_COUNT_ATTRIBUTE,
  593                   CDATA, String.valueOf(pager.getCountOfHits()));
  594               atts.addAttribute("", COUNT_OF_PAGES_ATTRIBUTE, COUNT_OF_PAGES_ATTRIBUTE,
  595                   CDATA, String.valueOf(pager.getCountOfPages()));
  596               contentHandler.startElement(NAMESPACE, HITS_ELEMENT, Q_HITS_ELEMENT, atts);
  597               generateHit(pager);
  598               contentHandler.endElement(NAMESPACE, HITS_ELEMENT, Q_HITS_ELEMENT);
  599           }
  600       }
  601   
  602       /**
  603        * Generate the xml content for each hit.
  604        *
  605        * @param  pager                 the LuceneCocoonPager with the search results.
  606        * @throws  SAXException         when there is a problem creating the output SAX events.
  607        */
  608       private void generateHit(LuceneCocoonPager pager) throws SAXException {
  609           // get the off set to start from
  610           int counter = pager.getStartIndex();
  611   
  612           // get an list of hits which should be placed onto a single page
  613           List l = (List) pager.next();
  614           Iterator i = l.iterator();
  615           for (; i.hasNext(); counter++) {
  616               LuceneCocoonPager.HitWrapper hw = (LuceneCocoonPager.HitWrapper) i.next();
  617               Document doc = hw.getDocument();
  618               float score = hw.getScore();
  619               String uri = doc.get(LuceneXMLIndexer.URL_FIELD);
  620   
  621               atts.clear();
  622               atts.addAttribute("", RANK_ATTRIBUTE, RANK_ATTRIBUTE, CDATA,
  623                       String.valueOf(counter));
  624               atts.addAttribute("", SCORE_ATTRIBUTE, SCORE_ATTRIBUTE, CDATA,
  625                       String.valueOf(score));
  626               atts.addAttribute("", URI_ATTRIBUTE, URI_ATTRIBUTE, CDATA,
  627                       String.valueOf(uri));
  628               contentHandler.startElement(NAMESPACE, HIT_ELEMENT, Q_HIT_ELEMENT, atts);
  629               // fix me, add here a summary of this hit
  630               for (Enumeration e = doc.fields(); e.hasMoreElements(); ) {
  631                   Field field = (Field)e.nextElement();
  632                   if (field.isStored()) {
  633                       if (LuceneXMLIndexer.URL_FIELD.equals(field.name()))
  634                           continue;
  635                       atts.clear();
  636                       atts.addAttribute("", NAME_ATTRIBUTE, NAME_ATTRIBUTE, CDATA, field.name());
  637                       contentHandler.startElement(NAMESPACE, FIELD_ELEMENT, Q_FIELD_ELEMENT, atts);
  638                       String value = field.stringValue();
  639                       contentHandler.characters(value.toCharArray(), 0, value.length());
  640                       contentHandler.endElement(NAMESPACE, FIELD_ELEMENT, Q_FIELD_ELEMENT);
  641                   }
  642               }
  643   
  644               contentHandler.endElement(NAMESPACE, HIT_ELEMENT, Q_HIT_ELEMENT);
  645           }
  646       }
  647   
  648       /**
  649        * Generate the navigation element.
  650        *
  651        * @param  pager                    Description of Parameter
  652        * @exception  SAXException         Description of Exception
  653        */
  654       private void generateNavigation(LuceneCocoonPager pager) throws SAXException {
  655           if (pager != null) {
  656               // generate navigation element
  657               atts.clear();
  658               atts.addAttribute("", TOTAL_COUNT_ATTRIBUTE, TOTAL_COUNT_ATTRIBUTE,
  659                   CDATA, String.valueOf(pager.getCountOfHits()));
  660               atts.addAttribute("", COUNT_OF_PAGES_ATTRIBUTE, COUNT_OF_PAGES_ATTRIBUTE,
  661                   CDATA, String.valueOf(pager.getCountOfPages()));
  662               atts.addAttribute("", HAS_NEXT_ATTRIBUTE, HAS_NEXT_ATTRIBUTE,
  663                   CDATA, String.valueOf(pager.hasNext()));
  664               atts.addAttribute("", HAS_PREVIOUS_ATTRIBUTE, HAS_PREVIOUS_ATTRIBUTE,
  665                   CDATA, String.valueOf(pager.hasPrevious()));
  666               atts.addAttribute("", NEXT_INDEX_ATTRIBUTE, NEXT_INDEX_ATTRIBUTE,
  667                   CDATA, String.valueOf(pager.nextIndex()));
  668               atts.addAttribute("", PREVIOUS_INDEX_ATTRIBUTE, PREVIOUS_INDEX_ATTRIBUTE,
  669                   CDATA, String.valueOf(pager.previousIndex()));
  670               contentHandler.startElement(NAMESPACE, NAVIGATION_ELEMENT, Q_NAVIGATION_ELEMENT, atts);
  671               int count_of_pages = pager.getCountOfPages();
  672               for (int i = 0, page_start_index = 0;
  673                       i < count_of_pages;
  674                       i++, page_start_index += pageLength.intValue()) {
  675                   atts.clear();
  676                   atts.addAttribute("", START_INDEX_ATTRIBUTE, START_INDEX_ATTRIBUTE,
  677                       CDATA, String.valueOf(page_start_index));
  678                   contentHandler.startElement(NAMESPACE, NAVIGATION_PAGE_ELEMENT, Q_NAVIGATION_PAGE_ELEMENT, atts);
  679                   contentHandler.endElement(NAMESPACE, NAVIGATION_PAGE_ELEMENT, Q_NAVIGATION_PAGE_ELEMENT);
  680               }
  681               // navigation is EMPTY element
  682               contentHandler.endElement(NAMESPACE, NAVIGATION_ELEMENT, Q_NAVIGATION_ELEMENT);
  683           }
  684       }
  685   
  686       /**
  687        * Build hits from a query input, and setup paging object.
  688        *
  689        * @throws  ProcessingException  if an error occurs
  690        */
  691       private LuceneCocoonPager buildHits() throws ProcessingException, IOException {
  692           if (queryString != null && queryString.length() != 0) {
  693               Hits hits = null;
  694   
  695               Analyzer analyzer = LuceneCocoonHelper.getAnalyzer(this.analyzer);
  696               lcs.setAnalyzer(analyzer);
  697               // get the directory where the index resides
  698               Directory directory = LuceneCocoonHelper.getDirectory(index, false);
  699               lcs.setDirectory(directory);
  700               hits = lcs.search(queryString, LuceneXMLIndexer.BODY_FIELD);
  701   
  702               // wrap the hits by an pager help object for accessing only a range of hits
  703               LuceneCocoonPager pager = new LuceneCocoonPager(hits);
  704   
  705               int start_index = START_INDEX_DEFAULT;
  706               if (this.startIndex != null) {
  707                   start_index = this.startIndex.intValue();
  708                   if (start_index <= 0) {
  709                       start_index = 0;
  710                   }
  711                   pager.setStartIndex(start_index);
  712               }
  713   
  714               int page_length = PAGE_LENGTH_DEFAULT;
  715               if (this.pageLength != null) {
  716                   page_length = this.pageLength.intValue();
  717                   if (page_length <= 0) {
  718                       page_length = hits.length();
  719                   }
  720                   pager.setCountOfHitsPerPage(page_length);
  721               }
  722   
  723               return pager;
  724           }
  725   
  726           return null;
  727       }
  728   
  729       /**
  730        * Recycle the generator
  731        */
  732       public void recycle() {
  733           super.recycle();
  734           if (lcs != null) {
  735               this.manager.release(lcs);
  736           }
  737           this.queryString = null;
  738           this.startIndex = null;
  739           this.pageLength = null;
  740           this.index = null;
  741           this.analyzer = null;
  742       }
  743   
  744   }

Save This Page
Home » cocoon-2.1.11-src » org.apache » cocoon » generation » [javadoc | source]