001    /**
002     * Copyright (c) 2000-present 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.ClassUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.PropsKeys;
024    import com.liferay.portal.kernel.util.PropsUtil;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.security.permission.PermissionThreadLocal;
027    import com.liferay.registry.Registry;
028    import com.liferay.registry.RegistryUtil;
029    import com.liferay.registry.ServiceReference;
030    import com.liferay.registry.ServiceTracker;
031    import com.liferay.registry.ServiceTrackerCustomizer;
032    
033    import java.util.Collection;
034    import java.util.HashSet;
035    import java.util.Iterator;
036    import java.util.List;
037    import java.util.Locale;
038    import java.util.Map;
039    import java.util.Set;
040    import java.util.concurrent.ConcurrentHashMap;
041    
042    /**
043     * @author Bruno Farache
044     * @author Raymond Aug??
045     * @author Michael C. Han
046     */
047    public class SearchEngineUtil {
048    
049            /**
050             * @deprecated As of 6.2.0, replaced by {@link
051             *             com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS}
052             */
053            @Deprecated
054            public static final int ALL_POS = -1;
055    
056            public static final String GENERIC_ENGINE_ID = "GENERIC_ENGINE";
057    
058            public static final String SYSTEM_ENGINE_ID = "SYSTEM_ENGINE";
059    
060            /**
061             * @deprecated As of 6.2.0, replaced by {@link #addDocument(String, long,
062             *             Document, boolean)}
063             */
064            @Deprecated
065            public static void addDocument(long companyId, Document document)
066                    throws SearchException {
067    
068                    addDocument(getSearchEngineId(document), companyId, document, true);
069            }
070    
071            /**
072             * @deprecated As of 7.0.0, replaced by {@link #addDocument(String, long,
073             *             Document, boolean)}
074             */
075            @Deprecated
076            public static void addDocument(
077                            String searchEngineId, long companyId, Document document)
078                    throws SearchException {
079    
080                    addDocument(searchEngineId, companyId, document, false);
081            }
082    
083            public static void addDocument(
084                            String searchEngineId, long companyId, Document document,
085                            boolean commitImmediately)
086                    throws SearchException {
087    
088                    if (isIndexReadOnly()) {
089                            return;
090                    }
091    
092                    if (_log.isDebugEnabled()) {
093                            _log.debug("Add document " + document.toString());
094                    }
095    
096                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
097    
098                    IndexWriter indexWriter = searchEngine.getIndexWriter();
099    
100                    _searchPermissionChecker.addPermissionFields(companyId, document);
101    
102                    SearchContext searchContext = new SearchContext();
103    
104                    searchContext.setCommitImmediately(commitImmediately);
105                    searchContext.setCompanyId(companyId);
106                    searchContext.setSearchEngineId(searchEngineId);
107    
108                    indexWriter.addDocument(searchContext, document);
109            }
110    
111            /**
112             * @deprecated As of 6.2.0, replaced by {@link #addDocuments(String, long,
113             *             Collection, boolean)}
114             */
115            @Deprecated
116            public static void addDocuments(
117                            long companyId, Collection<Document> documents)
118                    throws SearchException {
119    
120                    addDocuments(getSearchEngineId(documents), companyId, documents, false);
121            }
122    
123            /**
124             * @deprecated As of 7.0.0, replaced by {@link #addDocuments(String, long,
125             *             Collection, boolean)}
126             */
127            @Deprecated
128            public static void addDocuments(
129                            String searchEngineId, long companyId,
130                            Collection<Document> documents)
131                    throws SearchException {
132    
133                    addDocuments(searchEngineId, companyId, documents, false);
134            }
135    
136            public static void addDocuments(
137                            String searchEngineId, long companyId,
138                            Collection<Document> documents, boolean commitImmediately)
139                    throws SearchException {
140    
141                    if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
142                            return;
143                    }
144    
145                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
146    
147                    IndexWriter indexWriter = searchEngine.getIndexWriter();
148    
149                    for (Document document : documents) {
150                            if (_log.isDebugEnabled()) {
151                                    _log.debug("Add document " + document.toString());
152                            }
153    
154                            _searchPermissionChecker.addPermissionFields(companyId, document);
155                    }
156    
157                    SearchContext searchContext = new SearchContext();
158    
159                    searchContext.setCommitImmediately(commitImmediately);
160                    searchContext.setCompanyId(companyId);
161                    searchContext.setSearchEngineId(searchEngineId);
162    
163                    indexWriter.addDocuments(searchContext, documents);
164            }
165    
166            /**
167             * @deprecated As of 6.2.0, replaced by {@link #setSearchEngine(String,
168             *             SearchEngine)}
169             */
170            @Deprecated
171            public static void addSearchEngine(SearchEngine searchEngine) {
172                    String searchEngineId = getDefaultSearchEngineId();
173    
174                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
175    
176                    setSearchEngine(searchEngineId, searchEngine);
177            }
178    
179            public synchronized static void backup(long companyId, String backupName)
180                    throws SearchException {
181    
182                    for (SearchEngine searchEngine : _searchEngines.values()) {
183                            searchEngine.backup(companyId, backupName);
184                    }
185            }
186    
187            public synchronized static String backup(
188                            long companyId, String searchEngineId, String backupName)
189                    throws SearchException {
190    
191                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
192    
193                    return searchEngine.backup(companyId, backupName);
194            }
195    
196            public synchronized static void backup(String backupName)
197                    throws SearchException {
198    
199                    for (SearchEngine searchEngine : _searchEngines.values()) {
200                            for (long companyId : _companyIds) {
201                                    searchEngine.backup(companyId, backupName);
202                            }
203                    }
204            }
205    
206            /**
207             * @deprecated As of 6.2.0, replaced by {@link #deleteDocument(String, long,
208             *             String)}
209             */
210            @Deprecated
211            public static void deleteDocument(long companyId, String uid)
212                    throws SearchException {
213    
214                    for (String searchEngineId : _searchEngines.keySet()) {
215                            deleteDocument(searchEngineId, companyId, uid, true);
216                    }
217            }
218    
219            /**
220             * @deprecated As of 7.0.0, replaced by {@link #deleteDocument(String, long,
221             *             String, boolean)}
222             */
223            @Deprecated
224            public static void deleteDocument(
225                            String searchEngineId, long companyId, String uid)
226                    throws SearchException {
227    
228                    deleteDocument(searchEngineId, companyId, uid, false);
229            }
230    
231            public static void deleteDocument(
232                            String searchEngineId, long companyId, String uid,
233                            boolean commitImmediately)
234                    throws SearchException {
235    
236                    if (isIndexReadOnly()) {
237                            return;
238                    }
239    
240                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
241    
242                    IndexWriter indexWriter = searchEngine.getIndexWriter();
243    
244                    SearchContext searchContext = new SearchContext();
245    
246                    searchContext.setCommitImmediately(commitImmediately);
247                    searchContext.setCompanyId(companyId);
248                    searchContext.setSearchEngineId(searchEngineId);
249    
250                    indexWriter.deleteDocument(searchContext, uid);
251            }
252    
253            /**
254             * @deprecated As of 6.2.0, replaced by {@link #deleteDocuments(String,
255             *             long, Collection, boolean)}
256             */
257            @Deprecated
258            public static void deleteDocuments(long companyId, Collection<String> uids)
259                    throws SearchException {
260    
261                    for (String searchEngineId : _searchEngines.keySet()) {
262                            deleteDocuments(searchEngineId, companyId, uids, true);
263                    }
264            }
265    
266            /**
267             * @deprecated As of 7.0.0, replaced by {@link #deleteDocuments(String,
268             *             long, Collection, boolean)}
269             */
270            @Deprecated
271            public static void deleteDocuments(
272                            String searchEngineId, long companyId, Collection<String> uids)
273                    throws SearchException {
274    
275                    deleteDocuments(searchEngineId, companyId, uids, false);
276            }
277    
278            public static void deleteDocuments(
279                            String searchEngineId, long companyId, Collection<String> uids,
280                            boolean commitImmediately)
281                    throws SearchException {
282    
283                    if (isIndexReadOnly() || (uids == null) || uids.isEmpty()) {
284                            return;
285                    }
286    
287                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
288    
289                    IndexWriter indexWriter = searchEngine.getIndexWriter();
290    
291                    SearchContext searchContext = new SearchContext();
292    
293                    searchContext.setCommitImmediately(commitImmediately);
294                    searchContext.setCompanyId(companyId);
295                    searchContext.setSearchEngineId(searchEngineId);
296    
297                    indexWriter.deleteDocuments(searchContext, uids);
298            }
299    
300            /**
301             * @deprecated As of 6.2.0, replaced by {@link
302             *             #deletePortletDocuments(String, long, String, boolean)}
303             */
304            @Deprecated
305            public static void deletePortletDocuments(long companyId, String portletId)
306                    throws SearchException {
307    
308                    for (String searchEngineId : _searchEngines.keySet()) {
309                            deletePortletDocuments(searchEngineId, companyId, portletId, true);
310                    }
311            }
312    
313            /**
314             * @deprecated As of 7.0.0, replaced by {@link
315             *             #deletePortletDocuments(String, long, String, boolean)}
316             */
317            @Deprecated
318            public static void deletePortletDocuments(
319                            String searchEngineId, long companyId, String portletId)
320                    throws SearchException {
321    
322                    deletePortletDocuments(searchEngineId, companyId, portletId, false);
323            }
324    
325            public static void deletePortletDocuments(
326                            String searchEngineId, long companyId, String portletId,
327                            boolean commitImmediately)
328                    throws SearchException {
329    
330                    if (isIndexReadOnly()) {
331                            return;
332                    }
333    
334                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
335    
336                    if (searchEngine == null) {
337                            return;
338                    }
339    
340                    IndexWriter indexWriter = searchEngine.getIndexWriter();
341    
342                    SearchContext searchContext = new SearchContext();
343    
344                    searchContext.setCommitImmediately(commitImmediately);
345                    searchContext.setCompanyId(companyId);
346                    searchContext.setSearchEngineId(searchEngineId);
347    
348                    indexWriter.deletePortletDocuments(searchContext, portletId);
349            }
350    
351            public static String getDefaultSearchEngineId() {
352                    if (_defaultSearchEngineId == null) {
353                            return SYSTEM_ENGINE_ID;
354                    }
355    
356                    return _defaultSearchEngineId;
357            }
358    
359            public static String[] getEntryClassNames() {
360                    Set<String> assetEntryClassNames = new HashSet<String>();
361    
362                    for (Indexer indexer : IndexerRegistryUtil.getIndexers()) {
363                            for (String className : indexer.getClassNames()) {
364                                    if (!_excludedEntryClassNames.contains(className)) {
365                                            assetEntryClassNames.add(className);
366                                    }
367                            }
368                    }
369    
370                    return assetEntryClassNames.toArray(
371                            new String[assetEntryClassNames.size()]);
372            }
373    
374            /**
375             * @deprecated As of 6.2.0, replaced by {@link #getSearchEngine(String)}
376             */
377            @Deprecated
378            public static SearchEngine getSearchEngine() {
379                    return getSearchEngine(getDefaultSearchEngineId());
380            }
381    
382            public static SearchEngine getSearchEngine(String searchEngineId) {
383                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
384    
385                    SearchEngine searchEngine = _searchEngines.get(searchEngineId);
386    
387                    if (searchEngine == null) {
388                            if (SYSTEM_ENGINE_ID.equals(searchEngineId)) {
389                                    waitForSystemSearchEngine();
390    
391                                    searchEngine = _searchEngines.get(SYSTEM_ENGINE_ID);
392    
393                                    if (searchEngine == null) {
394                                            throw new IllegalStateException(
395                                                    "Unable to find search engine " + SYSTEM_ENGINE_ID);
396                                    }
397    
398                                    return searchEngine;
399                            }
400    
401                            if (getDefaultSearchEngineId().equals(searchEngineId)) {
402                                    throw new IllegalStateException(
403                                            "There is no default search engine configured with ID " +
404                                                    getDefaultSearchEngineId());
405                            }
406    
407                            if (_log.isWarnEnabled()) {
408                                    _log.warn(
409                                            "There is no search engine configured with ID " +
410                                                    searchEngineId);
411                            }
412                    }
413    
414                    return searchEngine;
415            }
416    
417            public static String getSearchEngineId(Collection<Document> documents) {
418                    if (!documents.isEmpty()) {
419                            Iterator<Document> iterator = documents.iterator();
420    
421                            Document document = iterator.next();
422    
423                            return getSearchEngineId(document);
424                    }
425    
426                    return getDefaultSearchEngineId();
427            }
428    
429            public static String getSearchEngineId(Document document) {
430                    String entryClassName = document.get("entryClassName");
431    
432                    Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
433    
434                    String searchEngineId = indexer.getSearchEngineId();
435    
436                    if (_log.isDebugEnabled()) {
437                            _log.debug(
438                                    "Search engine ID " + searchEngineId + " is associated with " +
439                                            ClassUtil.getClassName(indexer));
440                    }
441    
442                    return searchEngineId;
443            }
444    
445            public static Set<String> getSearchEngineIds() {
446                    PortalRuntimePermission.checkGetBeanProperty(
447                            SearchEngineUtil.class, "searchEngineIds");
448    
449                    return _searchEngines.keySet();
450            }
451    
452            public static SearchEngine getSearchEngineSilent(String searchEngineId) {
453                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
454    
455                    return _searchEngines.get(searchEngineId);
456            }
457    
458            public static SearchPermissionChecker getSearchPermissionChecker() {
459                    PortalRuntimePermission.checkGetBeanProperty(
460                            SearchEngineUtil.class, "searchPermissionChecker");
461    
462                    return _searchPermissionChecker;
463            }
464    
465            public static String getSearchReaderDestinationName(String searchEngineId) {
466                    return DestinationNames.SEARCH_READER.concat(StringPool.SLASH).concat(
467                            searchEngineId);
468            }
469    
470            public static String getSearchWriterDestinationName(String searchEngineId) {
471                    return DestinationNames.SEARCH_WRITER.concat(StringPool.SLASH).concat(
472                            searchEngineId);
473            }
474    
475            public static void indexKeyword(
476                            long companyId, String querySuggestion, float weight,
477                            String keywordType, Locale locale)
478                    throws SearchException {
479    
480                    String searchEngineId = getDefaultSearchEngineId();
481    
482                    indexKeyword(
483                            searchEngineId, companyId, querySuggestion, weight, keywordType,
484                            locale);
485            }
486    
487            public static void indexKeyword(
488                            String searchEngineId, long companyId, String querySuggestion,
489                            float weight, String keywordType, Locale locale)
490                    throws SearchException {
491    
492                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
493    
494                    IndexWriter indexWriter = searchEngine.getIndexWriter();
495    
496                    SearchContext searchContext = new SearchContext();
497    
498                    searchContext.setCompanyId(companyId);
499                    searchContext.setSearchEngineId(searchEngineId);
500                    searchContext.setKeywords(querySuggestion);
501                    searchContext.setLocale(locale);
502    
503                    indexWriter.indexKeyword(searchContext, weight, keywordType);
504            }
505    
506            public static void indexQuerySuggestionDictionaries(long companyId)
507                    throws SearchException {
508    
509                    Set<String> searchEngineIds = getSearchEngineIds();
510    
511                    for (String searchEngineId : searchEngineIds) {
512                            indexQuerySuggestionDictionaries(searchEngineId, companyId);
513                    }
514            }
515    
516            public static void indexQuerySuggestionDictionaries(
517                            String searchEngineId, long companyId)
518                    throws SearchException {
519    
520                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
521    
522                    IndexWriter indexWriter = searchEngine.getIndexWriter();
523    
524                    SearchContext searchContext = new SearchContext();
525    
526                    searchContext.setCompanyId(companyId);
527                    searchContext.setSearchEngineId(searchEngineId);
528    
529                    indexWriter.indexQuerySuggestionDictionaries(searchContext);
530            }
531    
532            public static void indexQuerySuggestionDictionary(
533                            long companyId, Locale locale)
534                    throws SearchException {
535    
536                    String searchEngineId = getDefaultSearchEngineId();
537    
538                    indexQuerySuggestionDictionary(searchEngineId, companyId, locale);
539            }
540    
541            public static void indexQuerySuggestionDictionary(
542                            String searchEngineId, long companyId, Locale locale)
543                    throws SearchException {
544    
545                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
546    
547                    IndexWriter indexWriter = searchEngine.getIndexWriter();
548    
549                    SearchContext searchContext = new SearchContext();
550    
551                    searchContext.setCompanyId(companyId);
552                    searchContext.setSearchEngineId(searchEngineId);
553                    searchContext.setLocale(locale);
554    
555                    indexWriter.indexQuerySuggestionDictionary(searchContext);
556            }
557    
558            public static void indexSpellCheckerDictionaries(long companyId)
559                    throws SearchException {
560    
561                    String searchEngineId = getDefaultSearchEngineId();
562    
563                    indexSpellCheckerDictionaries(searchEngineId, companyId);
564            }
565    
566            public static void indexSpellCheckerDictionaries(
567                            String searchEngineId, long companyId)
568                    throws SearchException {
569    
570                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
571    
572                    IndexWriter indexWriter = searchEngine.getIndexWriter();
573    
574                    SearchContext searchContext = new SearchContext();
575    
576                    searchContext.setCompanyId(companyId);
577                    searchContext.setSearchEngineId(searchEngineId);
578    
579                    indexWriter.indexSpellCheckerDictionaries(searchContext);
580            }
581    
582            public static void indexSpellCheckerDictionary(
583                            long companyId, Locale locale)
584                    throws SearchException {
585    
586                    String searchEngineId = getDefaultSearchEngineId();
587    
588                    indexSpellCheckerDictionary(searchEngineId, companyId, locale);
589            }
590    
591            public static void indexSpellCheckerDictionary(
592                            String searchEngineId, long companyId, Locale locale)
593                    throws SearchException {
594    
595                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
596    
597                    IndexWriter indexWriter = searchEngine.getIndexWriter();
598    
599                    SearchContext searchContext = new SearchContext();
600    
601                    searchContext.setCompanyId(companyId);
602                    searchContext.setSearchEngineId(searchEngineId);
603                    searchContext.setLocale(locale);
604    
605                    indexWriter.indexSpellCheckerDictionary(searchContext);
606            }
607    
608            public synchronized static void initialize(long companyId) {
609                    if (_companyIds.contains(companyId)) {
610                            return;
611                    }
612    
613                    waitForSystemSearchEngine();
614    
615                    _companyIds.add(companyId);
616    
617                    for (SearchEngine searchEngine : _searchEngines.values()) {
618                            searchEngine.initialize(companyId);
619                    }
620            }
621    
622            public static boolean isIndexReadOnly() {
623                    PortalRuntimePermission.checkGetBeanProperty(
624                            SearchEngineUtil.class, "indexReadOnly");
625    
626                    return _indexReadOnly;
627            }
628    
629            public synchronized static void removeBackup(
630                            long companyId, String backupName)
631                    throws SearchException {
632    
633                    for (SearchEngine searchEngine : _searchEngines.values()) {
634                            searchEngine.removeBackup(companyId, backupName);
635                    }
636            }
637    
638            public synchronized static void removeBackup(String backupName)
639                    throws SearchException {
640    
641                    for (SearchEngine searchEngine : _searchEngines.values()) {
642                            for (long companyId : _companyIds) {
643                                    searchEngine.removeBackup(companyId, backupName);
644                            }
645                    }
646            }
647    
648            public synchronized static void removeCompany(long companyId) {
649                    if (!_companyIds.contains(companyId)) {
650                            return;
651                    }
652    
653                    for (SearchEngine searchEngine : _searchEngines.values()) {
654                            searchEngine.removeCompany(companyId);
655                    }
656    
657                    _companyIds.remove(companyId);
658            }
659    
660            public static SearchEngine removeSearchEngine(String searchEngineId) {
661                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
662    
663                    return _searchEngines.remove(searchEngineId);
664            }
665    
666            public synchronized static void restore(long companyId, String backupName)
667                    throws SearchException {
668    
669                    for (SearchEngine searchEngine : _searchEngines.values()) {
670                            searchEngine.restore(companyId, backupName);
671                    }
672            }
673    
674            public synchronized static void restore(String backupName)
675                    throws SearchException {
676    
677                    for (SearchEngine searchEngine : _searchEngines.values()) {
678                            for (long companyId : _companyIds) {
679                                    searchEngine.restore(companyId, backupName);
680                            }
681                    }
682            }
683    
684            /**
685             * @deprecated As of 6.2.0
686             */
687            @Deprecated
688            public static Hits search(
689                            long companyId, long[] groupIds, long userId, String className,
690                            Query query, int start, int end)
691                    throws SearchException {
692    
693                    SearchContext searchContext = new SearchContext();
694    
695                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
696    
697                    if (userId > 0) {
698                            query = _searchPermissionChecker.getPermissionQuery(
699                                    companyId, groupIds, userId, className, query, searchContext);
700                    }
701    
702                    return search(
703                            companyId, query, SortFactoryUtil.getDefaultSorts(), start, end);
704            }
705    
706            /**
707             * @deprecated As of 6.2.0
708             */
709            @Deprecated
710            public static Hits search(
711                            long companyId, long[] groupIds, long userId, String className,
712                            Query query, Sort sort, int start, int end)
713                    throws SearchException {
714    
715                    SearchContext searchContext = new SearchContext();
716    
717                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
718    
719                    if (userId > 0) {
720                            query = _searchPermissionChecker.getPermissionQuery(
721                                    companyId, groupIds, userId, className, query, searchContext);
722                    }
723    
724                    return search(companyId, query, sort, start, end);
725            }
726    
727            /**
728             * @deprecated As of 6.2.0
729             */
730            @Deprecated
731            public static Hits search(
732                            long companyId, long[] groupIds, long userId, String className,
733                            Query query, Sort[] sorts, int start, int end)
734                    throws SearchException {
735    
736                    SearchContext searchContext = new SearchContext();
737    
738                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
739    
740                    if (userId > 0) {
741                            query = _searchPermissionChecker.getPermissionQuery(
742                                    companyId, groupIds, userId, className, query, searchContext);
743                    }
744    
745                    return search(companyId, query, sorts, start, end);
746            }
747    
748            /**
749             * @deprecated As of 6.2.0, replaced by {@link #search(String, long, Query,
750             *             int, int)}
751             */
752            @Deprecated
753            public static Hits search(long companyId, Query query, int start, int end)
754                    throws SearchException {
755    
756                    return search(getDefaultSearchEngineId(), companyId, query, start, end);
757            }
758    
759            /**
760             * @deprecated As of 6.2.0, replaced by {@link #search(String, long, Query,
761             *             Sort, int, int)}
762             */
763            @Deprecated
764            public static Hits search(
765                            long companyId, Query query, Sort sort, int start, int end)
766                    throws SearchException {
767    
768                    return search(
769                            getDefaultSearchEngineId(), companyId, query, sort, start, end);
770            }
771    
772            /**
773             * @deprecated As of 6.2.0, replaced by {@link #search(String, long, Query,
774             *             Sort[], int, int)}
775             */
776            @Deprecated
777            public static Hits search(
778                            long companyId, Query query, Sort[] sorts, int start, int end)
779                    throws SearchException {
780    
781                    return search(
782                            getDefaultSearchEngineId(), companyId, query, sorts, start, end);
783            }
784    
785            public static Hits search(SearchContext searchContext, Query query)
786                    throws SearchException {
787    
788                    if (_log.isDebugEnabled()) {
789                            _log.debug("Search query " + query.toString());
790                    }
791    
792                    SearchEngine searchEngine = getSearchEngine(
793                            searchContext.getSearchEngineId());
794    
795                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
796    
797                    return indexSearcher.search(searchContext, query);
798            }
799    
800            /**
801             * @deprecated As of 7.0.0, replaced by {@link #search(SearchContext,
802             *             Query)}
803             */
804            @Deprecated
805            public static Hits search(
806                            String searchEngineId, long companyId, Query query, int start,
807                            int end)
808                    throws SearchException {
809    
810                    return search(
811                            searchEngineId, companyId, query, SortFactoryUtil.getDefaultSorts(),
812                            start, end);
813            }
814    
815            /**
816             * @deprecated As of 7.0.0, replaced by {@link #search(SearchContext,
817             *             Query)}
818             */
819            @Deprecated
820            public static Hits search(
821                            String searchEngineId, long companyId, Query query, Sort sort,
822                            int start, int end)
823                    throws SearchException {
824    
825                    return search(
826                            searchEngineId, companyId, query, new Sort[] {sort}, start, end);
827            }
828    
829            /**
830             * @deprecated As of 7.0.0, replaced by {@link #search(SearchContext,
831             *             Query)}
832             */
833            @Deprecated
834            public static Hits search(
835                            String searchEngineId, long companyId, Query query, Sort[] sorts,
836                            int start, int end)
837                    throws SearchException {
838    
839                    SearchContext searchContext = new SearchContext();
840    
841                    searchContext.setCompanyId(companyId);
842                    searchContext.setEnd(end);
843                    searchContext.setSearchEngineId(searchEngineId);
844                    searchContext.setSorts(sorts);
845                    searchContext.setStart(start);
846    
847                    return search(searchContext, query);
848            }
849    
850            public static void setDefaultSearchEngineId(String defaultSearchEngineId) {
851                    PortalRuntimePermission.checkSetBeanProperty(
852                            SearchEngineUtil.class, "defaultSearchEngineId");
853    
854                    _defaultSearchEngineId = defaultSearchEngineId;
855            }
856    
857            public static void setIndexReadOnly(boolean indexReadOnly) {
858                    PortalRuntimePermission.checkSetBeanProperty(
859                            SearchEngineUtil.class, "indexReadOnly");
860    
861                    _indexReadOnly = indexReadOnly;
862            }
863    
864            public static void setSearchEngine(
865                    String searchEngineId, SearchEngine searchEngine) {
866    
867                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
868    
869                    _searchEngines.put(searchEngineId, searchEngine);
870    
871                    for (Long companyId : _companyIds) {
872                            searchEngine.initialize(companyId);
873                    }
874            }
875    
876            public static String spellCheckKeywords(SearchContext searchContext)
877                    throws SearchException {
878    
879                    if (_log.isDebugEnabled()) {
880                            _log.debug("Spell checking " + searchContext.getKeywords());
881                    }
882    
883                    SearchEngine searchEngine = getSearchEngine(
884                            searchContext.getSearchEngineId());
885    
886                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
887    
888                    return indexSearcher.spellCheckKeywords(searchContext);
889            }
890    
891            public static Map<String, List<String>> spellCheckKeywords(
892                            SearchContext searchContext, int max)
893                    throws SearchException {
894    
895                    if (_log.isDebugEnabled()) {
896                            _log.debug("Spell checking " + searchContext.getKeywords());
897                    }
898    
899                    SearchEngine searchEngine = getSearchEngine(
900                            searchContext.getSearchEngineId());
901    
902                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
903    
904                    return indexSearcher.spellCheckKeywords(searchContext, max);
905            }
906    
907            public static String[] suggestKeywordQueries(
908                            SearchContext searchContext, int max)
909                    throws SearchException {
910    
911                    if (_log.isDebugEnabled()) {
912                            _log.debug(
913                                    "Suggesting keyword queries" + searchContext.getKeywords());
914                    }
915    
916                    SearchEngine searchEngine = getSearchEngine(
917                            searchContext.getSearchEngineId());
918    
919                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
920    
921                    return indexSearcher.suggestKeywordQueries(searchContext, max);
922            }
923    
924            /**
925             * @deprecated As of 6.2.0, replaced by {@link #updateDocument(String, long,
926             *             Document)}
927             */
928            @Deprecated
929            public static void updateDocument(long companyId, Document document)
930                    throws SearchException {
931    
932                    updateDocument(getSearchEngineId(document), companyId, document, true);
933            }
934    
935            /**
936             * @deprecated As of 7.0.0, replaced by {@link #updateDocument(String, long,
937             *             Document, boolean)}
938             */
939            @Deprecated
940            public static void updateDocument(
941                            String searchEngineId, long companyId, Document document)
942                    throws SearchException {
943    
944                    updateDocument(searchEngineId, companyId, document, false);
945            }
946    
947            public static void updateDocument(
948                            String searchEngineId, long companyId, Document document,
949                            boolean commitImmediately)
950                    throws SearchException {
951    
952                    if (isIndexReadOnly()) {
953                            return;
954                    }
955    
956                    if (_log.isDebugEnabled()) {
957                            _log.debug("Document " + document.toString());
958                    }
959    
960                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
961    
962                    IndexWriter indexWriter = searchEngine.getIndexWriter();
963    
964                    _searchPermissionChecker.addPermissionFields(companyId, document);
965    
966                    SearchContext searchContext = new SearchContext();
967    
968                    searchContext.setCommitImmediately(commitImmediately);
969                    searchContext.setCompanyId(companyId);
970                    searchContext.setSearchEngineId(searchEngineId);
971    
972                    indexWriter.updateDocument(searchContext, document);
973            }
974    
975            /**
976             * @deprecated As of 6.2.0, replaced by {@link #updateDocuments(String,
977             *             long, Collection)}
978             */
979            @Deprecated
980            public static void updateDocuments(
981                            long companyId, Collection<Document> documents)
982                    throws SearchException {
983    
984                    updateDocuments(
985                            getSearchEngineId(documents), companyId, documents, true);
986            }
987    
988            /**
989             * @deprecated As of 7.0.0, replaced by {@link #updateDocuments(String,
990             *             long, Collection, boolean)}
991             */
992            @Deprecated
993            public static void updateDocuments(
994                            String searchEngineId, long companyId,
995                            Collection<Document> documents)
996                    throws SearchException {
997    
998                    updateDocuments(searchEngineId, companyId, documents, false);
999            }
1000    
1001            public static void updateDocuments(
1002                            String searchEngineId, long companyId,
1003                            Collection<Document> documents, boolean commitImmediately)
1004                    throws SearchException {
1005    
1006                    if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
1007                            return;
1008                    }
1009    
1010                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
1011    
1012                    IndexWriter indexWriter = searchEngine.getIndexWriter();
1013    
1014                    for (Document document : documents) {
1015                            if (_log.isDebugEnabled()) {
1016                                    _log.debug("Document " + document.toString());
1017                            }
1018    
1019                            _searchPermissionChecker.addPermissionFields(companyId, document);
1020                    }
1021    
1022                    SearchContext searchContext = new SearchContext();
1023    
1024                    searchContext.setCommitImmediately(commitImmediately);
1025                    searchContext.setCompanyId(companyId);
1026                    searchContext.setSearchEngineId(searchEngineId);
1027    
1028                    indexWriter.updateDocuments(searchContext, documents);
1029            }
1030    
1031            public static void updatePermissionFields(String name, String primKey) {
1032                    if (isIndexReadOnly() || !PermissionThreadLocal.isFlushEnabled()) {
1033                            return;
1034                    }
1035    
1036                    _searchPermissionChecker.updatePermissionFields(name, primKey);
1037            }
1038    
1039            public void setExcludedEntryClassNames(
1040                    List<String> excludedEntryClassNames) {
1041    
1042                    PortalRuntimePermission.checkSetBeanProperty(
1043                            getClass(), "excludedEntryClassNames");
1044    
1045                    _excludedEntryClassNames.addAll(excludedEntryClassNames);
1046            }
1047    
1048            /**
1049             * @deprecated As of 6.2.0, replaced by {@link #setSearchEngine(String,
1050             *             SearchEngine)}
1051             */
1052            @Deprecated
1053            public void setSearchEngine(SearchEngine searchEngine) {
1054                    String searchEngineId = getDefaultSearchEngineId();
1055    
1056                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
1057    
1058                    setSearchEngine(searchEngineId, searchEngine);
1059            }
1060    
1061            public void setSearchPermissionChecker(
1062                    SearchPermissionChecker searchPermissionChecker) {
1063    
1064                    PortalRuntimePermission.checkSetBeanProperty(
1065                            getClass(), "searchPermissionChecker");
1066    
1067                    _searchPermissionChecker = searchPermissionChecker;
1068            }
1069    
1070            private static void waitForSystemSearchEngine() {
1071                    try {
1072                            int count = 1000;
1073    
1074                            while (!_searchEngines.containsKey(SYSTEM_ENGINE_ID) &&
1075                                       (--count > 0)) {
1076    
1077                                    if (_log.isDebugEnabled()) {
1078                                            _log.debug("Waiting for search engine " + SYSTEM_ENGINE_ID);
1079                                    }
1080    
1081                                    Thread.sleep(500);
1082                            }
1083                    }
1084                    catch (InterruptedException ie) {
1085                            _log.error(ie, ie);
1086                    }
1087            }
1088    
1089            private SearchEngineUtil() {
1090                    Registry registry = RegistryUtil.getRegistry();
1091    
1092                    _serviceTracker = registry.trackServices(
1093                            SearchEngineConfigurator.class,
1094                            new SearchEngineConfiguratorServiceTrackerCustomizer());
1095    
1096                    _serviceTracker.open();
1097            }
1098    
1099            private static Log _log = LogFactoryUtil.getLog(SearchEngineUtil.class);
1100    
1101            private static Set<Long> _companyIds = new HashSet<Long>();
1102            private static String _defaultSearchEngineId;
1103            private static Set<String> _excludedEntryClassNames = new HashSet<String>();
1104            private static boolean _indexReadOnly = GetterUtil.getBoolean(
1105                    PropsUtil.get(PropsKeys.INDEX_READ_ONLY));
1106            private static Map<String, SearchEngine> _searchEngines =
1107                    new ConcurrentHashMap<String, SearchEngine>();
1108            private static SearchPermissionChecker _searchPermissionChecker;
1109    
1110            private ServiceTracker<SearchEngineConfigurator, SearchEngineConfigurator>
1111                    _serviceTracker;
1112    
1113            private class SearchEngineConfiguratorServiceTrackerCustomizer
1114                    implements ServiceTrackerCustomizer
1115                            <SearchEngineConfigurator, SearchEngineConfigurator> {
1116    
1117                    @Override
1118                    public SearchEngineConfigurator addingService(
1119                            ServiceReference<SearchEngineConfigurator> serviceReference) {
1120    
1121                            Registry registry = RegistryUtil.getRegistry();
1122    
1123                            SearchEngineConfigurator searchEngineConfigurator =
1124                                    registry.getService(serviceReference);
1125    
1126                            searchEngineConfigurator.afterPropertiesSet();
1127    
1128                            return searchEngineConfigurator;
1129                    }
1130    
1131                    @Override
1132                    public void modifiedService(
1133                            ServiceReference<SearchEngineConfigurator> serviceReference,
1134                            SearchEngineConfigurator searchEngineConfigurator) {
1135                    }
1136    
1137                    @Override
1138                    public void removedService(
1139                            ServiceReference<SearchEngineConfigurator> serviceReference,
1140                            SearchEngineConfigurator searchEngineConfigurator) {
1141    
1142                            Registry registry = RegistryUtil.getRegistry();
1143    
1144                            registry.ungetService(serviceReference);
1145    
1146                            searchEngineConfigurator.destroy();
1147                    }
1148    
1149            }
1150    
1151    }