001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.search; 029 030import org.opencms.file.CmsObject; 031import org.opencms.i18n.CmsEncoder; 032import org.opencms.main.CmsException; 033import org.opencms.main.CmsIllegalArgumentException; 034import org.opencms.main.CmsLog; 035import org.opencms.main.OpenCms; 036import org.opencms.search.CmsSearchParameters.CmsSearchFieldQuery; 037import org.opencms.util.CmsStringUtil; 038 039import java.util.ArrayList; 040import java.util.Arrays; 041import java.util.Collections; 042import java.util.Iterator; 043import java.util.List; 044import java.util.Map; 045import java.util.TreeMap; 046 047import org.apache.commons.logging.Log; 048import org.apache.lucene.search.BooleanClause; 049import org.apache.lucene.search.BooleanClause.Occur; 050import org.apache.lucene.search.Sort; 051 052/** 053 * Helper class to access the search facility within a jsp.<p> 054 * 055 * Typically, the following fields are available for searching: 056 * <ul> 057 * <li>title - the title of a resource</li> 058 * <li>keywords - the keywords of a resource</li> 059 * <li>description - the description of a resource</li> 060 * <li>content - the aggregated content of a resource</li> 061 * <li>created - the creation date of a resource</li> 062 * <li>lastmodified - the date of the last modification of a resource</li> 063 * <li>path - the path to display the resource</li> 064 * <li>channel - the channel of a resource</li> 065 * <li>contentdefinition - the name of the content definition class of a resource</li> 066 * </ul> 067 * 068 * @since 6.0.0 069 */ 070public class CmsSearch { 071 072 /** The log object for this class. */ 073 private static final Log LOG = CmsLog.getLog(CmsSearch.class); 074 075 /** The result categories of a search. */ 076 protected Map<String, Integer> m_categoriesFound; 077 078 /** The cms object. */ 079 protected transient CmsObject m_cms; 080 081 /** The latest exception. */ 082 protected Exception m_lastException; 083 084 /** The URL which leads to the next result page. */ 085 protected String m_nextUrl; 086 087 /** The number of pages for the result list. */ 088 protected int m_pageCount; 089 090 /** The restriction for the search parameters, used for "search in search result". */ 091 protected CmsSearchParameters m_parameterRestriction; 092 093 /** The search parameters used for searching, build out of the given individual parameter values. */ 094 protected CmsSearchParameters m_parameters; 095 096 /** The URL which leads to the previous result page. */ 097 protected String m_prevUrl; 098 099 /** The current search result. */ 100 protected List<CmsSearchResult> m_result; 101 102 /** The search parameter String. */ 103 protected String m_searchParameters; 104 105 /** The total number of search results matching the query. */ 106 protected int m_searchResultCount; 107 108 /** Indicates if the parsed query was deliberately set on this instance. */ 109 private boolean m_parsedQuerySet; 110 111 /** 112 * Default constructor, used to instantiate the search facility as a bean.<p> 113 */ 114 public CmsSearch() { 115 116 m_parameters = new CmsSearchParameters(); 117 m_parameters.setSearchRoots(""); 118 m_parameters.setSearchPage(1); 119 m_searchResultCount = 0; 120 m_parameters.setSort(CmsSearchParameters.SORT_DEFAULT); 121 m_parameters.setFields(Arrays.asList(CmsSearchIndex.DOC_META_FIELDS)); 122 m_parsedQuerySet = false; 123 } 124 125 /** 126 * Adds an individual query for a search field.<p> 127 * 128 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setField(String[])} 129 * will be ignored and only the individual field search settings will be used.<p> 130 * 131 * When combining occurrences of SHOULD, MUST and MUST_NOT, keep the following in mind: 132 * All SHOULD clauses will be grouped and wrapped in one query, 133 * all MUST and MUST_NOT clauses will be grouped in another query. 134 * This means that at least one of the terms which are given as a SHOULD query must occur in the 135 * search result.<p> 136 * 137 * @param fieldQuery the field query to use 138 * 139 * @since 8.0.2 140 */ 141 public void addFieldQuery(CmsSearchFieldQuery fieldQuery) { 142 143 m_parameters.addFieldQuery(fieldQuery); 144 resetLastResult(); 145 } 146 147 /** 148 * Adds an individual query for a search field.<p> 149 * 150 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setField(String[])} 151 * will be ignored and only the individual field search settings will be used.<p> 152 * 153 * When combining occurrences of SHOULD, MUST and MUST_NOT, keep the following in mind: 154 * All SHOULD clauses will be grouped and wrapped in one query, 155 * all MUST and MUST_NOT clauses will be grouped in another query. 156 * This means that at least one of the terms which are given as a SHOULD query must occur in the 157 * search result.<p> 158 * 159 * @param fieldName the field name 160 * @param searchQuery the search query 161 * @param occur the occur parameter for the query in the field 162 * 163 * @since 7.5.1 164 */ 165 public void addFieldQuery(String fieldName, String searchQuery, Occur occur) { 166 167 addFieldQuery(new CmsSearchParameters.CmsSearchFieldQuery(fieldName, searchQuery, occur)); 168 } 169 170 /** 171 * Adds an individual query for a search field that MUST occur.<p> 172 * 173 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setField(String[])} 174 * will be ignored and only the individual field search settings will be used.<p> 175 * 176 * When combining occurrences of SHOULD, MUST and MUST_NOT, keep the following in mind: 177 * All SHOULD clauses will be grouped and wrapped in one query, 178 * all MUST and MUST_NOT clauses will be grouped in another query. 179 * This means that at least one of the terms which are given as a SHOULD query must occur in the 180 * search result.<p> 181 * 182 * @param fieldName the field name 183 * @param searchQuery the search query 184 * 185 * @since 7.5.1 186 */ 187 public void addFieldQueryMust(String fieldName, String searchQuery) { 188 189 addFieldQuery(fieldName, searchQuery, BooleanClause.Occur.MUST); 190 } 191 192 /** 193 * Adds an individual query for a search field that MUST NOT occur.<p> 194 * 195 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setField(String[])} 196 * will be ignored and only the individual field search settings will be used.<p> 197 * 198 * When combining occurrences of SHOULD, MUST and MUST_NOT, keep the following in mind: 199 * All SHOULD clauses will be grouped and wrapped in one query, 200 * all MUST and MUST_NOT clauses will be grouped in another query. 201 * This means that at least one of the terms which are given as a SHOULD query must occur in the 202 * search result.<p> 203 * 204 * @param fieldName the field name 205 * @param searchQuery the search query 206 * 207 * @since 7.5.1 208 */ 209 public void addFieldQueryMustNot(String fieldName, String searchQuery) { 210 211 addFieldQuery(fieldName, searchQuery, BooleanClause.Occur.MUST_NOT); 212 } 213 214 /** 215 * Adds an individual query for a search field that SHOULD occur.<p> 216 * 217 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setField(String[])} 218 * will be ignored and only the individual field search settings will be used.<p> 219 * 220 * When combining occurrences of SHOULD, MUST and MUST_NOT, keep the following in mind: 221 * All SHOULD clauses will be grouped and wrapped in one query, 222 * all MUST and MUST_NOT clauses will be grouped in another query. 223 * This means that at least one of the terms which are given as a SHOULD query must occur in the 224 * search result.<p> 225 * 226 * @param fieldName the field name 227 * @param searchQuery the search query 228 * 229 * @since 7.5.1 230 */ 231 public void addFieldQueryShould(String fieldName, String searchQuery) { 232 233 addFieldQuery(fieldName, searchQuery, BooleanClause.Occur.SHOULD); 234 } 235 236 /** 237 * Returns <code>true</code> if a category overview should be shown as part of the result.<p> 238 * 239 * <b>Please note:</b> The calculation of the category count slows down the search time by an order 240 * of magnitude. Make sure that you only use this feature if it's really required! 241 * Be especially careful if your search result list can become large (> 1000 documents), since in this case 242 * overall system performance will certainly be impacted considerably when calculating the categories.<p> 243 * 244 * @return <code>true</code> if a category overview should be shown as part of the result 245 */ 246 public boolean getCalculateCategories() { 247 248 return m_parameters.getCalculateCategories(); 249 } 250 251 /** 252 * Returns the search categories.<p> 253 * 254 * @return the search categories 255 */ 256 public String[] getCategories() { 257 258 List<String> l = m_parameters.getCategories(); 259 return l.toArray(new String[l.size()]); 260 } 261 262 /** 263 * Returns the maximum number of pages which should be shown.<p> 264 * 265 * @return the maximum number of pages which should be shown 266 */ 267 public int getDisplayPages() { 268 269 return m_parameters.getDisplayPages(); 270 } 271 272 /** 273 * Gets the current fields list.<p> 274 * 275 * @return the fields to search 276 */ 277 public String getFields() { 278 279 if (m_parameters.getFields() == null) { 280 return ""; 281 } 282 StringBuffer result = new StringBuffer(); 283 Iterator<String> it = m_parameters.getFields().iterator(); 284 while (it.hasNext()) { 285 result.append(it.next()); 286 result.append(" "); 287 } 288 return result.toString(); 289 } 290 291 /** 292 * Gets the name of the current search index.<p> 293 * 294 * @return the name of the index 295 */ 296 public String getIndex() { 297 298 return m_parameters.getSearchIndex().getName(); 299 } 300 301 /** 302 * Gets the last exception after a search operation.<p> 303 * 304 * @return the exception occurred in a search operation or null 305 */ 306 public Exception getLastException() { 307 308 return m_lastException; 309 } 310 311 /** 312 * Gets the number of matches displayed on each page.<p> 313 * 314 * @return matches per result page 315 */ 316 public int getMatchesPerPage() { 317 318 return m_parameters.getMatchesPerPage(); 319 } 320 321 /** 322 * Returns the maximum creation date a resource must have to be included in the search result.<p> 323 * 324 * @return the maximum creation date a resource must have to be included in the search result 325 */ 326 public long getMaxDateCreated() { 327 328 return m_parameters.getMaxDateCreated(); 329 } 330 331 /** 332 * Returns the maximum last modification date a resource must have to be included in the search result.<p> 333 * 334 * @return the maximum last modification date a resource must have to be included in the search result 335 */ 336 public long getMaxDateLastModified() { 337 338 return m_parameters.getMaxDateLastModified(); 339 } 340 341 /** 342 * Returns the minimum creation date a resource must have to be included in the search result.<p> 343 * 344 * @return the minimum creation date a resource must have to be included in the search result 345 */ 346 public long getMinDateCreated() { 347 348 return m_parameters.getMinDateCreated(); 349 } 350 351 /** 352 * Returns the minimum last modification date a resource must have to be included in the search result.<p> 353 * 354 * @return the minimum last modification date a resource must have to be included in the search result 355 */ 356 public long getMinDateLastModified() { 357 358 return m_parameters.getMinDateLastModified(); 359 } 360 361 /** 362 * Gets the URL for the link to the next result page.<p> 363 * 364 * @return the URL to the next result page 365 */ 366 public String getNextUrl() { 367 368 return m_nextUrl; 369 } 370 371 /** 372 * Creates a sorted map of URLs to link to other search result pages.<p> 373 * 374 * The key values are Integers representing the page number, the entry 375 * holds the corresponding link.<p> 376 * 377 * @return a map with String URLs 378 */ 379 public Map<Integer, String> getPageLinks() { 380 381 Map<Integer, String> links = new TreeMap<Integer, String>(); 382 if (m_pageCount <= 1) { 383 return links; 384 } 385 int startIndex, endIndex; 386 String link = m_cms.getRequestContext().getUri() + m_parameters.toQueryString() + "&searchPage="; 387 if (getDisplayPages() < 1) { 388 // number of displayed pages not limited, build a map with all available page links 389 startIndex = 1; 390 endIndex = m_pageCount; 391 } else { 392 // limited number of displayed pages, calculate page range 393 int currentPage = getSearchPage(); 394 int countBeforeCurrent = getDisplayPages() / 2; 395 int countAfterCurrent; 396 if ((currentPage - countBeforeCurrent) < 1) { 397 // set count before to number of available pages 398 countBeforeCurrent = currentPage - 1; 399 } 400 // set count after to number of remaining pages (- 1 for current page) 401 countAfterCurrent = getDisplayPages() - countBeforeCurrent - 1; 402 // calculate start and end index 403 startIndex = currentPage - countBeforeCurrent; 404 endIndex = currentPage + countAfterCurrent; 405 // check end index 406 if (endIndex > m_pageCount) { 407 int delta = endIndex - m_pageCount; 408 // decrease start index with delta to get the right number of displayed pages 409 startIndex -= delta; 410 // check start index to avoid values < 1 411 if (startIndex < 1) { 412 startIndex = 1; 413 } 414 endIndex = m_pageCount; 415 } 416 } 417 418 // build the sorted tree map of page links 419 for (int i = startIndex; i <= endIndex; i++) { 420 links.put(Integer.valueOf(i), (link + i)); 421 } 422 return links; 423 } 424 425 /** 426 * Returns the search parameters used for searching, build out of the given individual parameter values.<p> 427 * 428 * @return the search parameters used for searching, build out of the given individual parameter values 429 */ 430 public CmsSearchParameters getParameters() { 431 432 if (m_parameterRestriction != null) { 433 m_parameters = m_parameters.restrict(m_parameterRestriction); 434 } 435 return m_parameters; 436 437 } 438 439 /** 440 * Returns the parsed query.<p> 441 * 442 * The parsed query is automatically set by the OpenCms search index when a query is created 443 * with either {@link #setQuery(String)} or {@link #addFieldQuery(CmsSearchFieldQuery)}. 444 * The Lucene query build from the parameters is stored here and can be later used 445 * for paging through the results.<p> 446 * 447 * Please note that this returns only to the query part, not the filter part of the search.<p> 448 * 449 * @return the parsed query 450 */ 451 public String getParsedQuery() { 452 453 return m_parameters.getParsedQuery(); 454 } 455 456 /** 457 * Gets the URL for the link to the previous result page.<p> 458 * 459 * @return the URL to the previous result page 460 */ 461 public String getPreviousUrl() { 462 463 return m_prevUrl; 464 } 465 466 /** 467 * Gets the current search query.<p> 468 * 469 * @return the current query string or null if no query was set before 470 */ 471 public String getQuery() { 472 473 return m_parameters.getQuery(); 474 } 475 476 /** 477 * Gets the minimum search query length.<p> 478 * 479 * @return the minimum search query length 480 */ 481 public int getQueryLength() { 482 483 return m_parameters.getQueryLength(); 484 } 485 486 /** 487 * Gets the current result page.<p> 488 * 489 * @return the current result page 490 */ 491 public int getSearchPage() { 492 493 return m_parameters.getSearchPage(); 494 } 495 496 /** 497 * Returns the search result for the current query, as a list of <code>{@link CmsSearchResult}</code> objects.<p> 498 * 499 * @return the search result (may be empty) or null if no index or query was set before 500 */ 501 public List<CmsSearchResult> getSearchResult() { 502 503 if ((m_cms != null) 504 && (m_result == null) 505 && (m_parameters.getIndex() != null) 506 && (m_parameters.isIgnoreQuery() 507 || CmsStringUtil.isNotEmpty(m_parameters.getQuery()) 508 || CmsStringUtil.isNotEmpty(m_parameters.getParsedQuery()) 509 || (m_parameters.getFieldQueries() != null))) { 510 511 if (!m_parameters.isIgnoreQuery() 512 && CmsStringUtil.isEmpty(m_parameters.getParsedQuery()) 513 && (getQueryLength() > 0)) { 514 515 if (m_parameters.getFieldQueries() != null) { 516 // check all field queries if the length of the query is ok 517 for (CmsSearchParameters.CmsSearchFieldQuery fq : m_parameters.getFieldQueries()) { 518 for (String keyword : fq.getSearchTerms()) { 519 if (CmsStringUtil.isEmpty(keyword) || (keyword.trim().length() < getQueryLength())) { 520 521 m_lastException = new CmsSearchException( 522 Messages.get().container( 523 Messages.ERR_QUERY_TOO_SHORT_1, 524 Integer.valueOf(getQueryLength()))); 525 526 return null; 527 } 528 } 529 } 530 531 } else if (m_parameters.getQuery().trim().length() < getQueryLength()) { 532 533 m_lastException = new CmsSearchException( 534 Messages.get().container(Messages.ERR_QUERY_TOO_SHORT_1, Integer.valueOf(getQueryLength()))); 535 536 return null; 537 } 538 } 539 540 try { 541 542 CmsSearchResultList result = m_parameters.getSearchIndex().search(m_cms, getParameters()); 543 544 if (result.size() > 0) { 545 546 m_result = result; 547 m_searchResultCount = result.getHitCount(); 548 m_categoriesFound = result.getCategories(); 549 550 // re-caluclate the number of pages for this search result 551 m_pageCount = m_searchResultCount / m_parameters.getMatchesPerPage(); 552 if ((m_searchResultCount % m_parameters.getMatchesPerPage()) != 0) { 553 m_pageCount++; 554 } 555 556 // re-calculate the URLs to browse forward and backward in the search result 557 String url = m_cms.getRequestContext().getUri() + m_parameters.toQueryString() + "&searchPage="; 558 if (m_parameters.getSearchPage() > 1) { 559 m_prevUrl = url + (m_parameters.getSearchPage() - 1); 560 } 561 if (m_parameters.getSearchPage() < m_pageCount) { 562 m_nextUrl = url + (m_parameters.getSearchPage() + 1); 563 } 564 } else { 565 m_result = Collections.emptyList(); 566 m_searchResultCount = 0; 567 m_categoriesFound = null; 568 m_pageCount = 0; 569 m_prevUrl = null; 570 m_nextUrl = null; 571 } 572 } catch (Exception exc) { 573 574 if (LOG.isDebugEnabled()) { 575 LOG.debug(Messages.get().getBundle().key(Messages.LOG_SEARCHING_FAILED_0), exc); 576 } 577 578 m_result = null; 579 m_searchResultCount = 0; 580 m_pageCount = 0; 581 582 m_lastException = exc; 583 } 584 } 585 586 return m_result; 587 } 588 589 /** 590 * Returns a map of categories (Strings) for the last search result, mapped to the hit count (Integer) of 591 * the documents in this category, or <code>null</code> if the categories have not been calculated.<p> 592 * 593 * @return a map of categories for the last search result 594 * 595 * @see CmsSearch#getCalculateCategories() 596 * @see CmsSearch#setCalculateCategories(boolean) 597 */ 598 public Map<String, Integer> getSearchResultCategories() { 599 600 return m_categoriesFound; 601 } 602 603 /** 604 * Returns the total number of search results matching the query.<p> 605 * 606 * @return the total number of search results matching the query 607 */ 608 public int getSearchResultCount() { 609 610 return m_searchResultCount; 611 } 612 613 /** 614 * Returns the search roots.<p> 615 * 616 * Only resources that are sub-resources of one of the search roots 617 * are included in the search result.<p> 618 * 619 * The search roots are used <i>in addition to</i> the current site root 620 * of the user performing the search.<p> 621 * 622 * By default, the search roots contain only one entry with an empty string.<p> 623 * 624 * @return the search roots 625 */ 626 public String[] getSearchRoots() { 627 628 List<String> l = m_parameters.getRoots(); 629 return l.toArray(new String[l.size()]); 630 } 631 632 /** 633 * Returns the sort order used for sorting the results of s search.<p> 634 * 635 * @return the sort order used for sorting the results of s search 636 */ 637 public Sort getSortOrder() { 638 639 return m_parameters.getSort(); 640 } 641 642 /** 643 * Initializes the bean with the cms object.<p> 644 * 645 * @param cms the cms object 646 */ 647 public void init(CmsObject cms) { 648 649 m_cms = cms; 650 m_result = null; 651 m_lastException = null; 652 m_pageCount = 0; 653 m_nextUrl = null; 654 m_prevUrl = null; 655 } 656 657 /** 658 * Sets the flag that controls calculation of result categories for the next search, 659 * use this only if it's really required since the search can become very slow using this option.<p> 660 * 661 * <b>Please note:</b> The calculation of the category count slows down the search time by an order 662 * of magnitude. Make sure that you only use this feature if it's really required! 663 * Be especially careful if your search result list can become large (> 1000 documents), since in this case 664 * overall system performance will certainly be impacted considerably when calculating the categories.<p> 665 * 666 * @param calculateCategories if <code>true</code>, the category count will be calculated for the next search 667 */ 668 public void setCalculateCategories(boolean calculateCategories) { 669 670 m_parameters.setCalculateCategories(calculateCategories); 671 } 672 673 /** 674 * Sets the search categories, all search results must be in one of the categories, 675 * the category set must match the indexed category exactly.<p> 676 * 677 * All categories will automatically be trimmed and lower cased, since search categories 678 * are also stored this way in the index.<p> 679 * 680 * @param categories the categories to set 681 */ 682 public void setCategories(String[] categories) { 683 684 List<String> setCategories = new ArrayList<String>(); 685 if (categories != null) { 686 if (categories.length != 0) { 687 // ensure all categories are not null, trimmed, not-empty and lowercased 688 String cat; 689 for (int i = 0; i < categories.length; i++) { 690 cat = categories[i]; 691 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(cat)) { 692 // all categories must internally be lower case, 693 // since the index keywords are lower cased as well 694 cat = cat.trim().toLowerCase(); 695 setCategories.add(cat); 696 } 697 } 698 } 699 } 700 m_parameters.setCategories(setCategories); 701 resetLastResult(); 702 } 703 704 /** 705 * Sets the maximum number of pages which should be shown.<p> 706 * 707 * Enter an odd value to achieve a nice, "symmetric" output.<p> 708 * 709 * @param value the maximum number of pages which should be shown 710 */ 711 public void setDisplayPages(int value) { 712 713 m_parameters.setDisplayPages(value); 714 } 715 716 /** 717 * Controls if the excerpt from a field is generated only for searched fields, or for all fields (the default).<p> 718 * 719 * The default setting is <code>false</code>, which means all text fields configured for the excerpt will 720 * be used to generate the excerpt, regardless if they have been searched in or not.<p> 721 * 722 * Please note: A field will only be included in the excerpt if it has been configured as <code>excerpt="true"</code> 723 * in <code>opencms-search.xml</code>. This method controls if so configured fields are used depending on the 724 * fields searched, see {@link #setField(String[])}.<p> 725 * 726 * @param value if <code>true</code>, the excerpt is generated only from the fields actually searched in 727 */ 728 public void setExcerptOnlySearchedFields(boolean value) { 729 730 m_parameters.setExcerptOnlySearchedFields(value); 731 resetLastResult(); 732 } 733 734 /** 735 * Sets the fields to search.<p> 736 * 737 * If the fields are set to <code>null</code>, 738 * or not set at all, the default fields "content" and "meta" are used.<p> 739 * 740 * For a list of valid field names, see the Interface constants of 741 * <code>{@link org.opencms.search.documents.I_CmsDocumentFactory}</code>. 742 * 743 * @param fields the fields to search 744 */ 745 public void setField(String[] fields) { 746 747 m_parameters.setFields(Arrays.asList(fields)); 748 resetLastResult(); 749 } 750 751 /** 752 * Set the name of the index to search.<p> 753 * 754 * A former search result will be deleted.<p> 755 * 756 * @param indexName the name of the index 757 */ 758 public void setIndex(String indexName) { 759 760 resetLastResult(); 761 if (CmsStringUtil.isNotEmpty(indexName)) { 762 try { 763 I_CmsSearchIndex idx = OpenCms.getSearchManager().getIndex(indexName); 764 CmsSearchIndex index = idx instanceof CmsSearchIndex ? (CmsSearchIndex)idx : null; 765 if (index == null) { 766 throw new CmsException(Messages.get().container(Messages.ERR_INDEX_NOT_FOUND_1, indexName)); 767 } 768 m_parameters.setSearchIndex(index); 769 } catch (Exception exc) { 770 if (LOG.isDebugEnabled()) { 771 LOG.debug(Messages.get().getBundle().key(Messages.LOG_INDEX_ACCESS_FAILED_1, indexName), exc); 772 } 773 m_lastException = exc; 774 } 775 } 776 } 777 778 /** 779 * Sets the number of matches per page.<p> 780 * 781 * @param matches the number of matches per page 782 */ 783 public void setMatchesPerPage(int matches) { 784 785 m_parameters.setMatchesPerPage(matches); 786 resetLastResult(); 787 } 788 789 /** 790 * Sets the maximum creation date a resource must have to be included in the search result.<p> 791 * 792 * @param maxDateCreated the maximum creation date to set 793 */ 794 public void setMaxDateCreated(String maxDateCreated) { 795 796 m_parameters.setMaxDateCreated(CmsStringUtil.getLongValue(maxDateCreated, Long.MAX_VALUE, "maxDateCreated")); 797 } 798 799 /** 800 * Sets the maximum last modification date a resource must have to be included in the search result.<p> 801 * 802 * @param maxDateLastModified the maximum last modification date to set 803 */ 804 public void setMaxDateLastModified(String maxDateLastModified) { 805 806 m_parameters.setMaxDateLastModified( 807 CmsStringUtil.getLongValue(maxDateLastModified, Long.MAX_VALUE, "maxDateLastModified")); 808 } 809 810 /** 811 * Sets the minimum creation date a resource must have to be included in the search result.<p> 812 * 813 * @param minDateCreated the minimum creation date to set 814 */ 815 public void setMinDateCreated(String minDateCreated) { 816 817 m_parameters.setMinDateCreated(CmsStringUtil.getLongValue(minDateCreated, Long.MIN_VALUE, "minDateCreated")); 818 } 819 820 /** 821 * Sets the minimum last modification date a resource must have to be included in the search result.<p> 822 * 823 * @param minDateLastModified he minimum last modification date to set 824 */ 825 public void setMinDateLastModified(String minDateLastModified) { 826 827 m_parameters.setMinDateLastModified( 828 CmsStringUtil.getLongValue(minDateLastModified, Long.MIN_VALUE, "minDateLastModified")); 829 } 830 831 /** 832 * Set the parameters to use if a non null instance is provided. <p> 833 * 834 * @param parameters the parameters to use for the search if a non null instance is provided 835 * 836 */ 837 public void setParameters(CmsSearchParameters parameters) { 838 839 if (parameters != null) { 840 m_parameters = parameters; 841 } 842 } 843 844 /** 845 * Sets the parsed query, which will be parameter decoded first.<p> 846 * 847 * The parsed query is automatically set by the OpenCms search index when a query is created 848 * with either {@link #setQuery(String)} or {@link #addFieldQuery(CmsSearchFieldQuery)}. 849 * The Lucene query build from the parameters is stored here and can be later used 850 * for paging through the results.<p> 851 * 852 * Please note that this applies only to the query part, not the filter part of the search.<p> 853 * 854 * @param parsedQuery the parsed query to set 855 */ 856 public void setParsedQuery(String parsedQuery) { 857 858 try { 859 m_parsedQuerySet = true; 860 m_parameters.setParsedQuery(CmsEncoder.decodeParameter(parsedQuery)); 861 } catch (CmsIllegalArgumentException iae) { 862 m_lastException = iae; 863 } 864 } 865 866 /** 867 * Sets the search query.<p> 868 * 869 * The syntax of the query depends on the search engine used. 870 * A former search result will be deleted.<p> 871 * 872 * @param query the search query (escaped format) 873 */ 874 public void setQuery(String query) { 875 876 try { 877 m_parameters.setQuery(CmsEncoder.decodeParameter(query)); 878 } catch (CmsIllegalArgumentException iae) { 879 m_lastException = iae; 880 } 881 resetLastResult(); 882 } 883 884 /** 885 * Sets the minimum length of the search query.<p> 886 * 887 * @param length the minimum search query length 888 */ 889 public void setQueryLength(int length) { 890 891 m_parameters.setQueryLength(length); 892 } 893 894 /** 895 * Limits the search to a given of resource type only.<p> 896 * 897 * @param resourceType the resource type to limit the search result to 898 * 899 * @since 7.5.1 900 */ 901 public void setResourceType(String resourceType) { 902 903 setResourceTypes(new String[] {resourceType}); 904 } 905 906 /** 907 * Limits the search to a given list of resource types only.<p> 908 * 909 * @param resourceTypes the resource types to limit the search result to 910 */ 911 public void setResourceTypes(String[] resourceTypes) { 912 913 if (resourceTypes != null) { 914 m_parameters.setResourceTypes(Arrays.asList(resourceTypes)); 915 } else { 916 m_parameters.setResourceTypes(null); 917 } 918 resetLastResult(); 919 } 920 921 /** 922 * Restrict the result of the next search to the results of the last search, 923 * restricted with the provided parameters.<p> 924 * 925 * Use this for "seach in search result" functions.<p> 926 * 927 * @param restriction the restriction to use 928 * 929 * @see CmsSearchParameters#restrict(CmsSearchParameters) 930 */ 931 public void setResultRestriction(CmsSearchParameters restriction) { 932 933 resetLastResult(); 934 m_parameterRestriction = restriction; 935 } 936 937 /** 938 * Sets the current result page.<p> 939 * 940 * Works with jsp bean mechanism for request parameter "searchPage" 941 * that is generated here for page links.<p> 942 * 943 * @param page the current result page 944 */ 945 public void setSearchPage(int page) { 946 947 m_parameters.setSearchPage(page); 948 resetLastResult(); 949 } 950 951 /** 952 * Convenience method to set exactly one search root.<p> 953 * 954 * @param searchRoot the search root to set 955 * 956 * @see #setSearchRoots(String[]) 957 */ 958 public void setSearchRoot(String searchRoot) { 959 960 setSearchRoots(CmsStringUtil.splitAsArray(searchRoot, ",")); 961 } 962 963 /** 964 * Sets the search root list.<p> 965 * 966 * Only resources that are sub-resources of one of the search roots 967 * are included in the search result.<p> 968 * 969 * The search roots set here are used <i>in addition to</i> the current site root 970 * of the user performing the search.<p> 971 * 972 * By default, the search roots contain only one entry with an empty string.<p> 973 * 974 * @param searchRoots the search roots to set 975 */ 976 public void setSearchRoots(String[] searchRoots) { 977 978 List<String> l = new ArrayList<String>(Arrays.asList(searchRoots)); 979 m_parameters.setRoots(l); 980 resetLastResult(); 981 } 982 983 /** 984 * Sets the sort order used for sorting the results of s search.<p> 985 * 986 * @param sortOrder the sort order to set 987 */ 988 public void setSortOrder(Sort sortOrder) { 989 990 m_parameters.setSort(sortOrder); 991 resetLastResult(); 992 } 993 994 /** 995 * Resets the last search result.<p> 996 */ 997 private void resetLastResult() { 998 999 m_result = null; 1000 m_lastException = null; 1001 m_categoriesFound = null; 1002 m_parameterRestriction = null; 1003 if (!m_parsedQuerySet) { 1004 // don't reset parsed query if it was deliberately set, otherwise initializing search bean from JSP might fail 1005 m_parameters.setParsedQuery(null); 1006 } 1007 } 1008}