1 16 package org.apache.cocoon.generation; 17 18 import org.apache.avalon.framework.activity.Disposable; 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 import org.apache.avalon.framework.service.ServiceManager; 25 26 import org.apache.cocoon.Constants; 27 import org.apache.cocoon.ProcessingException; 28 import org.apache.cocoon.components.search.LuceneCocoonHelper; 29 import org.apache.cocoon.components.search.LuceneCocoonPager; 30 import org.apache.cocoon.components.search.LuceneCocoonSearcher; 31 import org.apache.cocoon.components.search.LuceneXMLIndexer; 32 import org.apache.cocoon.environment.ObjectModelHelper; 33 import org.apache.cocoon.environment.Request; 34 import org.apache.cocoon.environment.SourceResolver; 35 36 import org.apache.lucene.analysis.Analyzer; 37 import org.apache.lucene.document.Document; 38 import org.apache.lucene.document.Field; 39 import org.apache.lucene.search.Hits; 40 import org.apache.lucene.store.Directory; 41 42 import org.xml.sax.SAXException ; 43 import org.xml.sax.helpers.AttributesImpl ; 44 45 import java.io.File ; 46 import java.io.IOException ; 47 import java.util.Enumeration ; 48 import java.util.Iterator ; 49 import java.util.List ; 50 import java.util.Map ; 51 52 98 public class SearchGenerator extends ServiceableGenerator 99 implements Contextualizable, Disposable 100 { 101 102 105 protected final static String NAMESPACE = "http://apache.org/cocoon/search/1.0"; 106 107 110 protected final static String PREFIX = "search"; 111 112 115 protected final static String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink"; 116 117 120 protected final static String CDATA = "CDATA"; 121 122 125 protected final static String RESULTS_ELEMENT = "results"; 126 127 130 protected final static String Q_RESULTS_ELEMENT = PREFIX + ":" + RESULTS_ELEMENT; 131 132 133 138 protected final static String DATE_ATTRIBUTE = "date"; 139 140 144 protected final static String QUERY_STRING_ATTRIBUTE = "query-string"; 145 146 150 protected final static String START_INDEX_ATTRIBUTE = "start-index"; 151 152 156 protected final static String PAGE_LENGTH_ATTRIBUTE = "page-length"; 157 158 161 protected final static String NAME_ATTRIBUTE = "name"; 162 163 167 protected final static String HITS_ELEMENT = "hits"; 168 169 173 protected final static String Q_HITS_ELEMENT = PREFIX + ":" + HITS_ELEMENT; 174 175 179 protected final static String TOTAL_COUNT_ATTRIBUTE = "total-count"; 180 181 185 protected final static String COUNT_OF_PAGES_ATTRIBUTE = "count-of-pages"; 186 187 191 protected final static String HIT_ELEMENT = "hit"; 192 193 197 protected final static String Q_HIT_ELEMENT = PREFIX + ":" + HIT_ELEMENT; 198 199 204 protected final static String RANK_ATTRIBUTE = "rank"; 205 206 210 protected final static String SCORE_ATTRIBUTE = "score"; 211 212 216 protected final static String URI_ATTRIBUTE = "uri"; 217 218 224 protected final static String FIELD_ELEMENT = "field"; 225 226 229 protected final static String Q_FIELD_ELEMENT = PREFIX + ":" + FIELD_ELEMENT; 230 231 235 protected final static String NAVIGATION_ELEMENT = "navigation"; 236 237 240 protected final static String Q_NAVIGATION_ELEMENT = PREFIX + ":" + NAVIGATION_ELEMENT; 241 242 246 protected final static String NAVIGATION_PAGE_ELEMENT = "navigation-page"; 247 248 252 protected final static String Q_NAVIGATION_PAGE_ELEMENT = PREFIX + ":" + NAVIGATION_PAGE_ELEMENT; 253 254 258 protected final static String HAS_NEXT_ATTRIBUTE = "has-next"; 259 260 264 protected final static String HAS_PREVIOUS_ATTRIBUTE = "has-previous"; 265 266 270 protected final static String NEXT_INDEX_ATTRIBUTE = "next-index"; 271 272 276 protected final static String PREVIOUS_INDEX_ATTRIBUTE = "previous-index"; 277 278 281 protected final static String INDEX_PARAM = "index"; 282 283 286 protected final static String INDEX_PARAM_DEFAULT = "index"; 287 288 292 protected final static String QUERY_PARAM = "query"; 293 294 298 protected final static String QUERY_STRING_PARAM = "query-string"; 299 300 303 protected final static String QUERY_STRING_PARAM_DEFAULT = "queryString"; 304 305 309 protected final static String START_INDEX_PARAM = "start-index"; 310 311 314 protected final static String START_INDEX_PARAM_DEFAULT = "startIndex"; 315 316 320 protected final static String START_INDEX_NEXT_PARAM = "start-next-index"; 321 322 325 protected final static String START_INDEX_NEXT_PARAM_DEFAULT = "startNextIndex"; 326 327 331 protected final static String START_INDEX_PREVIOUS_PARAM = "start-previous-index"; 332 333 336 protected final static String START_INDEX_PREVIOUS_PARAM_DEFAULT = "startPreviousIndex"; 337 338 343 protected final static int START_INDEX_DEFAULT = 0; 344 345 349 protected final static String PAGE_LENGTH_PARAM = "page-length"; 350 351 356 protected final static String PAGE_LENGTH_PARAM_DEFAULT = "pageLength"; 357 358 363 protected final static int PAGE_LENGTH_DEFAULT = 10; 364 365 366 367 377 private File workDir = null; 378 379 382 private LuceneCocoonSearcher lcs; 383 384 387 private File index = null; 388 389 392 private String queryString = ""; 393 394 397 private final AttributesImpl atts = new AttributesImpl (); 398 399 402 private Integer startIndex = null; 403 404 407 private Integer pageLength = null; 408 409 410 412 416 public void service(ServiceManager manager) throws ServiceException { 417 super.service(manager); 418 } 419 420 425 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) 426 throws ProcessingException, SAXException , IOException { 427 super.setup(resolver, objectModel, src, par); 428 429 try { 430 lcs = (LuceneCocoonSearcher) this.manager.lookup(LuceneCocoonSearcher.ROLE); 431 } catch (ServiceException e) { 432 throw new ProcessingException("Unable to lookup " + LuceneCocoonSearcher.ROLE, e); 433 } 434 435 String param_name; 436 Request request = ObjectModelHelper.getRequest(objectModel); 437 438 String index_file_name = par.getParameter(INDEX_PARAM, INDEX_PARAM_DEFAULT); 439 if (request.getParameter(INDEX_PARAM) != null) { 440 index_file_name = request.getParameter(INDEX_PARAM); 441 } 442 443 index = new File (index_file_name); 445 if (!index.isAbsolute()) { 446 index = new File (workDir, index.toString()); 447 } 448 449 451 queryString = par.getParameter(QUERY_PARAM, ""); 452 453 if (queryString.equals("")) { 455 param_name = par.getParameter(QUERY_STRING_PARAM, QUERY_STRING_PARAM_DEFAULT); 456 if (request.getParameter(param_name) != null) { 457 queryString = request.getParameter(param_name); 458 } 459 } 460 startIndex = null; 463 param_name = par.getParameter(START_INDEX_NEXT_PARAM, START_INDEX_NEXT_PARAM_DEFAULT); 464 if (request.getParameter(param_name) != null) { 465 startIndex = createInteger(request.getParameter(param_name)); 466 } 467 468 if (startIndex == null) { 469 param_name = par.getParameter(START_INDEX_PREVIOUS_PARAM, START_INDEX_PREVIOUS_PARAM_DEFAULT); 470 if (request.getParameter(param_name) != null) { 471 startIndex = createInteger(request.getParameter(param_name)); 472 } 473 } 474 if (startIndex == null) { 475 param_name = par.getParameter(START_INDEX_PARAM, START_INDEX_PARAM_DEFAULT); 476 if (request.getParameter(param_name) != null) { 477 startIndex = createInteger(request.getParameter(param_name)); 478 } 479 } 480 481 param_name = par.getParameter(PAGE_LENGTH_PARAM, PAGE_LENGTH_PARAM_DEFAULT); 483 if (request.getParameter(param_name) != null) { 484 pageLength = createInteger(request.getParameter(param_name)); 485 } 486 } 487 488 489 502 public void contextualize(Context context) throws ContextException { 503 workDir = (File ) context.get(Constants.CONTEXT_WORK_DIR); 505 } 506 507 518 public void generate() throws IOException , SAXException , ProcessingException { 519 if (startIndex == null) { 521 startIndex = new Integer (START_INDEX_DEFAULT); 522 } 523 if (pageLength == null) { 524 pageLength = new Integer (PAGE_LENGTH_DEFAULT); 525 } 526 527 this.contentHandler.startDocument(); 529 this.contentHandler.startPrefixMapping(PREFIX, NAMESPACE); 530 this.contentHandler.startPrefixMapping("xlink", XLINK_NAMESPACE); 531 532 generateResults(); 533 534 this.contentHandler.endPrefixMapping("xlink"); 536 this.contentHandler.endPrefixMapping(PREFIX); 537 this.contentHandler.endDocument(); 538 } 539 540 541 551 private Integer createInteger(String s) { 552 Integer i = null; 553 try { 554 i = new Integer (s); 555 } catch (NumberFormatException nfe) { 556 if (getLogger().isWarnEnabled()) { 558 getLogger().warn("Cannot convert " + s + " to Integer", nfe); 559 } 560 } 561 return i; 562 } 563 564 565 576 private void generateResults() throws SAXException , ProcessingException { 577 578 LuceneCocoonPager pager = buildHits(); 580 581 long time = System.currentTimeMillis(); 583 584 atts.clear(); 585 atts.addAttribute("", DATE_ATTRIBUTE, DATE_ATTRIBUTE, CDATA, String.valueOf(time)); 586 if (queryString != null && queryString.length() > 0) 587 atts.addAttribute("", QUERY_STRING_ATTRIBUTE, QUERY_STRING_ATTRIBUTE, CDATA, String.valueOf(queryString)); 588 atts.addAttribute("", START_INDEX_ATTRIBUTE, START_INDEX_ATTRIBUTE, CDATA, String.valueOf(startIndex)); 589 atts.addAttribute("", PAGE_LENGTH_ATTRIBUTE, PAGE_LENGTH_ATTRIBUTE, CDATA, String.valueOf(pageLength)); 590 591 contentHandler.startElement(NAMESPACE, RESULTS_ELEMENT, Q_RESULTS_ELEMENT, atts); 592 593 generateHits(pager); 595 generateNavigation(pager); 596 597 contentHandler.endElement(NAMESPACE, RESULTS_ELEMENT, Q_RESULTS_ELEMENT); 599 } 600 601 602 609 private void generateHits(LuceneCocoonPager pager) throws SAXException { 610 if (pager != null) { 611 atts.clear(); 612 atts.addAttribute("", TOTAL_COUNT_ATTRIBUTE, TOTAL_COUNT_ATTRIBUTE, 613 CDATA, String.valueOf(pager.getCountOfHits())); 614 atts.addAttribute("", COUNT_OF_PAGES_ATTRIBUTE, COUNT_OF_PAGES_ATTRIBUTE, 615 CDATA, String.valueOf(pager.getCountOfPages())); 616 contentHandler.startElement(NAMESPACE, HITS_ELEMENT, Q_HITS_ELEMENT, atts); 617 generateHit(pager); 618 contentHandler.endElement(NAMESPACE, HITS_ELEMENT, Q_HITS_ELEMENT); 619 } 620 } 621 622 623 630 private void generateHit(LuceneCocoonPager pager) throws SAXException { 631 int counter = pager.getStartIndex(); 633 634 List l = (List ) pager.next(); 636 Iterator i = l.iterator(); 637 for (; i.hasNext(); counter++) { 638 LuceneCocoonPager.HitWrapper hw = (LuceneCocoonPager.HitWrapper) i.next(); 639 Document doc = hw.getDocument(); 640 float score = hw.getScore(); 641 String uri = doc.get(LuceneXMLIndexer.URL_FIELD); 642 643 atts.clear(); 644 atts.addAttribute("", RANK_ATTRIBUTE, RANK_ATTRIBUTE, CDATA, 645 String.valueOf(counter)); 646 atts.addAttribute("", SCORE_ATTRIBUTE, SCORE_ATTRIBUTE, CDATA, 647 String.valueOf(score)); 648 atts.addAttribute("", URI_ATTRIBUTE, URI_ATTRIBUTE, CDATA, 649 String.valueOf(uri)); 650 contentHandler.startElement(NAMESPACE, HIT_ELEMENT, Q_HIT_ELEMENT, atts); 651 for (Enumeration e = doc.fields(); e.hasMoreElements(); ) { 653 Field field = (Field)e.nextElement(); 654 if (field.isStored()) { 655 if (LuceneXMLIndexer.URL_FIELD.equals(field.name())) 656 continue; 657 atts.clear(); 658 atts.addAttribute("", NAME_ATTRIBUTE, NAME_ATTRIBUTE, CDATA, field.name()); 659 contentHandler.startElement(NAMESPACE, FIELD_ELEMENT, Q_FIELD_ELEMENT, atts); 660 String value = field.stringValue(); 661 contentHandler.characters(value.toCharArray(), 0, value.length()); 662 contentHandler.endElement(NAMESPACE, FIELD_ELEMENT, Q_FIELD_ELEMENT); 663 } 664 } 665 666 contentHandler.endElement(NAMESPACE, HIT_ELEMENT, Q_HIT_ELEMENT); 667 } 668 } 669 670 671 678 private void generateNavigation(LuceneCocoonPager pager) throws SAXException { 679 680 if (pager != null) { 681 atts.clear(); 683 atts.addAttribute("", TOTAL_COUNT_ATTRIBUTE, TOTAL_COUNT_ATTRIBUTE, 684 CDATA, String.valueOf(pager.getCountOfHits())); 685 atts.addAttribute("", COUNT_OF_PAGES_ATTRIBUTE, COUNT_OF_PAGES_ATTRIBUTE, 686 CDATA, String.valueOf(pager.getCountOfPages())); 687 atts.addAttribute("", HAS_NEXT_ATTRIBUTE, HAS_NEXT_ATTRIBUTE, 688 CDATA, String.valueOf(pager.hasNext())); 689 atts.addAttribute("", HAS_PREVIOUS_ATTRIBUTE, HAS_PREVIOUS_ATTRIBUTE, 690 CDATA, String.valueOf(pager.hasPrevious())); 691 atts.addAttribute("", NEXT_INDEX_ATTRIBUTE, NEXT_INDEX_ATTRIBUTE, 692 CDATA, String.valueOf(pager.nextIndex())); 693 atts.addAttribute("", PREVIOUS_INDEX_ATTRIBUTE, PREVIOUS_INDEX_ATTRIBUTE, 694 CDATA, String.valueOf(pager.previousIndex())); 695 contentHandler.startElement(NAMESPACE, NAVIGATION_ELEMENT, Q_NAVIGATION_ELEMENT, atts); 696 int count_of_pages = pager.getCountOfPages(); 697 for (int i = 0, page_start_index = 0; 698 i < count_of_pages; 699 i++, page_start_index += pageLength.intValue()) { 700 atts.clear(); 701 atts.addAttribute("", START_INDEX_ATTRIBUTE, START_INDEX_ATTRIBUTE, 702 CDATA, String.valueOf(page_start_index)); 703 contentHandler.startElement(NAMESPACE, NAVIGATION_PAGE_ELEMENT, Q_NAVIGATION_PAGE_ELEMENT, atts); 704 contentHandler.endElement(NAMESPACE, NAVIGATION_PAGE_ELEMENT, Q_NAVIGATION_PAGE_ELEMENT); 705 } 706 contentHandler.endElement(NAMESPACE, NAVIGATION_ELEMENT, Q_NAVIGATION_ELEMENT); 708 } 709 } 710 711 712 718 private LuceneCocoonPager buildHits() throws ProcessingException { 719 720 if (queryString != null && queryString.length() != 0) { 721 Hits hits = null; 722 723 try { 724 Analyzer analyzer = LuceneCocoonHelper.getAnalyzer("org.apache.lucene.analysis.standard.StandardAnalyzer"); 725 lcs.setAnalyzer(analyzer); 726 Directory directory = LuceneCocoonHelper.getDirectory(index, false); 728 lcs.setDirectory(directory); 729 hits = lcs.search(queryString, LuceneXMLIndexer.BODY_FIELD); 730 } catch (IOException ioe) { 731 throw new ProcessingException("IOException in search", ioe); 732 } 733 734 LuceneCocoonPager pager = new LuceneCocoonPager(hits); 736 737 int start_index = START_INDEX_DEFAULT; 738 if (this.startIndex != null) { 739 start_index = this.startIndex.intValue(); 740 if (start_index <= 0) { 741 start_index = 0; 742 } 743 pager.setStartIndex(start_index); 744 } 745 746 int page_length = PAGE_LENGTH_DEFAULT; 747 if (this.pageLength != null) { 748 page_length = this.pageLength.intValue(); 749 if (page_length <= 0) { 750 page_length = hits.length(); 751 } 752 pager.setCountOfHitsPerPage(page_length); 753 } 754 755 return pager; 756 } 757 758 return null; 759 } 760 761 764 public void recycle() { 765 super.recycle(); 766 if (lcs != null) { 767 this.manager.release(lcs); 768 } 769 this.queryString = null; 770 this.startIndex = null; 771 this.pageLength = null; 772 this.index = null; 773 } 774 775 public void dispose() { 776 super.dispose(); 777 } 778 } 779 780 | Popular Tags |