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, 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.galleries;
029
030import org.opencms.ade.configuration.CmsFunctionAvailability;
031import org.opencms.ade.galleries.shared.CmsGallerySearchScope;
032import org.opencms.file.CmsObject;
033import org.opencms.file.CmsPropertyDefinition;
034import org.opencms.file.CmsResource;
035import org.opencms.file.types.CmsResourceTypeFunctionConfig;
036import org.opencms.i18n.CmsLocaleManager;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.search.A_CmsSearchIndex;
040import org.opencms.search.CmsSearchUtil;
041import org.opencms.search.fields.CmsSearchField;
042import org.opencms.search.fields.CmsSearchFieldConfiguration;
043import org.opencms.search.solr.CmsSolrQuery;
044import org.opencms.util.CmsPair;
045import org.opencms.util.CmsUUID;
046import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler;
047
048import java.util.ArrayList;
049import java.util.Arrays;
050import java.util.Collection;
051import java.util.Collections;
052import java.util.List;
053import java.util.Locale;
054import java.util.Set;
055import java.util.stream.Collectors;
056
057import org.apache.commons.logging.Log;
058import org.apache.solr.client.solrj.SolrQuery.ORDER;
059
060import com.google.common.base.Joiner;
061
062/**
063 * Parameters used for the gallery search index.<p>
064 *
065 * @since 8.0.0
066 */
067public class CmsGallerySearchParameters {
068
069    /** Sort parameter constants. */
070    public enum CmsGallerySortParam {
071
072        /** Sort by date created ascending. */
073        dateCreated_asc,
074
075        /** Sort by date created descending. */
076        dateCreated_desc,
077
078        /** Sort date expired ascending. */
079        dateExpired_asc,
080
081        /** Sort date expired descending. */
082        dateExpired_desc,
083
084        /** Sort by date modified ascending. */
085        dateLastModified_asc,
086
087        /** Sort by date modified descending. */
088        dateLastModified_desc,
089
090        /** Sort date released ascending. */
091        dateReleased_asc,
092
093        /** Sort date released descending. */
094        dateReleased_desc,
095
096        /** Sort by length ascending. */
097        length_asc,
098
099        /** Sort by length descending. */
100        length_desc,
101
102        /** Sort by VFS root path ascending. */
103        path_asc,
104
105        /** Sort by VFS root path descending. */
106        path_desc,
107
108        /** Sort by score descending. */
109        score,
110
111        /** Sort state ascending. */
112        state_asc,
113
114        /** Sort state descending. */
115        state_desc,
116
117        /** Sort by title ascending. */
118        title_asc,
119
120        /** Sort by title ascending. */
121        title_desc,
122
123        /** Sort by type ascending. */
124        type_asc,
125
126        /** Sort by type descending. */
127        type_desc,
128
129        /** Sort created by ascending. */
130        userCreated_asc,
131
132        /** Sort created by descending. */
133        userCreated_desc,
134
135        /** Sort modified by ascending. */
136        userLastModified_asc,
137
138        /** Sort modified by descending. */
139        userLastModified_desc;
140
141        /** The default sort parameter. */
142        public static final CmsGallerySortParam DEFAULT = title_asc;
143    }
144
145    /**
146     * Helper class to store a time range.<p>
147     */
148    class CmsGallerySearchTimeRange {
149
150        /** The end time of the time range. */
151        long m_endTime;
152
153        /** The start time of the time range. */
154        long m_startTime;
155
156        /**
157         * Default constructor.<p>
158         *
159         * This will create an object where the start date is equal to
160         * {@link Long#MIN_VALUE} and the end date is equal to {@link Long#MAX_VALUE}.<p>
161         */
162        public CmsGallerySearchTimeRange() {
163
164            m_startTime = Long.MIN_VALUE;
165            m_endTime = Long.MAX_VALUE;
166        }
167
168        /**
169         * Constructor with start and end time.<p>
170         *
171         * @param startTime the start time of the time range
172         * @param endTime the end time of the time range
173         */
174        public CmsGallerySearchTimeRange(long startTime, long endTime) {
175
176            m_startTime = startTime;
177            m_endTime = endTime;
178        }
179
180        /**
181         * Returns the end time of the time range.<p>
182         *
183         * @return the end time of the time range
184         */
185        public long getEndTime() {
186
187            return m_endTime;
188        }
189
190        /**
191         * Returns the start time of the time range.<p>
192         *
193         * @return the start time of the time range
194         */
195        public long getStartTime() {
196
197            return m_startTime;
198        }
199    }
200
201    /** Logge instance for this class. */
202    private static final Log LOG = CmsLog.getLog(CmsGallerySearchParameters.class);
203
204    /** The categories to search in. */
205    private List<String> m_categories;
206
207    /** The container types to search in. */
208    private List<String> m_containerTypes;
209
210    /** The time range for the date of resource creation to consider in the search. */
211    private CmsGallerySearchTimeRange m_dateCreatedTimeRange;
212
213    /** The time range for the date of resource last modification to consider in the search. */
214    private CmsGallerySearchTimeRange m_dateLastModifiedTimeRange;
215
216    /** The set of functions to be excluded from the search result (may be null). */
217    private Set<CmsUUID> m_excludedFunctions;
218
219    /** The list of folders to search in. */
220    private List<String> m_folders;
221
222    /** Enlists all VFS folders to perform a search in. */
223    private List<String> m_foldersToSearchIn;
224
225    /** If true, empty search result should be returned regardless of other settings. */
226    private boolean m_forceEmptyResult;
227
228    /** Function availability. */
229    private CmsFunctionAvailability m_functionAvailability;
230
231    /** The galleries to search in. */
232    private List<String> m_galleries;
233
234    /** Indicates the search exclude property should be ignored. */
235    private boolean m_ignoreSearchExclude;
236
237    /** Set of functions to include (whitelist). */
238    private Set<CmsUUID> m_includedFunctions;
239
240    /** Indicates if expired and unreleased resources should be included in the search. */
241    private boolean m_includeExpired;
242
243    /** The locale for the search. */
244    private String m_locale;
245
246    /** The number of search results per page. */
247    private int m_matchesPerPage;
248
249    /** The sitemap reference path. */
250    private String m_referencePath;
251
252    /** The resource types to search for. */
253    private List<String> m_resourceTypes;
254
255    /** The requested page of the result. */
256    private int m_resultPage;
257
258    /** The gallery search scope. */
259    private CmsGallerySearchScope m_scope;
260
261    /** The sort order for the search result. */
262    private CmsGallerySortParam m_sortOrder;
263
264    /** The template compatibility. */
265    private String m_templateCompatibility;
266
267    /** Search words to search for. */
268    private String m_words;
269
270    /**
271     * Default constructor.<p>
272     */
273    public CmsGallerySearchParameters() {
274
275        m_resultPage = 1;
276        m_matchesPerPage = 10;
277    }
278
279    /**
280     * Returns the categories that have been included in the search.<p>
281     *
282     * If no categories have been set, then <code>null</code> is returned.<p>
283     *
284     * @return the categories that have been included in the search
285     */
286    public List<String> getCategories() {
287
288        return m_categories;
289    }
290
291    /**
292     * Returns the container types that have been included in the search.<p>
293     *
294     * @return the container types that have been included in the search
295     */
296    public List<String> getContainerTypes() {
297
298        return m_containerTypes;
299    }
300
301    /**
302     * Returns the time range for the date of creation that has been used for the search result.<p>
303     *
304     * In case this time range has not been set, this will return an object
305     * where the start date is equal to {@link Long#MIN_VALUE} and the end date is equal to {@link Long#MAX_VALUE}.<p>
306     *
307     * @return the time range for the date of creation that has been used for the search result
308     */
309    public CmsGallerySearchTimeRange getDateCreatedRange() {
310
311        if (m_dateCreatedTimeRange == null) {
312            m_dateCreatedTimeRange = new CmsGallerySearchTimeRange();
313        }
314        return m_dateCreatedTimeRange;
315    }
316
317    /**
318     * Returns the time range for the dadelete examplete of last modification that has been used for the search result.<p>
319     *
320     * In case this time range has not been set, this will return an object
321     * where the start date is equal to {@link Long#MIN_VALUE} and the end date is equal to {@link Long#MAX_VALUE}.<p>
322     *
323     * @return the time range for the date of last modification that has been used for the search result
324     */
325    public CmsGallerySearchTimeRange getDateLastModifiedRange() {
326
327        if (m_dateLastModifiedTimeRange == null) {
328            m_dateLastModifiedTimeRange = new CmsGallerySearchTimeRange();
329        }
330        return m_dateLastModifiedTimeRange;
331    }
332
333    /**
334     * Gets the set of structure IDs of functions to exclude from the search result.
335     *
336     * @return the set of structure IDs to exclude
337     */
338    public Set<CmsUUID> getExcludedFunctions() {
339
340        return m_excludedFunctions;
341    }
342
343    /**
344     * Returns the list of folders to search in.<p>
345     *
346     * @return a list of paths of VFS folders
347     */
348    public List<String> getFolders() {
349
350        return m_folders;
351    }
352
353    /**
354     * Returns the galleries that have been included in the search.<p>
355     *
356     * If no galleries have been set, then <code>null</code> is returned.<p>
357     *
358     * @return the galleries that have been included in the search
359     */
360    public List<String> getGalleries() {
361
362        return m_galleries;
363    }
364
365    /**
366     * Gets the set of ids of functions to include.
367     *
368     * <p>Note: If the id of a function is returned in the ID set returned by thsi method,
369     * the function may still be excluded from search results based on other parameters.
370     *
371     * @return the included functions
372     */
373    public Set<CmsUUID> getIncludedFunctions() {
374
375        return m_includedFunctions;
376    }
377
378    /**
379     * Returns the locale that has been used for the search.<p>
380     *
381     * If no locale has been set, then <code>null</code> is returned.<p>
382     *
383     * @return the locale that has been used for the search
384     */
385    public String getLocale() {
386
387        if (m_locale == null) {
388            m_locale = CmsLocaleManager.getDefaultLocale().toString();
389        }
390        return m_locale;
391    }
392
393    /**
394     * Returns the maximum number of matches per result page.<p>
395     *
396     * @return the the maximum number of matches per result page
397     *
398     * @see #getMatchesPerPage()
399     * @see #setResultPage(int)
400     */
401    public int getMatchesPerPage() {
402
403        return m_matchesPerPage;
404    }
405
406    /**
407     * Returns a CmsSolrQuery representation of this class.
408     * @param cms the openCms object.
409     * @return CmsSolrQuery representation of this class.
410     */
411    public CmsSolrQuery getQuery(CmsObject cms) {
412
413        final CmsSolrQuery query = new CmsSolrQuery();
414
415        // set categories
416        query.setCategories(m_categories);
417
418        // set container types
419        if (null != m_containerTypes) {
420            query.addFilterQuery(CmsSearchField.FIELD_CONTAINER_TYPES, m_containerTypes, false, false);
421        }
422
423        // Set date created time filter
424        query.addFilterQuery(
425            CmsSearchUtil.getDateCreatedTimeRangeFilterQuery(
426                CmsSearchField.FIELD_DATE_CREATED,
427                getDateCreatedRange().m_startTime,
428                getDateCreatedRange().m_endTime));
429
430        // Set date last modified time filter
431        query.addFilterQuery(
432            CmsSearchUtil.getDateCreatedTimeRangeFilterQuery(
433                CmsSearchField.FIELD_DATE_LASTMODIFIED,
434                getDateLastModifiedRange().m_startTime,
435                getDateLastModifiedRange().m_endTime));
436
437        // set scope / folders to search in
438        m_foldersToSearchIn = new ArrayList<String>();
439        addFoldersToSearchIn(m_folders);
440        addFoldersToSearchIn(m_galleries);
441        setSearchFolders(cms);
442        query.addFilterQuery(
443            CmsSearchField.FIELD_PARENT_FOLDERS,
444            new ArrayList<String>(m_foldersToSearchIn),
445            false,
446            true);
447
448        if (!m_ignoreSearchExclude) {
449            // Reference for the values: CmsGallerySearchIndex.java, field EXCLUDE_PROPERTY_VALUES
450            query.addFilterQuery(
451                "-" + CmsSearchField.FIELD_SEARCH_EXCLUDE,
452                Arrays.asList(
453                    new String[] {
454                        A_CmsSearchIndex.PROPERTY_SEARCH_EXCLUDE_VALUE_ALL,
455                        A_CmsSearchIndex.PROPERTY_SEARCH_EXCLUDE_VALUE_GALLERY}),
456                false,
457                true);
458        }
459
460        // set matches per page
461        query.setRows(new Integer(m_matchesPerPage));
462
463        // set resource types
464        if (null != m_resourceTypes) {
465            List<String> resourceTypes = new ArrayList<>(m_resourceTypes);
466            if (m_resourceTypes.contains(CmsResourceTypeFunctionConfig.TYPE_NAME)
467                && !m_resourceTypes.contains(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION)) {
468                resourceTypes.add(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION);
469            }
470            query.setResourceTypes(resourceTypes);
471        }
472
473        // set result page
474        query.setStart(new Integer((m_resultPage - 1) * m_matchesPerPage));
475
476        // set search locale
477        if (null != m_locale) {
478            Locale l = CmsLocaleManager.getLocale(m_locale);
479            List<Locale> locales = new ArrayList<>(3);
480            locales.add(l);
481            if (!l.getVariant().isEmpty()) {
482                locales.add(new Locale(l.getLanguage(), l.getCountry()));
483            }
484            if (!l.getCountry().isEmpty()) {
485                locales.add(new Locale(l.getLanguage()));
486            }
487            query.setLocales(locales);
488        }
489
490        // set search words
491        if (null != m_words) {
492            query.setQuery(m_words);
493        }
494
495        // set sort order
496        query.setSort(getSort().getFirst(), getSort().getSecond());
497
498        // set result collapsing by id
499        // add sort criteria to possibly speed up performance and prevent sorting by score - not sure if a good solution
500        query.addFilterQuery(
501            "{!collapse field=id sort='"
502                + CmsSearchField.FIELD_INSTANCEDATE
503                + CmsSearchField.FIELD_POSTFIX_DATE
504                + " asc'}");
505
506        query.setFields(CmsGallerySearchResult.getRequiredSolrFields());
507
508        if ((m_functionAvailability != null) && m_functionAvailability.isDefined()) {
509            String notFunction = "(*:* AND -type:("
510                + CmsXmlDynamicFunctionHandler.TYPE_FUNCTION
511                + " OR "
512                + CmsResourceTypeFunctionConfig.TYPE_NAME
513                + "))";
514            Collection<CmsUUID> whitelist = m_functionAvailability.getWhitelist();
515            Collection<CmsUUID> blacklist = new ArrayList<>(m_functionAvailability.getBlacklist());
516            CmsUUID dummyId = CmsUUID.getNullUUID();
517            blacklist.add(dummyId);
518            String idClause;
519            if (whitelist != null) {
520                whitelist = new ArrayList<>(whitelist);
521                whitelist.add(dummyId);
522                String whitelistIdCondition = whitelist.stream().map(id -> id.toString()).collect(
523                    Collectors.joining(" OR "));
524                idClause = "id:(" + whitelistIdCondition + ")";
525            } else {
526                idClause = "*:* AND -id:("
527                    + blacklist.stream().map(id -> id.toString()).collect(Collectors.joining(" OR "))
528                    + ") ";
529            }
530            String functionFilter = "(" + notFunction + " OR (" + idClause + "))";
531            query.addFilterQuery(functionFilter);
532        }
533
534        if ((m_resourceTypes != null) && m_resourceTypes.contains(CmsResourceTypeFunctionConfig.TYPE_NAME)) {
535            if ((m_excludedFunctions != null) && (m_excludedFunctions.size() > 0)) {
536                List<CmsUUID> excludedFunctions = new ArrayList<>(m_excludedFunctions);
537                Collections.sort(excludedFunctions);
538                String orList = Joiner.on(" OR ").join(excludedFunctions);
539                String filter = "*:* AND -id:(" + orList + ")";
540                query.addFilterQuery(filter);
541            }
542            if (m_includedFunctions != null) {
543                List<CmsUUID> includedFunctions = new ArrayList<>(m_includedFunctions);
544                // not sure if order of terms matters for filter query caching in Solr, so normalize order just in case
545                Collections.sort(includedFunctions);
546                List<String> conditions = new ArrayList<>();
547                String notFunction = "(*:* AND -type:("
548                    + CmsXmlDynamicFunctionHandler.TYPE_FUNCTION
549                    + " OR "
550                    + CmsResourceTypeFunctionConfig.TYPE_NAME
551                    + "))";
552                conditions.add(notFunction);
553                for (CmsUUID id : includedFunctions) {
554                    conditions.add("id:" + id);
555                }
556                String includedFunctionsFilter = Joiner.on(" OR ").join(conditions);
557                query.addFilterQuery(includedFunctionsFilter);
558            }
559        }
560
561        if (m_templateCompatibility != null) {
562            if (m_templateCompatibility.matches("^[0-9a-zA-Z_]+$")) {
563                String fieldName = CmsPropertyDefinition.PROPERTY_TEMPLATE_COMPATILIBITY + "_prop";
564                query.addFilterQuery("(*:* NOT " + fieldName + ":*) OR " + fieldName + ":" + m_templateCompatibility);
565            } else {
566                LOG.warn(
567                    "Invalid template compatibility value: "
568                        + m_templateCompatibility
569                        + ". Must only contain digits, letters (a-z) or underscores.");
570            }
571        }
572
573        // include expired/unreleased
574        if (m_includeExpired) {
575            query.removeExpiration();
576        }
577
578        return query;
579    }
580
581    /**
582     * Gets the reference path.<p>
583     *
584     * @return the gallery reference path
585     */
586    public String getReferencePath() {
587
588        return m_referencePath;
589    }
590
591    /**
592     * Returns the names of the resource types that have been included in the search result.<p>
593     *
594     * If no resource types have been set, then <code>null</code> is returned.<p>
595     *
596     * @return the names of the resource types that have been included in the search result
597     */
598    public List<String> getResourceTypes() {
599
600        return m_resourceTypes;
601    }
602
603    /**
604     * Returns the index of the requested result page.<p>
605     *
606     * @return the index of the requested result page
607     *
608     * @see #setResultPage(int)
609     * @see #getMatchesPerPage()
610     * @see #setMatchesPerPage(int)
611     */
612    public int getResultPage() {
613
614        return m_resultPage;
615    }
616
617    /**
618     * The gallery search scope.<p>
619     *
620     * @return the gallery search scope
621     */
622    public CmsGallerySearchScope getScope() {
623
624        if (m_scope == null) {
625            return OpenCms.getWorkplaceManager().getGalleryDefaultScope();
626        }
627        return m_scope;
628    }
629
630    /**
631     * Returns the words (terms) that have been used for the full text search.<p>
632     *
633     * If no search words have been set, then <code>null</code> is returned.<p>
634     *
635     * @return the words (terms) that have been used for the full text search
636     */
637    public String getSearchWords() {
638
639        return m_words;
640    }
641
642    /**
643     * Returns the sort order that has been used in the search.<p>
644     *
645     * If the sort parameter has not been set the default sort order
646     * defined by {@link CmsGallerySortParam#DEFAULT} is used.<p>
647     *
648     * @return the sort order that has been used in the search
649     */
650    public CmsGallerySortParam getSortOrder() {
651
652        if (m_sortOrder == null) {
653
654            m_sortOrder = CmsGallerySortParam.DEFAULT;
655        }
656        return m_sortOrder;
657    }
658
659    /**
660     * Gets the template compatibility.
661     *
662     * <p>If set, matches those resources whose template.compatibility property is either empty or contains the value (possibly together with other values, separated by whitespace).
663     *
664     * @return the template compatibility
665     */
666    public String getTemplateCompatibility() {
667
668        return m_templateCompatibility;
669    }
670
671    /**
672     * If this returns true, an empty search result should be returned, regardless of other settings.
673     *
674     * @return true if an empty search result should be forced
675     */
676    public boolean isForceEmptyResult() {
677
678        return m_forceEmptyResult;
679    }
680
681    /**
682     * Returns the search exclude property ignore flag.<p>
683     *
684     * @return the search exclude property ignore flag
685     */
686    public boolean isIgnoreSearchExclude() {
687
688        return m_ignoreSearchExclude;
689    }
690
691    /**
692     * Returns a flag, indicating if release and expiration date should be ignored.<p>
693     *
694     * @return a flag, indicating if release and expiration date should be ignored
695     */
696    public boolean isIncludeExpired() {
697
698        return m_includeExpired;
699    }
700
701    /**
702     * Sets the categories for the search.<p>
703     *
704     * Results are found only if they are contained in at least one of the given categories.
705     *
706     * @param categories the categories to set
707     */
708    public void setCategories(List<String> categories) {
709
710        m_categories = categories;
711    }
712
713    /**
714     * Sets the container types for the search.<p>
715     *
716     * Results are found only if they are compatible with one of the given container types.
717     * If no container type is set, results compatible with any container will be returned in the search result.<p>
718     *
719     * @param containerTypes the container types to set
720     */
721    public void setContainerTypes(List<String> containerTypes) {
722
723        m_containerTypes = containerTypes;
724    }
725
726    /**
727     * Sets the time range for the date of resource creation to consider in the search.<p>
728     *
729     * @param startTime the start time of the time range
730     * @param endTime the end time of the time range
731     */
732    public void setDateCreatedTimeRange(long startTime, long endTime) {
733
734        if (m_dateCreatedTimeRange == null) {
735            m_dateCreatedTimeRange = new CmsGallerySearchTimeRange(startTime, endTime);
736        }
737    }
738
739    /**
740     * Sets the time range for the date of resource last modification to consider in the search.<p>
741     *
742     * @param startTime the start time of the time range
743     * @param endTime the end time of the time range
744     */
745    public void setDateLastModifiedTimeRange(long startTime, long endTime) {
746
747        if (m_dateLastModifiedTimeRange == null) {
748            m_dateLastModifiedTimeRange = new CmsGallerySearchTimeRange(startTime, endTime);
749        }
750    }
751
752    /**
753     * Sets the structure IDs of functions to exclude from the search results.
754     *
755     * @param excludedFunctions the structure IDs of functions to exclude
756     */
757    public void setExcludedFunctions(Set<CmsUUID> excludedFunctions) {
758
759        m_excludedFunctions = excludedFunctions;
760
761    }
762
763    /**
764     * Sets the folders to search in.<p>
765     *
766     * @param folders the list of VFS folders
767     */
768    public void setFolders(List<String> folders) {
769
770        m_folders = folders;
771    }
772
773    /**
774     * Enables/disables the 'force empty result' flag.
775     *
776     * If this is set to true, an empty search result should be returned regardless of the other parameters.
777     *
778     * @param forceEmptyResult if true, force an empty search result
779     */
780    public void setForceEmptyResult(boolean forceEmptyResult) {
781
782        m_forceEmptyResult = forceEmptyResult;
783    }
784
785    /**
786     * Sets the dynamic function availability.
787     *
788     * @param dynamicFunctionAvailability the dynamic function availability
789     */
790    public void setFunctionAvailability(CmsFunctionAvailability dynamicFunctionAvailability) {
791
792        m_functionAvailability = dynamicFunctionAvailability;
793    }
794
795    /**
796     * Sets the galleries for the search.<p>
797     *
798     * Results are found only if they are contained in one of the given galleries.
799     * If no gallery is set, results from all galleries will be returned in the search result.<p>
800     *
801     * @param galleries the galleries to set
802     */
803    public void setGalleries(List<String> galleries) {
804
805        m_galleries = galleries;
806    }
807
808    /**
809     * Sets the search exclude property ignore flag.<p>
810     *
811     * @param excludeForPageEditor the search exclude property ignore flag
812     */
813    public void setIgnoreSearchExclude(boolean excludeForPageEditor) {
814
815        m_ignoreSearchExclude = excludeForPageEditor;
816    }
817
818    /**
819     * Sets the ids of functions to include.
820     *
821     * @param includedFunctions the ids of functions to include
822     */
823    public void setIncludedFunctions(Set<CmsUUID> includedFunctions) {
824
825        m_includedFunctions = includedFunctions;
826    }
827
828    /**
829     * Set the flag, determining if expired and unreleased resources should be shown.
830     * @param includeExpired iff <code>true</code> expired and unreleased resources are shown.
831     */
832    public void setIncludeExpired(boolean includeExpired) {
833
834        m_includeExpired = includeExpired;
835
836    }
837
838    /**
839     * Sets the maximum number of matches per result page.<p>
840     *
841     * Use this together with {@link #setResultPage(int)} in order to split the result
842     * in more than one page.<p>
843     *
844     * @param matchesPerPage the the maximum number of matches per result page to set
845     *
846     * @see #getMatchesPerPage()
847     * @see #setResultPage(int)
848     */
849    public void setMatchesPerPage(int matchesPerPage) {
850
851        m_matchesPerPage = matchesPerPage;
852    }
853
854    /**
855     * Sets the gallery reference path.<p>
856     *
857     * @param referencePath the gallery reference path
858     */
859    public void setReferencePath(String referencePath) {
860
861        m_referencePath = referencePath;
862    }
863
864    /**
865     * Sets the names of the resource types to include in the search result.<p>
866     *
867     * Results are found only if they resources match one of the given resource type names.
868     * If no resource type name is set, all resource types will be returned in the search result.<p>
869     *
870     * @param resourceTypes the names of the resource types to include in the search result
871     */
872    public void setResourceTypes(List<String> resourceTypes) {
873
874        m_resourceTypes = resourceTypes;
875    }
876
877    /**
878     * Sets the index of the result page that should be returned.<p>
879     *
880     * Use this together with {@link #setMatchesPerPage(int)} in order to split the result
881     * in more than one page.<p>
882     *
883     * @param resultPage the index of the result page to return
884     *
885     * @see #getResultPage()
886     * @see #getMatchesPerPage()
887     * @see #setMatchesPerPage(int)
888     */
889    public void setResultPage(int resultPage) {
890
891        m_resultPage = resultPage;
892    }
893
894    /**
895     * Sets the search scope.<p>
896     *
897     * @param scope the search scope
898     */
899    public void setScope(CmsGallerySearchScope scope) {
900
901        m_scope = scope;
902    }
903
904    /**
905     * Sets the locale for the search.<p>
906     *
907     * Results are found only if they match the given locale.
908     * If no locale is set, results for all locales will be returned in the search result.<p>
909     *
910     * @param locale the locale to set
911     */
912    public void setSearchLocale(String locale) {
913
914        m_locale = locale;
915    }
916
917    /**
918     * Sets the words (terms) for the full text search.<p>
919     *
920     * Results are found only if they text extraction for the resource contains all given search words.
921     * If no search word is set, all resources will be returned in the search result.<p>
922     *
923     * Please note that this should be a list of words separated by white spaces.
924     * Simple Lucene modifiers such as (+), (-) and (*) are allowed, but anything more complex then this
925     * will be removed.<p>
926     *
927     * @param words the words (terms) for the full text search to set
928     */
929    public void setSearchWords(String words) {
930
931        m_words = words;
932    }
933
934    /**
935     * Sets the sort order for the search.<p>
936     *
937     * @param sortOrder the sort order to set
938     */
939    public void setSortOrder(CmsGallerySortParam sortOrder) {
940
941        m_sortOrder = sortOrder;
942    }
943
944    /**
945     * Sets the template compatibility string.
946     *
947     * @param compatibility the template compatibility string
948     */
949    public void setTemplateCompatibility(String compatibility) {
950
951        m_templateCompatibility = compatibility;
952    }
953
954    /**
955     * Adds folders to perform the search in.
956     * @param folders Folders to search in.
957     */
958    private void addFoldersToSearchIn(final List<String> folders) {
959
960        if (null == folders) {
961            return;
962        }
963
964        for (String folder : folders) {
965            if (!CmsResource.isFolder(folder)) {
966                folder += "/";
967            }
968
969            m_foldersToSearchIn.add(folder);
970        }
971    }
972
973    /**
974     * Checks if the given list of resource type names contains a function-like type.<p>
975     *
976     * @param resourceTypes the collection of resource types
977     * @return true if the list contains a function-like type
978     */
979    private boolean containsFunctionType(List<String> resourceTypes) {
980
981        if (resourceTypes.contains(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION)) {
982            return true;
983        }
984        if (resourceTypes.contains(CmsResourceTypeFunctionConfig.TYPE_NAME)) {
985            return true;
986        }
987        return false;
988    }
989
990    /**
991     * Returns the Lucene sort indicated by the selected sort order.<p>
992     *
993     * @return the Lucene sort indicated by the selected sort order
994     *
995     * @see #getSortOrder()
996     */
997    private CmsPair<String, org.apache.solr.client.solrj.SolrQuery.ORDER> getSort() {
998
999        final String sortTitle = CmsSearchFieldConfiguration.getLocaleExtendedName(
1000            CmsSearchField.FIELD_DISPTITLE,
1001            getLocale()) + "_sort";
1002
1003        switch (getSortOrder()) {
1004            case dateCreated_asc:
1005                return CmsPair.create(CmsSearchField.FIELD_DATE_CREATED, ORDER.asc);
1006            case dateCreated_desc:
1007                return CmsPair.create(CmsSearchField.FIELD_DATE_CREATED, ORDER.desc);
1008            case dateExpired_asc:
1009                return CmsPair.create(CmsSearchField.FIELD_DATE_EXPIRED, ORDER.asc);
1010            case dateExpired_desc:
1011                return CmsPair.create(CmsSearchField.FIELD_DATE_EXPIRED, ORDER.desc);
1012            case dateLastModified_asc:
1013                return CmsPair.create(CmsSearchField.FIELD_DATE_LASTMODIFIED, ORDER.asc);
1014            case dateLastModified_desc:
1015                return CmsPair.create(CmsSearchField.FIELD_DATE_LASTMODIFIED, ORDER.desc);
1016            case dateReleased_asc:
1017                return CmsPair.create(CmsSearchField.FIELD_DATE_RELEASED, ORDER.asc);
1018            case dateReleased_desc:
1019                return CmsPair.create(CmsSearchField.FIELD_DATE_RELEASED, ORDER.desc);
1020            case length_asc:
1021                return CmsPair.create(CmsSearchField.FIELD_SIZE, ORDER.asc);
1022            case length_desc:
1023                return CmsPair.create(CmsSearchField.FIELD_SIZE, ORDER.desc);
1024            case path_asc:
1025                return CmsPair.create(CmsSearchField.FIELD_PATH, ORDER.asc);
1026            case path_desc:
1027                return CmsPair.create(CmsSearchField.FIELD_PATH, ORDER.desc);
1028            case score:
1029                return CmsPair.create(CmsSearchField.FIELD_SCORE, ORDER.desc);
1030            case state_asc:
1031                return CmsPair.create(CmsSearchField.FIELD_STATE, ORDER.asc);
1032            case state_desc:
1033                return CmsPair.create(CmsSearchField.FIELD_STATE, ORDER.desc);
1034            case title_asc:
1035                return CmsPair.create(sortTitle, ORDER.asc);
1036            case title_desc:
1037                return CmsPair.create(sortTitle, ORDER.desc);
1038            case type_asc:
1039                return CmsPair.create(CmsSearchField.FIELD_TYPE, ORDER.asc);
1040            case type_desc:
1041                return CmsPair.create(CmsSearchField.FIELD_TYPE, ORDER.desc);
1042            case userCreated_asc:
1043                return CmsPair.create(CmsSearchField.FIELD_USER_CREATED, ORDER.asc);
1044            case userCreated_desc:
1045                return CmsPair.create(CmsSearchField.FIELD_USER_CREATED, ORDER.desc);
1046            case userLastModified_asc:
1047                return CmsPair.create(CmsSearchField.FIELD_USER_LAST_MODIFIED, ORDER.asc);
1048            case userLastModified_desc:
1049                return CmsPair.create(CmsSearchField.FIELD_USER_LAST_MODIFIED, ORDER.desc);
1050            default:
1051                return CmsPair.create(sortTitle, ORDER.asc);
1052        }
1053    }
1054
1055    /**
1056     * Applies the defined search folders to the Solr query.
1057     *
1058     * @param obj The current CmsObject object.
1059     */
1060    private void setSearchFolders(CmsObject obj) {
1061
1062        // check if parentFolders to search in have been set
1063        // if this evaluates false, the search folders have already been set, so
1064        // there's no need to add a scope filter
1065        if (m_foldersToSearchIn.isEmpty()) {
1066            // only append scope filter if no no folders or galleries given
1067            setSearchScopeFilter(obj);
1068        }
1069    }
1070
1071    /**
1072     * Sets the search scope.
1073     *
1074     * @param cms The current CmsObject object.
1075     */
1076    private void setSearchScopeFilter(CmsObject cms) {
1077
1078        final List<String> searchRoots = CmsSearchUtil.computeScopeFolders(cms, this);
1079
1080        // If the resource types contain the type "function" also
1081        // add "/system/modules/" to the search path
1082
1083        if ((null != getResourceTypes()) && containsFunctionType(getResourceTypes())) {
1084            searchRoots.add("/system/modules/");
1085        }
1086
1087        addFoldersToSearchIn(searchRoots);
1088    }
1089}