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.i18n.CmsEncoder; 031import org.opencms.main.CmsException; 032import org.opencms.main.CmsIllegalArgumentException; 033import org.opencms.main.CmsLog; 034import org.opencms.main.OpenCms; 035import org.opencms.search.fields.CmsSearchField; 036import org.opencms.util.CmsStringUtil; 037 038import java.util.ArrayList; 039import java.util.Arrays; 040import java.util.Iterator; 041import java.util.List; 042 043import org.apache.commons.collections.ListUtils; 044import org.apache.commons.logging.Log; 045import org.apache.lucene.search.BooleanClause; 046import org.apache.lucene.search.BooleanClause.Occur; 047import org.apache.lucene.search.Sort; 048import org.apache.lucene.search.SortField; 049 050/** 051 * Contains the search parameters for a call to <code>{@link org.opencms.search.CmsSearchIndex#search(org.opencms.file.CmsObject, CmsSearchParameters)}</code>.<p> 052 * 053 * Primary purpose is translation of search arguments to response parameters and from request parameters as 054 * well as support for creation of restrictions of several search query parameter sets. <p> 055 * 056 * @since 6.0.0 057 */ 058public class CmsSearchParameters { 059 060 /** 061 * Describes a specific search field query.<p> 062 */ 063 public static class CmsSearchFieldQuery { 064 065 /** The field name. */ 066 private String m_fieldName; 067 068 /** The occur parameter for this field. */ 069 private Occur m_fieldOccur; 070 071 /** The search term list. */ 072 private List<String> m_searchTerms; 073 074 /** The occur parameter used for the search term combination. */ 075 private Occur m_termOccur; 076 077 /** 078 * Creates a new search field query with a variable length search term list.<p> 079 * 080 * @param fieldName the field name 081 * @param fieldOccur the occur parameter for this field 082 * @param termList the search term list 083 * @param termOccur the occur parameter used for the search term combination 084 */ 085 public CmsSearchFieldQuery(String fieldName, Occur fieldOccur, List<String> termList, Occur termOccur) { 086 087 super(); 088 m_fieldName = fieldName; 089 m_fieldOccur = fieldOccur; 090 m_searchTerms = termList; 091 m_termOccur = termOccur; 092 } 093 094 /** 095 * Creates a new search field query with just a single search term.<p> 096 * 097 * Please note: Since there is only one term, the ocucr parameter for the term combination is 098 * not required and set to <code>null</code>.<p> 099 * 100 * @param fieldName the field name 101 * @param searchTerm the search term 102 * @param fieldOccur the occur parameter for this field 103 */ 104 public CmsSearchFieldQuery(String fieldName, String searchTerm, Occur fieldOccur) { 105 106 this(fieldName, fieldOccur, Arrays.asList(searchTerm), null); 107 } 108 109 /** 110 * Returns the field name.<p> 111 * 112 * @return the field name 113 */ 114 public String getFieldName() { 115 116 return m_fieldName; 117 } 118 119 /** 120 * Returns the occur parameter for this field query.<p> 121 * 122 * @return the occur parameter for this field query 123 */ 124 public Occur getOccur() { 125 126 return m_fieldOccur; 127 } 128 129 /** 130 * Returns the first entry from the term list.<p> 131 * 132 * @return the search query 133 * 134 * @deprecated use {@link #getSearchTerms()} instead 135 */ 136 @Deprecated 137 public String getSearchQuery() { 138 139 return m_searchTerms.get(0); 140 } 141 142 /** 143 * Returns the search term list.<p> 144 * 145 * @return the search term list 146 */ 147 public List<String> getSearchTerms() { 148 149 return m_searchTerms; 150 } 151 152 /** 153 * Returns the occur parameter used for the search term combination of this field query.<p> 154 * 155 * @return the occur parameter used for the search term combination of this field query 156 */ 157 public Occur getTermOccur() { 158 159 return m_termOccur; 160 } 161 162 /** 163 * Sets the name of the field to use this query for.<p> 164 * 165 * @param fieldName the name of the field to use this query for 166 */ 167 public void setFieldName(String fieldName) { 168 169 m_fieldName = fieldName; 170 } 171 172 /** 173 * Sets the occur parameter for this field query.<p> 174 * 175 * @param occur the occur parameter to set 176 */ 177 public void setOccur(BooleanClause.Occur occur) { 178 179 m_fieldOccur = occur; 180 } 181 182 /** 183 * Sets the search keywords to just a single entry.<p> 184 * 185 * @param searchQuery the single search keyword to set 186 * 187 * @deprecated use {@link #setSearchTerms(List)} instead 188 */ 189 @Deprecated 190 public void setSearchQuery(String searchQuery) { 191 192 setSearchTerms(Arrays.asList(searchQuery)); 193 } 194 195 /** 196 * Sets the search terms.<p> 197 * 198 * @param searchTerms the search terms to set 199 */ 200 public void setSearchTerms(List<String> searchTerms) { 201 202 m_searchTerms = searchTerms; 203 } 204 } 205 206 /** Sort result documents by date of creation, then score. */ 207 public static final Sort SORT_DATE_CREATED = new Sort( 208 new SortField(CmsSearchField.FIELD_DATE_CREATED, SortField.Type.STRING, true)); 209 210 /** Sort result documents by date of last modification, then score. */ 211 public static final Sort SORT_DATE_LASTMODIFIED = new Sort( 212 new SortField(CmsSearchField.FIELD_DATE_LASTMODIFIED, SortField.Type.STRING, true)); 213 214 /** Default sort order (by document score). */ 215 public static final Sort SORT_DEFAULT = Sort.RELEVANCE; 216 217 /** Names of the default sort options. */ 218 public static final String[] SORT_NAMES = { 219 "SORT_DEFAULT", 220 "SORT_DATE_CREATED", 221 "SORT_DATE_LASTMODIFIED", 222 "SORT_TITLE"}; 223 224 /** Sort result documents by title, then score. */ 225 public static final Sort SORT_TITLE = new Sort( 226 new SortField[] {new SortField(CmsSearchField.FIELD_TITLE, SortField.Type.STRING), SortField.FIELD_SCORE}); 227 228 /** The log object for this class. */ 229 private static final Log LOG = CmsLog.getLog(CmsSearchParameters.class); 230 231 /** The number of displayed pages returned by getPageLinks(). */ 232 protected int m_displayPages; 233 234 /** The number of matches per page. */ 235 protected int m_matchesPerPage; 236 237 /** If <code>true</code>, the category count is calculated for all search results. */ 238 private boolean m_calculateCategories; 239 240 /** The list of categories to limit the search to. */ 241 private List<String> m_categories; 242 243 /** Indicates if all fields should be used for generating the excerpt, regardless if they have been searched or not. */ 244 private boolean m_excerptOnlySearchedFields; 245 246 /** The map of individual search field queries. */ 247 private List<CmsSearchFieldQuery> m_fieldQueries; 248 249 /** The list of search index fields to search in. */ 250 private List<String> m_fields; 251 252 /** The index to search. */ 253 private CmsSearchIndex m_index; 254 255 /** Indicates if the query part should be ignored so that only filters are used for searching. */ 256 private boolean m_isIgnoreQuery; 257 258 /** The creation date the resources have to have as maximum. */ 259 private long m_maxDateCreated; 260 261 /** The last modification date the resources have to have as maximum. */ 262 private long m_maxDateLastModified; 263 264 /** The creation date the resources have to have as minimum. */ 265 private long m_minDateCreated; 266 267 /** The last modification date the resources have to have as minimum. */ 268 private long m_minDateLastModified; 269 270 /** The current result page. */ 271 private int m_page; 272 273 /** The pre-parsed query. */ 274 private String m_parsedQuery; 275 276 /** The search query to use. */ 277 private String m_query; 278 279 /** The minimum length of the search query. */ 280 private int m_queryLength; 281 282 /** The list of resource types to limit the search to. */ 283 private List<String> m_resourceTypes; 284 285 /** Only resource that are sub-resource of one of the search roots are included in the search result. */ 286 private List<String> m_roots; 287 288 /** The sort order for the search. */ 289 private Sort m_sort; 290 291 /** 292 * Creates a new search parameter instance with no search query and 293 * default values for the remaining parameters. <p> 294 * 295 * Before using this search parameters for a search method 296 * <code>{@link #setQuery(String)}</code> has to be invoked. <p> 297 * 298 */ 299 public CmsSearchParameters() { 300 301 this(""); 302 } 303 304 /** 305 * Creates a new search parameter instance with the provided search query and 306 * default values for the remaining parameters. <p> 307 * 308 * Only the "meta" field (combination of content and title) will be used for search. 309 * No search root restriction is chosen. 310 * No category restriction is used. 311 * No category counts are calculated for the result. 312 * Sorting is turned off. This is a simple but fast setup. <p> 313 * 314 * @param query the query to search for 315 */ 316 public CmsSearchParameters(String query) { 317 318 this(query, null, null, null, null, false, null); 319 320 } 321 322 /** 323 * Creates a new search parameter instance with the provided parameter values.<p> 324 * 325 * @param query the search term to search the index 326 * @param fields the list of fields to search 327 * @param roots only resource that are sub-resource of one of the search roots are included in the search result 328 * @param categories the list of categories to limit the search to 329 * @param resourceTypes the list of resource types to limit the search to 330 * @param calculateCategories if <code>true</code>, the category count is calculated for all search results 331 * (use with caution, this option uses much performance) 332 * @param sort the sort order for the search 333 */ 334 public CmsSearchParameters( 335 String query, 336 List<String> fields, 337 List<String> roots, 338 List<String> categories, 339 List<String> resourceTypes, 340 boolean calculateCategories, 341 Sort sort) { 342 343 super(); 344 m_query = (query == null) ? "" : query; 345 if (fields == null) { 346 fields = new ArrayList<String>(2); 347 fields.add(CmsSearchIndex.DOC_META_FIELDS[0]); 348 fields.add(CmsSearchIndex.DOC_META_FIELDS[1]); 349 } 350 m_fields = fields; 351 if (roots == null) { 352 roots = new ArrayList<String>(2); 353 } 354 m_roots = roots; 355 m_categories = (categories == null) ? new ArrayList<String>() : categories; 356 m_resourceTypes = (resourceTypes == null) ? new ArrayList<String>() : resourceTypes; 357 m_calculateCategories = calculateCategories; 358 // null sort is allowed default 359 m_sort = sort; 360 m_page = 1; 361 m_queryLength = -1; 362 m_matchesPerPage = 10; 363 m_displayPages = 10; 364 m_isIgnoreQuery = false; 365 366 m_minDateCreated = Long.MIN_VALUE; 367 m_maxDateCreated = Long.MAX_VALUE; 368 m_minDateLastModified = Long.MIN_VALUE; 369 m_maxDateLastModified = Long.MAX_VALUE; 370 } 371 372 /** 373 * Adds an individual query for a search field.<p> 374 * 375 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setFields(List)} 376 * will be ignored and only the individual field search settings will be used.<p> 377 * 378 * @param query the query to add 379 * 380 * @since 7.5.1 381 */ 382 public void addFieldQuery(CmsSearchFieldQuery query) { 383 384 if (m_fieldQueries == null) { 385 m_fieldQueries = new ArrayList<CmsSearchFieldQuery>(); 386 m_fields = new ArrayList<String>(); 387 } 388 m_fieldQueries.add(query); 389 // add the used field used in the fields query to the list of fields used in the search 390 if (!m_fields.contains(query.getFieldName())) { 391 m_fields.add(query.getFieldName()); 392 } 393 } 394 395 /** 396 * Adds an individual query for a search field.<p> 397 * 398 * If this is used, any setting made with {@link #setQuery(String)} and {@link #setFields(List)} 399 * will be ignored and only the individual field search settings will be used.<p> 400 * 401 * @param fieldName the field name 402 * @param searchQuery the search query 403 * @param occur the occur parameter for the query in the field 404 * 405 * @since 7.5.1 406 */ 407 public void addFieldQuery(String fieldName, String searchQuery, Occur occur) { 408 409 CmsSearchFieldQuery newQuery = new CmsSearchFieldQuery(fieldName, searchQuery, occur); 410 addFieldQuery(newQuery); 411 } 412 413 /** 414 * Returns whether category counts are calculated for search results or not. <p> 415 * 416 * @return a boolean that tells whether category counts are calculated for search results or not 417 */ 418 public boolean getCalculateCategories() { 419 420 return m_calculateCategories; 421 } 422 423 /** 424 * Returns the list of categories to limit the search to.<p> 425 * 426 * @return the list of categories to limit the search to 427 */ 428 public List<String> getCategories() { 429 430 return m_categories; 431 } 432 433 /** 434 * Returns the maximum number of pages which should be shown.<p> 435 * 436 * @return the maximum number of pages which should be shown 437 */ 438 public int getDisplayPages() { 439 440 return m_displayPages; 441 } 442 443 /** 444 * Returns the list of individual field queries.<p> 445 * 446 * @return the list of individual field queries 447 * 448 * @since 7.5.1 449 */ 450 public List<CmsSearchFieldQuery> getFieldQueries() { 451 452 return m_fieldQueries; 453 } 454 455 /** 456 * Returns the list of search index field names (Strings) to search in.<p> 457 * 458 * @return the list of search index field names (Strings) to search in 459 */ 460 public List<String> getFields() { 461 462 return m_fields; 463 } 464 465 /** 466 * Get the name of the index for the search.<p> 467 * 468 * @return the name of the index for the search 469 */ 470 public String getIndex() { 471 472 return m_index.getName(); 473 } 474 475 /** 476 * Gets the number of matches displayed on each page.<p> 477 * 478 * @return matches per result page 479 */ 480 public int getMatchesPerPage() { 481 482 return m_matchesPerPage; 483 } 484 485 /** 486 * Returns the maximum creation date a resource must have to be included in the search result.<p> 487 * 488 * @return the maximum creation date a resource must have to be included in the search result 489 */ 490 public long getMaxDateCreated() { 491 492 return m_maxDateCreated; 493 } 494 495 /** 496 * Returns the maximum last modification date a resource must have to be included in the search result.<p> 497 * 498 * @return the maximum last modification date a resource must have to be included in the search result 499 */ 500 public long getMaxDateLastModified() { 501 502 return m_maxDateLastModified; 503 } 504 505 /** 506 * Returns the minimum creation date a resource must have to be included in the search result.<p> 507 * 508 * @return the minimum creation date a resource must have to be included in the search result 509 */ 510 public long getMinDateCreated() { 511 512 return m_minDateCreated; 513 } 514 515 /** 516 * Returns the minimum last modification date a resource must have to be included in the search result.<p> 517 * 518 * @return the minimum last modification date a resource must have to be included in the search result 519 */ 520 public long getMinDateLastModified() { 521 522 return m_minDateLastModified; 523 } 524 525 /** 526 * Returns the parsed query.<p> 527 * 528 * The parsed query is automatically set by the OpenCms search index when a query is created 529 * with either {@link #setQuery(String)} or {@link #addFieldQuery(CmsSearchFieldQuery)}. 530 * The Lucene query build from the parameters is stored here and can be later used 531 * for paging through the results.<p> 532 * 533 * Please note that this returns only to the query part, not the filter part of the search.<p> 534 * 535 * @return the parsed query 536 */ 537 public String getParsedQuery() { 538 539 return m_parsedQuery; 540 } 541 542 /** 543 * Returns the search query to use.<p> 544 * 545 * @return the search query to use 546 */ 547 public String getQuery() { 548 549 return m_query; 550 } 551 552 /** 553 * Gets the minimum search query length.<p> 554 * 555 * @return the minimum search query length 556 */ 557 public int getQueryLength() { 558 559 return m_queryLength; 560 } 561 562 /** 563 * Returns the list of resource types to limit the search to.<p> 564 * 565 * @return the list of resource types to limit the search to 566 * 567 * @since 7.5.1 568 */ 569 public List<String> getResourceTypes() { 570 571 return m_resourceTypes; 572 } 573 574 /** 575 * Returns the list of strings of search roots to use.<p> 576 * 577 * Only resource that are sub-resource of one of the search roots are included in the search result.<p> 578 * 579 * @return the list of strings of search roots to use 580 */ 581 public List<String> getRoots() { 582 583 return m_roots; 584 } 585 586 /** 587 * Returns the list of categories to limit the search to.<p> 588 * 589 * @return the list of categories to limit the search to 590 */ 591 public String getSearchCategories() { 592 593 return toSeparatedString(getCategories(), ','); 594 } 595 596 /** 597 * Returns the search index to search in or null if not set before 598 * (<code>{@link #setSearchIndex(CmsSearchIndex)}</code>). <p> 599 * 600 * @return the search index to search in or null if not set before (<code>{@link #setSearchIndex(CmsSearchIndex)}</code>) 601 */ 602 public CmsSearchIndex getSearchIndex() { 603 604 return m_index; 605 } 606 607 /** 608 * Returns the search page to display.<p> 609 * 610 * @return the search page to display 611 */ 612 public int getSearchPage() { 613 614 return m_page; 615 } 616 617 /** 618 * Returns the comma separated lists of root folder names to restrict search to.<p> 619 * 620 * This method is a "sibling" to method <code>{@link #getRoots()}</code> but with 621 * the support of being usable with widget technology. <p> 622 * 623 * @return the comma separated lists of field names to search in 624 * 625 * @see #setSortName(String) 626 */ 627 public String getSearchRoots() { 628 629 return toSeparatedString(m_roots, ','); 630 } 631 632 /** 633 * Returns the instance that defines the sort order for the results. 634 * 635 * @return the instance that defines the sort order for the results 636 */ 637 public Sort getSort() { 638 639 return m_sort; 640 } 641 642 /** 643 * Returns the name of the sort option being used.<p> 644 * @return the name of the sort option being used 645 * 646 * @see #SORT_NAMES 647 * @see #setSortName(String) 648 */ 649 public String getSortName() { 650 651 if (m_sort == SORT_DATE_CREATED) { 652 return SORT_NAMES[1]; 653 } 654 if (m_sort == SORT_DATE_LASTMODIFIED) { 655 return SORT_NAMES[2]; 656 } 657 if (m_sort == SORT_TITLE) { 658 return SORT_NAMES[3]; 659 } 660 return SORT_NAMES[0]; 661 } 662 663 /** 664 * Returns <code>true</code> if the category count is calculated for all search results.<p> 665 * 666 * @return <code>true</code> if the category count is calculated for all search results 667 */ 668 public boolean isCalculateCategories() { 669 670 return m_calculateCategories; 671 } 672 673 /** 674 * Returns <code>true</code> if fields configured for the excerpt should be used for generating the excerpt only 675 * if they have been actually searched in.<p> 676 * 677 * The default setting is <code>false</code>, which means all text fields configured for the excerpt will 678 * be used to generate the excerpt, regardless if they have been searched in or not.<p> 679 * 680 * Please note: A field will only be included in the excerpt if it has been configured as <code>excerpt="true"</code> 681 * in <code>opencms-search.xml</code>. This method controls if so configured fields are used depending on the 682 * fields searched, see {@link #setFields(List)}.<p> 683 * 684 * @return <code>true</code> if fields configured for the excerpt should be used for generating the excerpt only 685 * if they have been actually searched in 686 */ 687 public boolean isExcerptOnlySearchedFields() { 688 689 return m_excerptOnlySearchedFields; 690 } 691 692 /** 693 * Returns <code>true</code> if the query part should be ignored so that only filters are used for searching.<p> 694 * 695 * @return <code>true</code> if the query part should be ignored so that only filters are used for searching 696 * 697 * @since 8.0.0 698 */ 699 public boolean isIgnoreQuery() { 700 701 return m_isIgnoreQuery; 702 } 703 704 /** 705 * Creates a merged parameter set from this parameters, restricted by the given other parameters.<p> 706 * 707 * This is mainly intended for "search in search result" functions.<p> 708 * 709 * The restricted query is build of the queries of both parameters, appended with AND.<p> 710 * 711 * The lists in the restriction for <code>{@link #getFields()}</code>, <code>{@link #getRoots()}</code> and 712 * <code>{@link #getCategories()}</code> are <b>intersected</b> with the lists of this search parameters. Only 713 * elements contained in both lists are included for the created search parameters. 714 * If a list in either the restriction or in this search parameters is <code>null</code>, 715 * the list from the other search parameters is used directly.<p> 716 * 717 * The values for 718 * <code>{@link #isCalculateCategories()}</code> 719 * and <code>{@link #getSort()}</code> of this parameters are used for the restricted parameters.<p> 720 * 721 * @param restriction the parameters to restrict this parameters with 722 * @return the restricted parameters 723 */ 724 public CmsSearchParameters restrict(CmsSearchParameters restriction) { 725 726 // append queries 727 StringBuffer query = new StringBuffer(256); 728 if (getQuery() != null) { 729 // don't blow up unnecessary closures (if CmsSearch is reused and restricted several times) 730 boolean closure = !getQuery().startsWith("+("); 731 if (closure) { 732 query.append("+("); 733 } 734 query.append(getQuery()); 735 if (closure) { 736 query.append(")"); 737 } 738 } 739 if (restriction.getQuery() != null) { 740 // don't let Lucene max terms be exceeded in case someone reuses a CmsSearch and continuously restricts 741 // query with the same restrictions... 742 if (query.indexOf(restriction.getQuery()) < 0) { 743 query.append(" +("); 744 query.append(restriction.getQuery()); 745 query.append(")"); 746 } 747 } 748 749 // restrict fields 750 List<String> fields = null; 751 if ((m_fields != null) && (m_fields.size() > 0)) { 752 if ((restriction.getFields() != null) && (restriction.getFields().size() > 0)) { 753 fields = ListUtils.intersection(m_fields, restriction.getFields()); 754 } else { 755 fields = m_fields; 756 } 757 } else { 758 fields = restriction.getFields(); 759 } 760 761 // restrict roots 762 List<String> roots = null; 763 if ((m_roots != null) && (m_roots.size() > 0)) { 764 if ((restriction.getRoots() != null) && (restriction.getRoots().size() > 0)) { 765 roots = ListUtils.intersection(m_roots, restriction.getRoots()); 766 // TODO: This only works if there are equal paths in both parameter sets - for two distinct sets 767 // all root restrictions are dropped with an empty list. 768 } else { 769 roots = m_roots; 770 } 771 } else { 772 roots = restriction.getRoots(); 773 } 774 775 // restrict categories 776 List<String> categories = null; 777 if ((m_categories != null) && (m_categories.size() > 0)) { 778 if ((restriction.getCategories() != null) && (restriction.getCategories().size() > 0)) { 779 categories = ListUtils.intersection(m_categories, restriction.getCategories()); 780 } else { 781 categories = m_categories; 782 } 783 } else { 784 categories = restriction.getCategories(); 785 } 786 787 // restrict resource types 788 List<String> resourceTypes = null; 789 if ((m_resourceTypes != null) && (m_resourceTypes.size() > 0)) { 790 if ((restriction.getResourceTypes() != null) && (restriction.getResourceTypes().size() > 0)) { 791 resourceTypes = ListUtils.intersection(m_resourceTypes, restriction.getResourceTypes()); 792 } else { 793 resourceTypes = m_resourceTypes; 794 } 795 } else { 796 resourceTypes = restriction.getResourceTypes(); 797 } 798 799 // create the new search parameters 800 CmsSearchParameters result = new CmsSearchParameters( 801 query.toString(), 802 fields, 803 roots, 804 categories, 805 resourceTypes, 806 m_calculateCategories, 807 m_sort); 808 result.setIndex(getIndex()); 809 return result; 810 } 811 812 /** 813 * Set whether category counts shall be calculated for the corresponding search results or not.<p> 814 * 815 * @param flag true if category counts shall be calculated for the corresponding search results or false if not 816 */ 817 public void setCalculateCategories(boolean flag) { 818 819 m_calculateCategories = flag; 820 } 821 822 /** 823 * Set the list of categories (strings) to this parameters. <p> 824 * 825 * @param categories the list of categories (strings) of this parameters 826 */ 827 public void setCategories(List<String> categories) { 828 829 m_categories = categories; 830 } 831 832 /** 833 * Sets the maximum number of pages which should be shown.<p> 834 * 835 * Enter an odd value to achieve a nice, "symmetric" output.<p> 836 * 837 * @param value the maximum number of pages which should be shown 838 */ 839 public void setDisplayPages(int value) { 840 841 m_displayPages = value; 842 } 843 844 /** 845 * Controls if the excerpt from a field is generated only for searched fields, or for all fields (the default).<p> 846 * 847 * @param excerptOnlySearchedFields if <code>true</code>, the excerpt is generated only from the fields actually searched in 848 * 849 * @see #isExcerptOnlySearchedFields() 850 */ 851 public void setExcerptOnlySearchedFields(boolean excerptOnlySearchedFields) { 852 853 m_excerptOnlySearchedFields = excerptOnlySearchedFields; 854 } 855 856 /** 857 * Sets the list of strings of names of fields to search in. <p> 858 * 859 * @param fields the list of strings of names of fields to search in to set 860 */ 861 public void setFields(List<String> fields) { 862 863 m_fields = fields; 864 } 865 866 /** 867 * Sets the flag to indicate if the query part should be ignored so that only filters are used for searching.<p> 868 * 869 * @param isIgnoreQuery the flag to indicate if the query part should be ignored 870 * 871 * @since 8.0.0 872 */ 873 public void setIgnoreQuery(boolean isIgnoreQuery) { 874 875 m_isIgnoreQuery = isIgnoreQuery; 876 } 877 878 /** 879 * Set the name of the index to search.<p> 880 * 881 * @param indexName the name of the index 882 */ 883 public void setIndex(String indexName) { 884 885 CmsSearchIndex index; 886 if (CmsStringUtil.isNotEmpty(indexName)) { 887 try { 888 I_CmsSearchIndex idx = OpenCms.getSearchManager().getIndex(indexName); 889 index = idx instanceof CmsSearchIndex ? (CmsSearchIndex)idx : null; 890 if (index == null) { 891 throw new CmsException(Messages.get().container(Messages.ERR_INDEX_NOT_FOUND_1, indexName)); 892 } 893 setSearchIndex(index); 894 } catch (Exception exc) { 895 if (LOG.isErrorEnabled()) { 896 LOG.error(Messages.get().getBundle().key(Messages.LOG_INDEX_ACCESS_FAILED_1, indexName), exc); 897 } 898 } 899 } 900 } 901 902 /** 903 * Sets the number of matches per page.<p> 904 * 905 * @param matches the number of matches per page 906 */ 907 public void setMatchesPerPage(int matches) { 908 909 m_matchesPerPage = matches; 910 } 911 912 /** 913 * Sets the maximum creation date a resource must have to be included in the search result.<p> 914 * 915 * @param maxDateCreated the maximum creation date to set 916 */ 917 public void setMaxDateCreated(long maxDateCreated) { 918 919 m_maxDateCreated = maxDateCreated; 920 } 921 922 /** 923 * Sets the maximum last modification date a resource must have to be included in the search result.<p> 924 * 925 * @param maxDateLastModified the maximum last modification date to set 926 */ 927 public void setMaxDateLastModified(long maxDateLastModified) { 928 929 m_maxDateLastModified = maxDateLastModified; 930 } 931 932 /** 933 * Sets the minimum creation date a resource must have to be included in the search result.<p> 934 * 935 * @param minDateCreated the minimum creation date to set 936 */ 937 public void setMinDateCreated(long minDateCreated) { 938 939 m_minDateCreated = minDateCreated; 940 } 941 942 /** 943 * Sets the minimum last modification date a resource must have to be included in the search result.<p> 944 * 945 * @param minDateLastModified he minimum last modification date to set 946 */ 947 public void setMinDateLastModified(long minDateLastModified) { 948 949 m_minDateLastModified = minDateLastModified; 950 } 951 952 /** 953 * Sets the parsed query.<p> 954 * 955 * The parsed query is automatically set by the OpenCms search index when a query is created 956 * with either {@link #setQuery(String)} or {@link #addFieldQuery(CmsSearchFieldQuery)}. 957 * The Lucene query build from the parameters is stored here and can be later used 958 * for paging through the results.<p> 959 * 960 * Please note that this applies only to the query part, not the filter part of the search.<p> 961 * 962 * @param parsedQuery the parsed query to set 963 */ 964 public void setParsedQuery(String parsedQuery) { 965 966 m_parsedQuery = parsedQuery; 967 } 968 969 /** 970 * Sets the query to search for. <p> 971 * 972 * The decoding here is tailored for query strings that are 973 * additionally manually UTF-8 encoded at client side (javascript) to get around an 974 * issue with special chars in applications that use non- UTF-8 encoding 975 * (e.g. ISO-8859-1) OpenCms applications. It is not recommended to use this with 976 * front ends that don't encode manually as characters like sole "%" (without number suffix) 977 * will cause an Exception.<p> 978 * 979 * @param query the query to search for to set 980 */ 981 public void setQuery(String query) { 982 983 // for use with widgets the exception is thrown here to enforce the error message next to the widget 984 if (query.trim().length() < getQueryLength()) { 985 throw new CmsIllegalArgumentException( 986 Messages.get().container(Messages.ERR_QUERY_TOO_SHORT_1, Integer.valueOf(getQueryLength()))); 987 } 988 m_query = query; 989 } 990 991 /** 992 * Sets the minimum length of the search query.<p> 993 * 994 * @param length the minimum search query length 995 */ 996 public void setQueryLength(int length) { 997 998 m_queryLength = length; 999 } 1000 1001 /** 1002 * Set the list of resource types (strings) to limit the search to. <p> 1003 * 1004 * @param resourceTypes the list of resource types (strings) to limit the search to 1005 * 1006 * @since 7.5.1 1007 */ 1008 public void setResourceTypes(List<String> resourceTypes) { 1009 1010 m_resourceTypes = resourceTypes; 1011 } 1012 1013 /** 1014 * Sets the list of strings of roots to search under for the search.<p> 1015 * 1016 * @param roots the list of strings of roots to search under for the search to set 1017 */ 1018 public void setRoots(List<String> roots) { 1019 1020 m_roots = roots; 1021 } 1022 1023 /** 1024 * Set the comma separated search root names to restrict search to.<p> 1025 * 1026 * @param categories the comma separated category names to restrict search to 1027 */ 1028 public void setSearchCategories(String categories) { 1029 1030 setCategories(CmsStringUtil.splitAsList(categories, ',')); 1031 } 1032 1033 /** 1034 * Sets the search index to use for the search. <p> 1035 * 1036 * @param index the search index to use for the search to set. 1037 * 1038 * @throws CmsIllegalArgumentException if null is given as argument 1039 */ 1040 public void setSearchIndex(CmsSearchIndex index) throws CmsIllegalArgumentException { 1041 1042 if (index == null) { 1043 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_INDEX_NULL_0)); 1044 } 1045 m_index = index; 1046 } 1047 1048 /** 1049 * Set the search page to display. <p> 1050 * 1051 * @param page the search page to display 1052 */ 1053 public void setSearchPage(int page) { 1054 1055 m_page = page; 1056 } 1057 1058 /** 1059 * Set the comma separated search root names to restrict search to.<p> 1060 * 1061 * @param rootNameList the comma separated search root names to restrict search to 1062 */ 1063 public void setSearchRoots(String rootNameList) { 1064 1065 m_roots = CmsStringUtil.splitAsList(rootNameList, ','); 1066 } 1067 1068 /** 1069 * Set the instance that defines the sort order for search results. 1070 * 1071 * @param sortOrder the instance that defines the sort order for search results to set 1072 */ 1073 public void setSort(Sort sortOrder) { 1074 1075 m_sort = sortOrder; 1076 } 1077 1078 /** 1079 * Sets the internal member of type <code>{@link Sort}</code> according to 1080 * the given sort name. <p> 1081 * 1082 * For a list of valid sort names, please see <code>{@link #SORT_NAMES}</code>.<p> 1083 * 1084 * @param sortName the name of the sort to use 1085 * 1086 * @see #SORT_NAMES 1087 */ 1088 public void setSortName(String sortName) { 1089 1090 if (sortName.equals(SORT_NAMES[1])) { 1091 m_sort = SORT_DATE_CREATED; 1092 } else if (sortName.equals(SORT_NAMES[2])) { 1093 m_sort = SORT_DATE_LASTMODIFIED; 1094 } else if (sortName.equals(SORT_NAMES[3])) { 1095 m_sort = SORT_TITLE; 1096 } else { 1097 m_sort = SORT_DEFAULT; 1098 } 1099 } 1100 1101 /** 1102 * Creates a query String build from this search parameters for HTML links.<p> 1103 * 1104 * @return a query String build from this search parameters for HTML links 1105 */ 1106 public String toQueryString() { 1107 1108 StringBuffer result = new StringBuffer(128); 1109 result.append("?action=search"); 1110 if (getParsedQuery() != null) { 1111 result.append("&parsedQuery="); 1112 result.append(CmsEncoder.encodeParameter(getParsedQuery())); 1113 } else { 1114 result.append("&query="); 1115 result.append(CmsEncoder.encodeParameter(getQuery())); 1116 } 1117 1118 result.append("&matchesPerPage="); 1119 result.append(getMatchesPerPage()); 1120 result.append("&displayPages="); 1121 result.append(getDisplayPages()); 1122 result.append("&index="); 1123 result.append(CmsEncoder.encodeParameter(getIndex())); 1124 1125 Sort sort = getSort(); 1126 if (sort != CmsSearchParameters.SORT_DEFAULT) { 1127 result.append("&sort="); 1128 if (sort == CmsSearchParameters.SORT_TITLE) { 1129 result.append("title"); 1130 } else if (sort == CmsSearchParameters.SORT_DATE_CREATED) { 1131 result.append("date-created"); 1132 } else if (sort == CmsSearchParameters.SORT_DATE_LASTMODIFIED) { 1133 result.append("date-lastmodified"); 1134 } 1135 } 1136 1137 if ((getCategories() != null) && (getCategories().size() > 0)) { 1138 result.append("&category="); 1139 Iterator<String> it = getCategories().iterator(); 1140 while (it.hasNext()) { 1141 result.append(it.next()); 1142 if (it.hasNext()) { 1143 result.append(','); 1144 } 1145 } 1146 } 1147 1148 if (getMinDateCreated() > Long.MIN_VALUE) { 1149 result.append("&minDateCreated="); 1150 result.append(getMinDateCreated()); 1151 } 1152 if (getMinDateLastModified() > Long.MIN_VALUE) { 1153 result.append("&minDateLastModified="); 1154 result.append(getMinDateLastModified()); 1155 } 1156 if (getMaxDateCreated() < Long.MAX_VALUE) { 1157 result.append("&maxDateCreated="); 1158 result.append(getMaxDateCreated()); 1159 } 1160 if (getMaxDateLastModified() < Long.MAX_VALUE) { 1161 result.append("&maxDateLastModified="); 1162 result.append(getMaxDateLastModified()); 1163 } 1164 1165 if ((getRoots() != null) && (getRoots().size() > 0)) { 1166 result.append("&searchRoots="); 1167 Iterator<String> it = getRoots().iterator(); 1168 while (it.hasNext()) { 1169 result.append(CmsEncoder.encode(it.next())); 1170 if (it.hasNext()) { 1171 result.append(','); 1172 } 1173 } 1174 } 1175 1176 if (isExcerptOnlySearchedFields()) { 1177 result.append("&excerptOnlySearchedFields=true"); 1178 } 1179 1180 return result.toString(); 1181 } 1182 1183 /** 1184 * @see java.lang.Object#toString() 1185 */ 1186 @Override 1187 public String toString() { 1188 1189 StringBuffer result = new StringBuffer(); 1190 result.append("query:["); 1191 result.append(m_query); 1192 result.append("] "); 1193 if ((m_fields != null) && (m_fields.size() > 0)) { 1194 result.append("fields:["); 1195 for (int i = 0; i < m_fields.size(); i++) { 1196 result.append(m_fields.get(i)); 1197 if ((i + 1) < m_fields.size()) { 1198 result.append(", "); 1199 } 1200 } 1201 result.append("] "); 1202 } 1203 if ((m_roots != null) && (m_roots.size() > 0)) { 1204 result.append("roots:["); 1205 for (int i = 0; i < m_roots.size(); i++) { 1206 result.append(m_roots.get(i)); 1207 if ((i + 1) < m_roots.size()) { 1208 result.append(", "); 1209 } 1210 } 1211 result.append("] "); 1212 } 1213 if ((m_categories != null) && (m_categories.size() > 0)) { 1214 result.append("categories:["); 1215 for (int i = 0; i < m_categories.size(); i++) { 1216 result.append(m_categories.get(i)); 1217 if ((i + 1) < m_categories.size()) { 1218 result.append(", "); 1219 } 1220 } 1221 result.append("] "); 1222 } 1223 if ((m_resourceTypes != null) && (m_resourceTypes.size() > 0)) { 1224 result.append("resourceTypes:["); 1225 for (int i = 0; i < m_resourceTypes.size(); i++) { 1226 result.append(m_resourceTypes.get(i)); 1227 if ((i + 1) < m_resourceTypes.size()) { 1228 result.append(", "); 1229 } 1230 } 1231 result.append("] "); 1232 } 1233 if (m_calculateCategories) { 1234 result.append("calculate-categories "); 1235 } 1236 if (m_excerptOnlySearchedFields) { 1237 result.append("excerpt-searched-fields-only "); 1238 } 1239 result.append("sort:["); 1240 if (m_sort == CmsSearchParameters.SORT_DEFAULT) { 1241 result.append("default"); 1242 } else if (m_sort == CmsSearchParameters.SORT_TITLE) { 1243 result.append("title"); 1244 } else if (m_sort == CmsSearchParameters.SORT_DATE_CREATED) { 1245 result.append("date-created"); 1246 } else if (m_sort == CmsSearchParameters.SORT_DATE_LASTMODIFIED) { 1247 result.append("date-lastmodified"); 1248 } else { 1249 result.append("unknown"); 1250 } 1251 result.append("]"); 1252 1253 return result.toString(); 1254 } 1255 1256 /** 1257 * Concatenates the elements of the string list separated by the given separator character.<p> 1258 * 1259 * @param stringList the list 1260 * @param separator the separator 1261 * 1262 * @return the concatenated string 1263 */ 1264 private String toSeparatedString(List<String> stringList, char separator) { 1265 1266 StringBuffer result = new StringBuffer(); 1267 Iterator<String> it = stringList.iterator(); 1268 while (it.hasNext()) { 1269 result.append(it.next()); 1270 if (it.hasNext()) { 1271 result.append(separator); 1272 } 1273 } 1274 return result.toString(); 1275 } 1276}