001    /**
002     * Copyright (c) 2000-2013 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.Map;
031    import java.util.Set;
032    import java.util.concurrent.ConcurrentHashMap;
033    
034    /**
035     * @author Bruno Farache
036     * @author Raymond Aug??
037     * @author Michael C. Han
038     */
039    public class SearchEngineUtil {
040    
041            /**
042             * @deprecated {@link com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS}
043             */
044            public static final int ALL_POS = -1;
045    
046            public static final String GENERIC_ENGINE_ID = "GENERIC_ENGINE";
047    
048            public static final String SYSTEM_ENGINE_ID = "SYSTEM_ENGINE";
049    
050            /**
051             * @deprecated {@link #addDocument(String, long, Document)}
052             */
053            public static void addDocument(long companyId, Document document)
054                    throws SearchException {
055    
056                    addDocument(_getSearchEngineId(document), companyId, document);
057            }
058    
059            public static void addDocument(
060                            String searchEngineId, long companyId, Document document)
061                    throws SearchException {
062    
063                    if (isIndexReadOnly()) {
064                            return;
065                    }
066    
067                    if (_log.isDebugEnabled()) {
068                            _log.debug("Add document " + document.toString());
069                    }
070    
071                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
072    
073                    IndexWriter indexWriter = searchEngine.getIndexWriter();
074    
075                    _searchPermissionChecker.addPermissionFields(companyId, document);
076    
077                    SearchContext searchContext = new SearchContext();
078    
079                    searchContext.setCompanyId(companyId);
080                    searchContext.setSearchEngineId(searchEngineId);
081    
082                    indexWriter.addDocument(searchContext, document);
083            }
084    
085            /**
086             * @deprecated {@link #addDocuments(String, long, Collection)}
087             */
088            public static void addDocuments(
089                            long companyId, Collection<Document> documents)
090                    throws SearchException {
091    
092                    addDocuments(_getSearchEngineId(documents), companyId, documents);
093            }
094    
095            public static void addDocuments(
096                            String searchEngineId, long companyId,
097                            Collection<Document> documents)
098                    throws SearchException {
099    
100                    if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
101                            return;
102                    }
103    
104                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
105    
106                    IndexWriter indexWriter = searchEngine.getIndexWriter();
107    
108                    for (Document document : documents) {
109                            if (_log.isDebugEnabled()) {
110                                    _log.debug("Add document " + document.toString());
111                            }
112    
113                            _searchPermissionChecker.addPermissionFields(companyId, document);
114                    }
115    
116                    SearchContext searchContext = new SearchContext();
117    
118                    searchContext.setCompanyId(companyId);
119                    searchContext.setSearchEngineId(searchEngineId);
120    
121                    indexWriter.addDocuments(searchContext, documents);
122            }
123    
124            /**
125             * @deprecated {@link #setSearchEngine(String, SearchEngine)}
126             */
127            public static void addSearchEngine(SearchEngine searchEngine) {
128                    String searchEngineId = getDefaultSearchEngineId();
129    
130                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
131    
132                    _searchEngines.put(searchEngineId, searchEngine);
133            }
134    
135            /**
136             * @deprecated {@link #deleteDocument(String, long, String)}
137             */
138            public static void deleteDocument(long companyId, String uid)
139                    throws SearchException {
140    
141                    for (String searchEngineId : _searchEngines.keySet()) {
142                            deleteDocument(searchEngineId, companyId, uid);
143                    }
144            }
145    
146            public static void deleteDocument(
147                            String searchEngineId, long companyId, String uid)
148                    throws SearchException {
149    
150                    if (isIndexReadOnly()) {
151                            return;
152                    }
153    
154                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
155    
156                    IndexWriter indexWriter = searchEngine.getIndexWriter();
157    
158                    SearchContext searchContext = new SearchContext();
159    
160                    searchContext.setCompanyId(companyId);
161                    searchContext.setSearchEngineId(searchEngineId);
162    
163                    indexWriter.deleteDocument(searchContext, uid);
164            }
165    
166            /**
167             * @deprecated {@link #deleteDocuments(String, long, Collection)}
168             */
169            public static void deleteDocuments(long companyId, Collection<String> uids)
170                    throws SearchException {
171    
172                    for (String searchEngineId : _searchEngines.keySet()) {
173                            deleteDocuments(searchEngineId, companyId, uids);
174                    }
175            }
176    
177            public static void deleteDocuments(
178                            String searchEngineId, long companyId, Collection<String> uids)
179                    throws SearchException {
180    
181                    if (isIndexReadOnly() || (uids == null) || uids.isEmpty()) {
182                            return;
183                    }
184    
185                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
186    
187                    IndexWriter indexWriter = searchEngine.getIndexWriter();
188    
189                    SearchContext searchContext = new SearchContext();
190    
191                    searchContext.setCompanyId(companyId);
192                    searchContext.setSearchEngineId(searchEngineId);
193    
194                    indexWriter.deleteDocuments(searchContext, uids);
195            }
196    
197            /**
198             * @deprecated {@link #deletePortletDocuments(String, long, String)}
199             */
200            public static void deletePortletDocuments(long companyId, String portletId)
201                    throws SearchException {
202    
203                    for (String searchEngineId : _searchEngines.keySet()) {
204                            deletePortletDocuments(searchEngineId, companyId, portletId);
205                    }
206            }
207    
208            public static void deletePortletDocuments(
209                            String searchEngineId, long companyId, String portletId)
210                    throws SearchException {
211    
212                    if (isIndexReadOnly()) {
213                            return;
214                    }
215    
216                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
217    
218                    if (searchEngine == null) {
219                            return;
220                    }
221    
222                    IndexWriter indexWriter = searchEngine.getIndexWriter();
223    
224                    SearchContext searchContext = new SearchContext();
225    
226                    searchContext.setCompanyId(companyId);
227                    searchContext.setSearchEngineId(searchEngineId);
228    
229                    indexWriter.deletePortletDocuments(searchContext, portletId);
230            }
231    
232            public static String getDefaultSearchEngineId() {
233                    if (_defaultSearchEngineId == null) {
234                            return SYSTEM_ENGINE_ID;
235                    }
236    
237                    return _defaultSearchEngineId;
238            }
239    
240            public static String[] getEntryClassNames() {
241                    Set<String> assetEntryClassNames = new HashSet<String>();
242    
243                    for (Indexer indexer : IndexerRegistryUtil.getIndexers()) {
244                            for (String className : indexer.getClassNames()) {
245                                    if (!_excludedEntryClassNames.contains(className)) {
246                                            assetEntryClassNames.add(className);
247                                    }
248                            }
249                    }
250    
251                    return assetEntryClassNames.toArray(
252                            new String[assetEntryClassNames.size()]);
253            }
254    
255            /**
256             * @deprecated {@link #getSearchEngine(String)}
257             */
258            public static SearchEngine getSearchEngine() {
259                    return getSearchEngine(getDefaultSearchEngineId());
260            }
261    
262            public static SearchEngine getSearchEngine(String searchEngineId) {
263                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
264    
265                    SearchEngine searchEngine = _searchEngines.get(searchEngineId);
266    
267                    if (searchEngine == null) {
268                            if (getDefaultSearchEngineId().equals(searchEngineId)) {
269                                    throw new IllegalStateException(
270                                            "There is no default search engine configured with ID " +
271                                                    getDefaultSearchEngineId());
272                            }
273    
274                            if (_log.isWarnEnabled()) {
275                                    _log.warn(
276                                            "There is no search engine configured with ID " +
277                                                    searchEngineId);
278                            }
279                    }
280    
281                    return searchEngine;
282            }
283    
284            public static Set<String> getSearchEngineIds() {
285                    PortalRuntimePermission.checkGetBeanProperty(
286                            SearchEngineUtil.class, "searchEngineIds");
287    
288                    return _searchEngines.keySet();
289            }
290    
291            public static SearchEngine getSearchEngineSilent(String searchEngineId) {
292                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
293    
294                    return _searchEngines.get(searchEngineId);
295            }
296    
297            public static SearchPermissionChecker getSearchPermissionChecker() {
298                    PortalRuntimePermission.checkGetBeanProperty(
299                            SearchEngineUtil.class, "searchPermissionChecker");
300    
301                    return _searchPermissionChecker;
302            }
303    
304            public static String getSearchReaderDestinationName(String searchEngineId) {
305                    return DestinationNames.SEARCH_READER.concat(StringPool.SLASH).concat(
306                            searchEngineId);
307            }
308    
309            public static String getSearchWriterDestinationName(String searchEngineId) {
310                    return DestinationNames.SEARCH_WRITER.concat(StringPool.SLASH).concat(
311                            searchEngineId);
312            }
313    
314            public static boolean isIndexReadOnly() {
315                    PortalRuntimePermission.checkGetBeanProperty(
316                            SearchEngineUtil.class, "indexReadOnly");
317    
318                    return _indexReadOnly;
319            }
320    
321            public static SearchEngine removeSearchEngine(String searchEngineId) {
322                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
323    
324                    return _searchEngines.remove(searchEngineId);
325            }
326    
327            /**
328             * @deprecated
329             */
330            public static Hits search(
331                            long companyId, long[] groupIds, long userId, String className,
332                            Query query, int start, int end)
333                    throws SearchException {
334    
335                    SearchContext searchContext = new SearchContext();
336    
337                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
338    
339                    if (userId > 0) {
340                            query = _searchPermissionChecker.getPermissionQuery(
341                                    companyId, groupIds, userId, className, query, searchContext);
342                    }
343    
344                    return search(
345                            companyId, query, SortFactoryUtil.getDefaultSorts(), start, end);
346            }
347    
348            /**
349             * @deprecated
350             */
351            public static Hits search(
352                            long companyId, long[] groupIds, long userId, String className,
353                            Query query, Sort sort, int start, int end)
354                    throws SearchException {
355    
356                    SearchContext searchContext = new SearchContext();
357    
358                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
359    
360                    if (userId > 0) {
361                            query = _searchPermissionChecker.getPermissionQuery(
362                                    companyId, groupIds, userId, className, query, searchContext);
363                    }
364    
365                    return search(companyId, query, sort, start, end);
366            }
367    
368            /**
369             * @deprecated
370             */
371            public static Hits search(
372                            long companyId, long[] groupIds, long userId, String className,
373                            Query query, Sort[] sorts, int start, int end)
374                    throws SearchException {
375    
376                    SearchContext searchContext = new SearchContext();
377    
378                    searchContext.setSearchEngineId(getDefaultSearchEngineId());
379    
380                    if (userId > 0) {
381                            query = _searchPermissionChecker.getPermissionQuery(
382                                    companyId, groupIds, userId, className, query, searchContext);
383                    }
384    
385                    return search(companyId, query, sorts, start, end);
386            }
387    
388            /**
389             * @deprecated {@link #search(String, long, Query, int, int)}
390             */
391            public static Hits search(long companyId, Query query, int start, int end)
392                    throws SearchException {
393    
394                    return search(getDefaultSearchEngineId(), companyId, query, start, end);
395            }
396    
397            /**
398             * @deprecated {@link #search(String, long, Query, Sort, int, int)}
399             */
400            public static Hits search(
401                            long companyId, Query query, Sort sort, int start, int end)
402                    throws SearchException {
403    
404                    return search(
405                            getDefaultSearchEngineId(), companyId, query, sort, start, end);
406            }
407    
408            /**
409             * @deprecated {@link #search(String, long, Query, Sort[], int, int)}
410             */
411            public static Hits search(
412                            long companyId, Query query, Sort[] sorts, int start, int end)
413                    throws SearchException {
414    
415                    return search(
416                            getDefaultSearchEngineId(), companyId, query, sorts, start, end);
417            }
418    
419            public static Hits search(SearchContext searchContext, Query query)
420                    throws SearchException {
421    
422                    if (_log.isDebugEnabled()) {
423                            _log.debug("Search query " + query.toString());
424                    }
425    
426                    SearchEngine searchEngine = getSearchEngine(
427                            searchContext.getSearchEngineId());
428    
429                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
430    
431                    return indexSearcher.search(searchContext, query);
432            }
433    
434            public static Hits search(
435                            String searchEngineId, long companyId, Query query, int start,
436                            int end)
437                    throws SearchException {
438    
439                    if (_log.isDebugEnabled()) {
440                            _log.debug("Search query " + query.toString());
441                    }
442    
443                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
444    
445                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
446    
447                    return indexSearcher.search(
448                            searchEngineId, companyId, query, SortFactoryUtil.getDefaultSorts(),
449                            start, end);
450            }
451    
452            public static Hits search(
453                            String searchEngineId, long companyId, Query query, Sort sort,
454                            int start, int end)
455                    throws SearchException {
456    
457                    if (_log.isDebugEnabled()) {
458                            _log.debug("Search query " + query.toString());
459                    }
460    
461                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
462    
463                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
464    
465                    return indexSearcher.search(
466                            searchEngineId, companyId, query, new Sort[] {sort}, start, end);
467            }
468    
469            public static Hits search(
470                            String searchEngineId, long companyId, Query query, Sort[] sorts,
471                            int start, int end)
472                    throws SearchException {
473    
474                    if (_log.isDebugEnabled()) {
475                            _log.debug("Search query " + query.toString());
476                    }
477    
478                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
479    
480                    IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
481    
482                    return indexSearcher.search(
483                            searchEngineId, companyId, query, sorts, start, end);
484            }
485    
486            public static void setDefaultSearchEngineId(String defaultSearchEngineId) {
487                    PortalRuntimePermission.checkSetBeanProperty(
488                            SearchEngineUtil.class, "defaultSearchEngineId");
489    
490                    _defaultSearchEngineId = defaultSearchEngineId;
491            }
492    
493            public static void setIndexReadOnly(boolean indexReadOnly) {
494                    PortalRuntimePermission.checkSetBeanProperty(
495                            SearchEngineUtil.class, "indexReadOnly");
496    
497                    _indexReadOnly = indexReadOnly;
498            }
499    
500            public static void setSearchEngine(
501                    String searchEngineId, SearchEngine searchEngine) {
502    
503                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
504    
505                    _searchEngines.put(searchEngineId, searchEngine);
506            }
507    
508            /**
509             * @deprecated {@link #updateDocument(String, long, Document)}
510             */
511            public static void updateDocument(long companyId, Document document)
512                    throws SearchException {
513    
514                    updateDocument(_getSearchEngineId(document), companyId, document);
515            }
516    
517            public static void updateDocument(
518                            String searchEngineId, long companyId, Document document)
519                    throws SearchException {
520    
521                    if (isIndexReadOnly()) {
522                            return;
523                    }
524    
525                    if (_log.isDebugEnabled()) {
526                            _log.debug("Document " + document.toString());
527                    }
528    
529                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
530    
531                    IndexWriter indexWriter = searchEngine.getIndexWriter();
532    
533                    _searchPermissionChecker.addPermissionFields(companyId, document);
534    
535                    SearchContext searchContext = new SearchContext();
536    
537                    searchContext.setCompanyId(companyId);
538                    searchContext.setSearchEngineId(searchEngineId);
539    
540                    indexWriter.updateDocument(searchContext, document);
541            }
542    
543            /**
544             * @deprecated {@link #updateDocuments(String, long, Collection)}
545             */
546            public static void updateDocuments(
547                            long companyId, Collection<Document> documents)
548                    throws SearchException {
549    
550                    updateDocuments(_getSearchEngineId(documents), companyId, documents);
551            }
552    
553            public static void updateDocuments(
554                            String searchEngineId, long companyId,
555                            Collection<Document> documents)
556                    throws SearchException {
557    
558                    if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
559                            return;
560                    }
561    
562                    SearchEngine searchEngine = getSearchEngine(searchEngineId);
563    
564                    IndexWriter indexWriter = searchEngine.getIndexWriter();
565    
566                    for (Document document : documents) {
567                            if (_log.isDebugEnabled()) {
568                                    _log.debug("Document " + document.toString());
569                            }
570    
571                            _searchPermissionChecker.addPermissionFields(companyId, document);
572                    }
573    
574                    SearchContext searchContext = new SearchContext();
575    
576                    searchContext.setCompanyId(companyId);
577                    searchContext.setSearchEngineId(searchEngineId);
578    
579                    indexWriter.updateDocuments(searchContext, documents);
580            }
581    
582            public static void updatePermissionFields(long resourceId) {
583                    if (isIndexReadOnly() || !PermissionThreadLocal.isFlushEnabled()) {
584                            return;
585                    }
586    
587                    _searchPermissionChecker.updatePermissionFields(resourceId);
588            }
589    
590            public static void updatePermissionFields(String name, String primKey) {
591                    if (isIndexReadOnly() || !PermissionThreadLocal.isFlushEnabled()) {
592                            return;
593                    }
594    
595                    _searchPermissionChecker.updatePermissionFields(name, primKey);
596            }
597    
598            public void setExcludedEntryClassNames(
599                    List<String> excludedEntryClassNames) {
600    
601                    PortalRuntimePermission.checkSetBeanProperty(
602                            getClass(), "excludedEntryClassNames");
603    
604                    _excludedEntryClassNames.addAll(excludedEntryClassNames);
605            }
606    
607            /**
608             * @deprecated {@link #setSearchEngine(String, SearchEngine)}
609             */
610            public void setSearchEngine(SearchEngine searchEngine) {
611                    String searchEngineId = getDefaultSearchEngineId();
612    
613                    PortalRuntimePermission.checkSearchEngine(searchEngineId);
614    
615                    _searchEngines.put(searchEngineId, searchEngine);
616            }
617    
618            public void setSearchPermissionChecker(
619                    SearchPermissionChecker searchPermissionChecker) {
620    
621                    PortalRuntimePermission.checkSetBeanProperty(
622                            getClass(), "searchPermissionChecker");
623    
624                    _searchPermissionChecker = searchPermissionChecker;
625            }
626    
627            private static String _getSearchEngineId(Collection<Document> documents) {
628                    if (!documents.isEmpty()) {
629                            Document document = documents.iterator().next();
630    
631                            return _getSearchEngineId(document);
632                    }
633    
634                    return getDefaultSearchEngineId();
635            }
636    
637            private static String _getSearchEngineId(Document document) {
638                    String entryClassName = document.get("entryClassName");
639    
640                    Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
641    
642                    String searchEngineId = indexer.getSearchEngineId();
643    
644                    if (_log.isDebugEnabled()) {
645                            _log.debug(
646                                    "Search engine ID for " + indexer.getClass() + " is " +
647                                            searchEngineId);
648                    }
649    
650                    return searchEngineId;
651            }
652    
653            private static Log _log = LogFactoryUtil.getLog(SearchEngineUtil.class);
654    
655            private static String _defaultSearchEngineId;
656            private static Set<String> _excludedEntryClassNames = new HashSet<String>();
657            private static boolean _indexReadOnly = GetterUtil.getBoolean(
658                    PropsUtil.get(PropsKeys.INDEX_READ_ONLY));
659            private static Map<String, SearchEngine> _searchEngines =
660                    new ConcurrentHashMap<String, SearchEngine>();
661            private static SearchPermissionChecker _searchPermissionChecker;
662    
663    }