001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.search;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.messaging.DestinationNames;
020    import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.PropsUtil;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.security.permission.PermissionThreadLocal;
026    
027    import java.util.Collection;
028    import java.util.HashSet;
029    import java.util.List;
030    import java.util.Locale;
031    import java.util.Map;
032    import java.util.Set;
033    import java.util.concurrent.ConcurrentHashMap;
034    
035    /**
036     * @author Bruno Farache
037     * @author Raymond Augé
038     * @author Michael C. Han
039     */
040    public class SearchEngineUtil {
041    
042            /**
043             * @deprecated {@link com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS}
044             */
045            public static final int ALL_POS = -1;
046    
047            public static final String GENERIC_ENGINE_ID = "GENERIC_ENGINE";
048    
049            public static final String SYSTEM_ENGINE_ID = "SYSTEM_ENGINE";
050    
051            /**
052             * @deprecated {@link #addDocument(String, long, Document)}
053             */
054            public static void addDocument(long companyId, Document document)
055                    throws SearchException {
056    
057                    addDocument(_getSearchEngineId(document), companyId, document);
058            }
059    
060            public static void addDocument(
061                            String searchEngineId, long companyId, Document document)
062                    throws SearchException {
063    
064                    if (isIndexReadOnly()) {
065                            return;
066                    }
067    
068                    if (_log.isDebugEnabled()) {
069                            _log.debug("Add document " + document.toString());
070                    }
071    
072                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
073    
074                    IndexWriter indexWriter = searchEngine.getIndexWriter();
075    
076                    _searchPermissionChecker.addPermissionFields(companyId, document);
077    
078                    SearchContext searchContext = new SearchContext();
079    
080                    searchContext.setCompanyId(companyId);
081                    searchContext.setSearchEngineId(searchEngineId);
082    
083                    indexWriter.addDocument(searchContext, document);
084            }
085    
086            /**
087             * @deprecated {@link #addDocuments(String, long, Collection)}
088             */
089            public static void addDocuments(
090                            long companyId, Collection<Document> documents)
091                    throws SearchException {
092    
093                    addDocuments(_getSearchEngineId(documents), companyId, documents);
094            }
095    
096            public static void addDocuments(
097                            String searchEngineId, long companyId,
098                            Collection<Document> documents)
099                    throws SearchException {
100    
101                    if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
102                            return;
103                    }
104    
105                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
106    
107                    IndexWriter indexWriter = searchEngine.getIndexWriter();
108    
109                    for (Document document : documents) {
110                            if (_log.isDebugEnabled()) {
111                                    _log.debug("Add document " + document.toString());
112                            }
113    
114                            _searchPermissionChecker.addPermissionFields(companyId, document);
115                    }
116    
117                    SearchContext searchContext = new SearchContext();
118    
119                    searchContext.setCompanyId(companyId);
120                    searchContext.setSearchEngineId(searchEngineId);
121    
122                    indexWriter.addDocuments(searchContext, documents);
123            }
124    
125            /**
126             * @deprecated {@link #setSearchEngine(String, SearchEngine)}
127             */
128            public static void addSearchEngine(SearchEngine searchEngine) {
129                    String searchEngineId = getDefaultSearchEngineId();
130    
131                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
132    
133                    _searchEngines.put(searchEngineId, searchEngine);
134            }
135    
136            /**
137             * @deprecated {@link #deleteDocument(String, long, String)}
138             */
139            public static void deleteDocument(long companyId, String uid)
140                    throws SearchException {
141    
142                    for (String searchEngineId : _searchEngines.keySet()) {
143                            deleteDocument(searchEngineId, companyId, uid);
144                    }
145            }
146    
147            public static void deleteDocument(
148                            String searchEngineId, long companyId, String uid)
149                    throws SearchException {
150    
151                    if (isIndexReadOnly()) {
152                            return;
153                    }
154    
155                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
156    
157                    IndexWriter indexWriter = searchEngine.getIndexWriter();
158    
159                    SearchContext searchContext = new SearchContext();
160    
161                    searchContext.setCompanyId(companyId);
162                    searchContext.setSearchEngineId(searchEngineId);
163    
164                    indexWriter.deleteDocument(searchContext, uid);
165            }
166    
167            /**
168             * @deprecated {@link #deleteDocuments(String, long, Collection)}
169             */
170            public static void deleteDocuments(long companyId, Collection<String> uids)
171                    throws SearchException {
172    
173                    for (String searchEngineId : _searchEngines.keySet()) {
174                            deleteDocuments(searchEngineId, companyId, uids);
175                    }
176            }
177    
178            public static void deleteDocuments(
179                            String searchEngineId, long companyId, Collection<String> uids)
180                    throws SearchException {
181    
182                    if (isIndexReadOnly() || (uids == null) || uids.isEmpty()) {
183                            return;
184                    }
185    
186                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
187    
188                    IndexWriter indexWriter = searchEngine.getIndexWriter();
189    
190                    SearchContext searchContext = new SearchContext();
191    
192                    searchContext.setCompanyId(companyId);
193                    searchContext.setSearchEngineId(searchEngineId);
194    
195                    indexWriter.deleteDocuments(searchContext, uids);
196            }
197    
198            /**
199             * @deprecated {@link #deletePortletDocuments(String, long, String)}
200             */
201            public static void deletePortletDocuments(long companyId, String portletId)
202                    throws SearchException {
203    
204                    for (String searchEngineId : _searchEngines.keySet()) {
205                            deletePortletDocuments(searchEngineId, companyId, portletId);
206                    }
207            }
208    
209            public static void deletePortletDocuments(
210                            String searchEngineId, long companyId, String portletId)
211                    throws SearchException {
212    
213                    if (isIndexReadOnly()) {
214                            return;
215                    }
216    
217                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
218    
219                    if (searchEngine == null) {
220                            return;
221                    }
222    
223                    IndexWriter indexWriter = searchEngine.getIndexWriter();
224    
225                    SearchContext searchContext = new SearchContext();
226    
227                    searchContext.setCompanyId(companyId);
228                    searchContext.setSearchEngineId(searchEngineId);
229    
230                    indexWriter.deletePortletDocuments(searchContext, portletId);
231            }
232    
233            public static String getDefaultSearchEngineId() {
234                    if (_defaultSearchEngineId == null) {
235                            return SYSTEM_ENGINE_ID;
236                    }
237    
238                    return _defaultSearchEngineId;
239            }
240    
241            public static String[] getEntryClassNames() {
242                    Set<String> assetEntryClassNames = new HashSet<String>();
243    
244                    for (Indexer indexer : IndexerRegistryUtil.getIndexers()) {
245                            for (String className : indexer.getClassNames()) {
246                                    if (!_excludedEntryClassNames.contains(className)) {
247                                            assetEntryClassNames.add(className);
248                                    }
249                            }
250                    }
251    
252                    return assetEntryClassNames.toArray(
253                            new String[assetEntryClassNames.size()]);
254            }
255    
256            /**
257             * @deprecated {@link #getSearchEngine(String)}
258             */
259            public static SearchEngine getSearchEngine() {
260                    return getSearchEngine(getDefaultSearchEngineId());
261            }
262    
263            public static SearchEngine getSearchEngine(String searchEngineId) {
264                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
265    
266                    SearchEngine searchEngine = _searchEngines.get(searchEngineId);
267    
268                    if (searchEngine == null) {
269                            if (getDefaultSearchEngineId().equals(searchEngineId)) {
270                                    throw new IllegalStateException(
271                                            "There is no default search engine configured with ID " +
272                                                    getDefaultSearchEngineId());
273                            }
274    
275                            if (_log.isWarnEnabled()) {
276                                    _log.warn(
277                                            "There is no search engine configured with ID " +
278                                                    searchEngineId);
279                            }
280                    }
281    
282                    return searchEngine;
283            }
284    
285            public static Set<String> getSearchEngineIds() {
286                    PortalRuntimePermission.checkGetBeanProperty(
287                            SearchEngineUtil.class, "searchEngineIds");
288    
289                    return _searchEngines.keySet();
290            }
291    
292            public static SearchEngine getSearchEngineSilent(String searchEngineId) {
293                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
294    
295                    return _searchEngines.get(searchEngineId);
296            }
297    
298            public static SearchPermissionChecker getSearchPermissionChecker() {
299                    PortalRuntimePermission.checkGetBeanProperty(
300                            SearchEngineUtil.class, "searchPermissionChecker");
301    
302                    return _searchPermissionChecker;
303            }
304    
305            public static String getSearchReaderDestinationName(String searchEngineId) {
306                    return DestinationNames.SEARCH_READER.concat(StringPool.SLASH).concat(
307                            searchEngineId);
308            }
309    
310            public static String getSearchWriterDestinationName(String searchEngineId) {
311                    return DestinationNames.SEARCH_WRITER.concat(StringPool.SLASH).concat(
312                            searchEngineId);
313            }
314    
315            public static void indexDictionaries(long companyId)
316                    throws SearchException {
317    
318                    Set<String> searchEngineIds = getSearchEngineIds();
319    
320                    for (String searchEngineId : searchEngineIds) {
321                            indexDictionaries(searchEngineId, companyId);
322                    }
323            }
324    
325            public static void indexDictionaries(String searchEngineId, long companyId)
326                    throws SearchException {
327    
328                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
329    
330                    IndexWriter indexWriter = searchEngine.getIndexWriter();
331    
332                    SearchContext searchContext = new SearchContext();
333    
334                    searchContext.setCompanyId(companyId);
335                    searchContext.setSearchEngineId(searchEngineId);
336    
337                    indexWriter.indexDictionaries(searchContext);
338            }
339    
340            public static void indexDictionary(long companyId, Locale locale)
341                    throws SearchException {
342    
343                    Set<String> searchEngineIds = getSearchEngineIds();
344    
345                    for (String searchEngineId : searchEngineIds) {
346                            indexDictionary(searchEngineId, companyId, locale);
347                    }
348            }
349    
350            public static void indexDictionary(
351                            String searchEngineId, long companyId, Locale locale)
352                    throws SearchException {
353    
354                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
355    
356                    IndexWriter indexWriter = searchEngine.getIndexWriter();
357    
358                    SearchContext searchContext = new SearchContext();
359    
360                    searchContext.setCompanyId(companyId);
361                    searchContext.setSearchEngineId(searchEngineId);
362                    searchContext.setLocale(locale);
363    
364                    indexWriter.indexDictionary(searchContext);
365            }
366    
367            public static boolean isIndexReadOnly() {
368                    PortalRuntimePermission.checkGetBeanProperty(
369                            SearchEngineUtil.class, "indexReadOnly");
370    
371                    return _indexReadOnly;
372            }
373    
374            public static SearchEngine removeSearchEngine(String searchEngineId) {
375                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
376    
377                    return _searchEngines.remove(searchEngineId);
378            }
379    
380            /**
381             * @deprecated
382             */
383            public static Hits search(
384                            long companyId, long[] groupIds, long userId, String className,
385                            Query query, int start, int end)
386                    throws SearchException {
387    
388                    SearchContext searchContext = new SearchContext();
389    
390                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
391    
392                    if (userId > 0) {
393                            query = _searchPermissionChecker.getPermissionQuery(
394                                    companyId, groupIds, userId, className, query, searchContext);
395                    }
396    
397                    return search(
398                            companyId, query, SortFactoryUtil.getDefaultSorts(), start, end);
399            }
400    
401            /**
402             * @deprecated
403             */
404            public static Hits search(
405                            long companyId, long[] groupIds, long userId, String className,
406                            Query query, Sort sort, int start, int end)
407                    throws SearchException {
408    
409                    SearchContext searchContext = new SearchContext();
410    
411                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
412    
413                    if (userId > 0) {
414                            query = _searchPermissionChecker.getPermissionQuery(
415                                    companyId, groupIds, userId, className, query, searchContext);
416                    }
417    
418                    return search(companyId, query, sort, start, end);
419            }
420    
421            /**
422             * @deprecated
423             */
424            public static Hits search(
425                            long companyId, long[] groupIds, long userId, String className,
426                            Query query, Sort[] sorts, int start, int end)
427                    throws SearchException {
428    
429                    SearchContext searchContext = new SearchContext();
430    
431                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
432    
433                    if (userId > 0) {
434                            query = _searchPermissionChecker.getPermissionQuery(
435                                    companyId, groupIds, userId, className, query, searchContext);
436                    }
437    
438                    return search(companyId, query, sorts, start, end);
439            }
440    
441            /**
442             * @deprecated {@link #search(String, long, Query, int, int)}
443             */
444            public static Hits search(long companyId, Query query, int start, int end)
445                    throws SearchException {
446    
447                    return search(getDefaultSearchEngineId(), companyId, query, start, end);
448            }
449    
450            /**
451             * @deprecated {@link #search(String, long, Query, Sort, int, int)}
452             */
453            public static Hits search(
454                            long companyId, Query query, Sort sort, int start, int end)
455                    throws SearchException {
456    
457                    return search(
458                            getDefaultSearchEngineId(), companyId, query, sort, start, end);
459            }
460    
461            /**
462             * @deprecated {@link #search(String, long, Query, Sort[], int, int)}
463             */
464            public static Hits search(
465                            long companyId, Query query, Sort[] sorts, int start, int end)
466                    throws SearchException {
467    
468                    return search(
469                            getDefaultSearchEngineId(), companyId, query, sorts, start, end);
470            }
471    
472            public static Hits search(SearchContext searchContext, Query query)
473                    throws SearchException {
474    
475                    if (_log.isDebugEnabled()) {
476                            _log.debug("Search query " + query.toString());
477                    }
478    
479                    SearchEngine searchEngine = getSearchEngine(
480                            searchContext.getSearchEngineId());
481    
482                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
483    
484                    return indexSearcher.search(searchContext, query);
485            }
486    
487            public static Hits search(
488                            String searchEngineId, long companyId, Query query, int start,
489                            int end)
490                    throws SearchException {
491    
492                    if (_log.isDebugEnabled()) {
493                            _log.debug("Search query " + query.toString());
494                    }
495    
496                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
497    
498                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
499    
500                    return indexSearcher.search(
501                            searchEngineId, companyId, query, SortFactoryUtil.getDefaultSorts(),
502                            start, end);
503            }
504    
505            public static Hits search(
506                            String searchEngineId, long companyId, Query query, Sort sort,
507                            int start, int end)
508                    throws SearchException {
509    
510                    if (_log.isDebugEnabled()) {
511                            _log.debug("Search query " + query.toString());
512                    }
513    
514                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
515    
516                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
517    
518                    return indexSearcher.search(
519                            searchEngineId, companyId, query, new Sort[] {sort}, start, end);
520            }
521    
522            public static Hits search(
523                            String searchEngineId, long companyId, Query query, Sort[] sorts,
524                            int start, int end)
525                    throws SearchException {
526    
527                    if (_log.isDebugEnabled()) {
528                            _log.debug("Search query " + query.toString());
529                    }
530    
531                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
532    
533                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
534    
535                    return indexSearcher.search(
536                            searchEngineId, companyId, query, sorts, start, end);
537            }
538    
539            public static void setDefaultSearchEngineId(String defaultSearchEngineId) {
540                    PortalRuntimePermission.checkSetBeanProperty(
541                            SearchEngineUtil.class, "defaultSearchEngineId");
542    
543                    _defaultSearchEngineId = defaultSearchEngineId;
544            }
545    
546            public static void setIndexReadOnly(boolean indexReadOnly) {
547                    PortalRuntimePermission.checkSetBeanProperty(
548                            SearchEngineUtil.class, "indexReadOnly");
549    
550                    _indexReadOnly = indexReadOnly;
551            }
552    
553            public static void setSearchEngine(
554                    String searchEngineId, SearchEngine searchEngine) {
555    
556                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
557    
558                    _searchEngines.put(searchEngineId, searchEngine);
559            }
560    
561            public static String spellCheckKeywords(SearchContext searchContext)
562                    throws SearchException {
563    
564                    if (_log.isDebugEnabled()) {
565                            _log.debug("Spell checking " + searchContext.getKeywords());
566                    }
567    
568                    SearchEngine searchEngine = getSearchEngine(
569                            searchContext.getSearchEngineId());
570    
571                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
572    
573                    return indexSearcher.spellCheckKeywords(searchContext);
574            }
575    
576            public static Map<String, List<String>> spellCheckKeywords(
577                            SearchContext searchContext, int max)
578                    throws SearchException {
579    
580                    if (_log.isDebugEnabled()) {
581                            _log.debug("Spell checking " + searchContext.getKeywords());
582                    }
583    
584                    SearchEngine searchEngine = getSearchEngine(
585                            searchContext.getSearchEngineId());
586    
587                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
588    
589                    return indexSearcher.spellCheckKeywords(searchContext, max);
590            }
591    
592            public static String[] suggestKeywordQueries(
593                            SearchContext searchContext, int max)
594                    throws SearchException {
595    
596                    if (_log.isDebugEnabled()) {
597                            _log.debug(
598                                    "Suggesting keyword queries" + searchContext.getKeywords());
599                    }
600    
601                    SearchEngine searchEngine = getSearchEngine(
602                            searchContext.getSearchEngineId());
603    
604                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
605    
606                    return indexSearcher.suggestKeywordQueries(searchContext, max);
607            }
608    
609            /**
610             * @deprecated {@link #updateDocument(String, long, Document)}
611             */
612            public static void updateDocument(long companyId, Document document)
613                    throws SearchException {
614    
615                    updateDocument(_getSearchEngineId(document), companyId, document);
616            }
617    
618            public static void updateDocument(
619                            String searchEngineId, long companyId, Document document)
620                    throws SearchException {
621    
622                    if (isIndexReadOnly()) {
623                            return;
624                    }
625    
626                    if (_log.isDebugEnabled()) {
627                            _log.debug("Document " + document.toString());
628                    }
629    
630                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
631    
632                    IndexWriter indexWriter = searchEngine.getIndexWriter();
633    
634                    _searchPermissionChecker.addPermissionFields(companyId, document);
635    
636                    SearchContext searchContext = new SearchContext();
637    
638                    searchContext.setCompanyId(companyId);
639                    searchContext.setSearchEngineId(searchEngineId);
640    
641                    indexWriter.updateDocument(searchContext, document);
642            }
643    
644            /**
645             * @deprecated {@link #updateDocuments(String, long, Collection)}
646             */
647            public static void updateDocuments(
648                            long companyId, Collection<Document> documents)
649                    throws SearchException {
650    
651                    updateDocuments(_getSearchEngineId(documents), companyId, documents);
652            }
653    
654            public static void updateDocuments(
655                            String searchEngineId, long companyId,
656                            Collection<Document> documents)
657                    throws SearchException {
658    
659                    if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
660                            return;
661                    }
662    
663                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
664    
665                    IndexWriter indexWriter = searchEngine.getIndexWriter();
666    
667                    for (Document document : documents) {
668                            if (_log.isDebugEnabled()) {
669                                    _log.debug("Document " + document.toString());
670                            }
671    
672                            _searchPermissionChecker.addPermissionFields(companyId, document);
673                    }
674    
675                    SearchContext searchContext = new SearchContext();
676    
677                    searchContext.setCompanyId(companyId);
678                    searchContext.setSearchEngineId(searchEngineId);
679    
680                    indexWriter.updateDocuments(searchContext, documents);
681            }
682    
683            public static void updatePermissionFields(String name, String primKey) {
684                    if (isIndexReadOnly() || !PermissionThreadLocal.isFlushEnabled()) {
685                            return;
686                    }
687    
688                    _searchPermissionChecker.updatePermissionFields(name, primKey);
689            }
690    
691            public void setExcludedEntryClassNames(
692                    List<String> excludedEntryClassNames) {
693    
694                    PortalRuntimePermission.checkSetBeanProperty(
695                            getClass(), "excludedEntryClassNames");
696    
697                    _excludedEntryClassNames.addAll(excludedEntryClassNames);
698            }
699    
700            /**
701             * @deprecated {@link #setSearchEngine(String, SearchEngine)}
702             */
703            public void setSearchEngine(SearchEngine searchEngine) {
704                    String searchEngineId = getDefaultSearchEngineId();
705    
706                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
707    
708                    _searchEngines.put(searchEngineId, searchEngine);
709            }
710    
711            public void setSearchPermissionChecker(
712                    SearchPermissionChecker searchPermissionChecker) {
713    
714                    PortalRuntimePermission.checkSetBeanProperty(
715                            getClass(), "searchPermissionChecker");
716    
717                    _searchPermissionChecker = searchPermissionChecker;
718            }
719    
720            private static String _getSearchEngineId(Collection<Document> documents) {
721                    if (!documents.isEmpty()) {
722                            Document document = documents.iterator().next();
723    
724                            return _getSearchEngineId(document);
725                    }
726    
727                    return getDefaultSearchEngineId();
728            }
729    
730            private static String _getSearchEngineId(Document document) {
731                    String entryClassName = document.get("entryClassName");
732    
733                    Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
734    
735                    String searchEngineId = indexer.getSearchEngineId();
736    
737                    if (_log.isDebugEnabled()) {
738                            _log.debug(
739                                    "Search engine ID for " + indexer.getClass() + " is " +
740                                            searchEngineId);
741                    }
742    
743                    return searchEngineId;
744            }
745    
746            private static Log _log = LogFactoryUtil.getLog(SearchEngineUtil.class);
747    
748            private static String _defaultSearchEngineId;
749            private static Set<String> _excludedEntryClassNames = new HashSet<String>();
750            private static boolean _indexReadOnly = GetterUtil.getBoolean(
751                    PropsUtil.get(PropsKeys.INDEX_READ_ONLY));
752            private static Map<String, SearchEngine> _searchEngines =
753                    new ConcurrentHashMap<String, SearchEngine>();
754            private static SearchPermissionChecker _searchPermissionChecker;
755    
756    }