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.NoSuchCountryException;
018    import com.liferay.portal.NoSuchModelException;
019    import com.liferay.portal.NoSuchRegionException;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.language.LanguageUtil;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.search.facet.AssetEntriesFacet;
025    import com.liferay.portal.kernel.search.facet.Facet;
026    import com.liferay.portal.kernel.search.facet.MultiValueFacet;
027    import com.liferay.portal.kernel.search.facet.ScopeFacet;
028    import com.liferay.portal.kernel.search.filter.BooleanFilter;
029    import com.liferay.portal.kernel.search.filter.Filter;
030    import com.liferay.portal.kernel.search.filter.QueryFilter;
031    import com.liferay.portal.kernel.search.filter.TermsFilter;
032    import com.liferay.portal.kernel.search.generic.BooleanQueryImpl;
033    import com.liferay.portal.kernel.search.generic.MatchAllQuery;
034    import com.liferay.portal.kernel.search.hits.HitsProcessor;
035    import com.liferay.portal.kernel.search.hits.HitsProcessorRegistryUtil;
036    import com.liferay.portal.kernel.trash.TrashHandler;
037    import com.liferay.portal.kernel.trash.TrashRenderer;
038    import com.liferay.portal.kernel.util.ArrayUtil;
039    import com.liferay.portal.kernel.util.GetterUtil;
040    import com.liferay.portal.kernel.util.ListUtil;
041    import com.liferay.portal.kernel.util.LocaleUtil;
042    import com.liferay.portal.kernel.util.LocalizationUtil;
043    import com.liferay.portal.kernel.util.PropsKeys;
044    import com.liferay.portal.kernel.util.PropsUtil;
045    import com.liferay.portal.kernel.util.SetUtil;
046    import com.liferay.portal.kernel.util.StringPool;
047    import com.liferay.portal.kernel.util.StringUtil;
048    import com.liferay.portal.kernel.util.UnicodeProperties;
049    import com.liferay.portal.kernel.util.Validator;
050    import com.liferay.portal.kernel.workflow.WorkflowConstants;
051    import com.liferay.portal.model.Address;
052    import com.liferay.portal.model.AttachedModel;
053    import com.liferay.portal.model.AuditedModel;
054    import com.liferay.portal.model.BaseModel;
055    import com.liferay.portal.model.Country;
056    import com.liferay.portal.model.Group;
057    import com.liferay.portal.model.GroupedModel;
058    import com.liferay.portal.model.Region;
059    import com.liferay.portal.model.ResourcedModel;
060    import com.liferay.portal.model.TrashedModel;
061    import com.liferay.portal.model.User;
062    import com.liferay.portal.model.WorkflowedModel;
063    import com.liferay.portal.security.permission.PermissionChecker;
064    import com.liferay.portal.security.permission.PermissionThreadLocal;
065    import com.liferay.portal.service.CountryServiceUtil;
066    import com.liferay.portal.service.GroupLocalServiceUtil;
067    import com.liferay.portal.service.RegionServiceUtil;
068    import com.liferay.portal.service.ServiceContext;
069    import com.liferay.portal.service.ServiceContextThreadLocal;
070    import com.liferay.portal.service.UserLocalServiceUtil;
071    import com.liferay.portal.util.PortalUtil;
072    import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
073    import com.liferay.portlet.asset.model.AssetCategory;
074    import com.liferay.portlet.asset.model.AssetEntry;
075    import com.liferay.portlet.asset.model.AssetRendererFactory;
076    import com.liferay.portlet.asset.model.AssetTag;
077    import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
078    import com.liferay.portlet.asset.service.AssetEntryLocalServiceUtil;
079    import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
080    import com.liferay.portlet.expando.model.ExpandoBridge;
081    import com.liferay.portlet.expando.model.ExpandoColumn;
082    import com.liferay.portlet.expando.model.ExpandoColumnConstants;
083    import com.liferay.portlet.expando.service.ExpandoColumnLocalServiceUtil;
084    import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;
085    import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
086    import com.liferay.portlet.ratings.model.RatingsStats;
087    import com.liferay.portlet.ratings.service.RatingsStatsLocalServiceUtil;
088    import com.liferay.portlet.trash.model.TrashEntry;
089    
090    import java.io.Serializable;
091    
092    import java.util.ArrayList;
093    import java.util.Collection;
094    import java.util.Collections;
095    import java.util.Date;
096    import java.util.HashMap;
097    import java.util.HashSet;
098    import java.util.List;
099    import java.util.Locale;
100    import java.util.Map;
101    import java.util.Set;
102    
103    import javax.portlet.PortletRequest;
104    import javax.portlet.PortletResponse;
105    
106    /**
107     * @author Brian Wing Shun Chan
108     * @author Hugo Huijser
109     * @author Ryan Park
110     * @author Raymond Aug??
111     */
112    public abstract class BaseIndexer implements Indexer {
113    
114            @Override
115            public void delete(long companyId, String uid) throws SearchException {
116                    try {
117                            SearchEngineUtil.deleteDocument(
118                                    getSearchEngineId(), companyId, uid, _commitImmediately);
119                    }
120                    catch (SearchException se) {
121                            throw se;
122                    }
123                    catch (Exception e) {
124                            throw new SearchException(e);
125                    }
126            }
127    
128            @Override
129            public void delete(Object obj) throws SearchException {
130                    try {
131                            doDelete(obj);
132                    }
133                    catch (SearchException se) {
134                            throw se;
135                    }
136                    catch (Exception e) {
137                            throw new SearchException(e);
138                    }
139            }
140    
141            /**
142             * @deprecated As of 7.0.0, replaced by {@link #getSearchClassNames}
143             */
144            @Deprecated
145            @Override
146            public String[] getClassNames() {
147                    return getSearchClassNames();
148            }
149    
150            @Override
151            public Document getDocument(Object obj) throws SearchException {
152                    try {
153                            Document document = doGetDocument(obj);
154    
155                            for (IndexerPostProcessor indexerPostProcessor :
156                                            _indexerPostProcessors) {
157    
158                                    indexerPostProcessor.postProcessDocument(document, obj);
159                            }
160    
161                            if (document == null) {
162                                    return null;
163                            }
164    
165                            Map<String, Field> fields = document.getFields();
166    
167                            Field groupIdField = fields.get(Field.GROUP_ID);
168    
169                            if (groupIdField != null) {
170                                    long groupId = GetterUtil.getLong(groupIdField.getValue());
171    
172                                    addStagingGroupKeyword(document, groupId);
173                            }
174    
175                            return document;
176                    }
177                    catch (SearchException se) {
178                            throw se;
179                    }
180                    catch (Exception e) {
181                            throw new SearchException(e);
182                    }
183            }
184    
185            @Override
186            public BooleanFilter getFacetBooleanFilter(
187                            String className, SearchContext searchContext)
188                    throws Exception {
189    
190                    BooleanFilter facetBooleanFilter = new BooleanFilter();
191    
192                    facetBooleanFilter.addTerm(Field.ENTRY_CLASS_NAME, className);
193    
194                    if (searchContext.getUserId() > 0) {
195                            SearchPermissionChecker searchPermissionChecker =
196                                    SearchEngineUtil.getSearchPermissionChecker();
197    
198                            long[] groupIds = searchContext.getGroupIds();
199    
200                            long groupId = GetterUtil.getLong(
201                                    searchContext.getAttribute("groupId"));
202    
203                            if (groupId > 0) {
204                                    groupIds = new long[] {groupId};
205                            }
206    
207                            facetBooleanFilter =
208                                    searchPermissionChecker.getPermissionBooleanFilter(
209                                            searchContext.getCompanyId(), groupIds,
210                                    searchContext.getUserId(), className, facetBooleanFilter,
211                                    searchContext);
212                    }
213    
214                    return facetBooleanFilter;
215            }
216    
217            @Override
218            public BooleanQuery getFullQuery(SearchContext searchContext)
219                    throws SearchException {
220    
221                    try {
222                            searchContext.setSearchEngineId(getSearchEngineId());
223    
224                            resetFullQuery(searchContext);
225    
226                            String[] fullQueryEntryClassNames =
227                                    searchContext.getFullQueryEntryClassNames();
228    
229                            if (ArrayUtil.isNotEmpty(fullQueryEntryClassNames)) {
230                                    searchContext.setAttribute(
231                                            "relatedEntryClassNames", getSearchClassNames());
232                            }
233    
234                            String[] entryClassNames = ArrayUtil.append(
235                                    getSearchClassNames(), fullQueryEntryClassNames);
236    
237                            searchContext.setEntryClassNames(entryClassNames);
238    
239                            BooleanFilter fullQueryBooleanFilter = new BooleanFilter();
240    
241                            addSearchAssetCategoryIds(fullQueryBooleanFilter, searchContext);
242                            addSearchAssetTagNames(fullQueryBooleanFilter, searchContext);
243                            addSearchEntryClassNames(fullQueryBooleanFilter, searchContext);
244                            addSearchFolderId(fullQueryBooleanFilter, searchContext);
245                            addSearchGroupId(fullQueryBooleanFilter, searchContext);
246                            addSearchLayout(fullQueryBooleanFilter, searchContext);
247                            addSearchUserId(fullQueryBooleanFilter, searchContext);
248    
249                            BooleanQuery fullQuery = createFullQuery(
250                                    fullQueryBooleanFilter, searchContext);
251    
252                            fullQuery.setQueryConfig(searchContext.getQueryConfig());
253    
254                            return fullQuery;
255                    }
256                    catch (SearchException se) {
257                            throw se;
258                    }
259                    catch (Exception e) {
260                            throw new SearchException(e);
261                    }
262            }
263    
264            @Override
265            public IndexerPostProcessor[] getIndexerPostProcessors() {
266                    return _indexerPostProcessors;
267            }
268    
269            /**
270             * @deprecated As of 7.0.0, replaced by {@link #getClassName}
271             */
272            @Deprecated
273            @Override
274            public String getPortletId() {
275                    return StringPool.BLANK;
276            }
277    
278            @Override
279            public String[] getSearchClassNames() {
280                    return new String[] {getClassName()};
281            }
282    
283            @Override
284            public String getSearchEngineId() {
285                    if (_searchEngineId != null) {
286                            return _searchEngineId;
287                    }
288    
289                    Class<?> clazz = getClass();
290    
291                    String searchEngineId = GetterUtil.getString(
292                            PropsUtil.get(
293                                    PropsKeys.INDEX_SEARCH_ENGINE_ID,
294                                    new com.liferay.portal.kernel.configuration.Filter(
295                                            clazz.getName())));
296    
297                    if (Validator.isNotNull(searchEngineId)) {
298                            SearchEngine searchEngine = SearchEngineUtil.getSearchEngine(
299                                    searchEngineId);
300    
301                            if (searchEngine != null) {
302                                    _searchEngineId = searchEngineId;
303                            }
304                    }
305    
306                    if (_searchEngineId == null) {
307                            _searchEngineId = SearchEngineUtil.getDefaultSearchEngineId();
308                    }
309    
310                    if (_log.isDebugEnabled()) {
311                            _log.debug(
312                                    "Search engine ID for " + clazz.getName() + " is " +
313                                            searchEngineId);
314                    }
315    
316                    return _searchEngineId;
317            }
318    
319            @Override
320            public String getSortField(String orderByCol) {
321                    String sortField = doGetSortField(orderByCol);
322    
323                    if (_document.isDocumentSortableTextField(sortField)) {
324                            return DocumentImpl.getSortableFieldName(sortField);
325                    }
326    
327                    return sortField;
328            }
329    
330            @Override
331            public String getSortField(String orderByCol, int sortType) {
332                    if ((sortType == Sort.DOUBLE_TYPE) || (sortType == Sort.FLOAT_TYPE) ||
333                            (sortType == Sort.INT_TYPE) || (sortType == Sort.LONG_TYPE)) {
334    
335                            return DocumentImpl.getSortableFieldName(orderByCol);
336                    }
337    
338                    return getSortField(orderByCol);
339            }
340    
341            /**
342             * @deprecated As of 7.0.0, replaced by {@link #getSummary(Document, String,
343             *             PortletRequest, PortletResponse)}
344             */
345            @Deprecated
346            @Override
347            public Summary getSummary(Document document, Locale locale, String snippet)
348                    throws SearchException {
349    
350                    return getSummary(document, snippet, null, null);
351            }
352    
353            @Override
354            public Summary getSummary(
355                            Document document, String snippet, PortletRequest portletRequest,
356                            PortletResponse portletResponse)
357                    throws SearchException {
358    
359                    try {
360                            Locale locale = getLocale(portletRequest);
361    
362                            Summary summary = doGetSummary(
363                                    document, locale, snippet, portletRequest, portletResponse);
364    
365                            for (IndexerPostProcessor indexerPostProcessor :
366                                            _indexerPostProcessors) {
367    
368                                    indexerPostProcessor.postProcessSummary(
369                                            summary, document, locale, snippet);
370                            }
371    
372                            return summary;
373                    }
374                    catch (SearchException se) {
375                            throw se;
376                    }
377                    catch (Exception e) {
378                            throw new SearchException(e);
379                    }
380            }
381    
382            @Override
383            public boolean hasPermission(
384                            PermissionChecker permissionChecker, String entryClassName,
385                            long entryClassPK, String actionId)
386                    throws Exception {
387    
388                    return true;
389            }
390    
391            @Override
392            public boolean isCommitImmediately() {
393                    return _commitImmediately;
394            }
395    
396            @Override
397            public boolean isFilterSearch() {
398                    return _filterSearch;
399            }
400    
401            public boolean isIndexerEnabled() {
402                    return _indexerEnabled;
403            }
404    
405            @Override
406            public boolean isPermissionAware() {
407                    return _permissionAware;
408            }
409    
410            public boolean isSelectAllLocales() {
411                    return _selectAllLocales;
412            }
413    
414            @Override
415            public boolean isStagingAware() {
416                    return _stagingAware;
417            }
418    
419            @Override
420            public boolean isVisible(long classPK, int status) throws Exception {
421                    return true;
422            }
423    
424            @Override
425            public boolean isVisibleRelatedEntry(long classPK, int status)
426                    throws Exception {
427    
428                    return true;
429            }
430    
431            @Override
432            public void postProcessContextBooleanFilter(
433                            BooleanFilter contextBooleanFilter, SearchContext searchContext)
434                    throws Exception {
435            }
436    
437            /**
438             * @deprecated As of 7.0.0, replaced by {@link #postProcessContextBooleanFilter(
439             *             BooleanFilter, SearchContext)}
440             */
441            @Deprecated
442            @Override
443            public void postProcessContextQuery(
444                            BooleanQuery contextQuery, SearchContext searchContext)
445                    throws Exception {
446            }
447    
448            @Override
449            public void postProcessSearchQuery(
450                            BooleanQuery searchQuery, BooleanFilter fullQueryBooleanFilter,
451                            SearchContext searchContext)
452                    throws Exception {
453    
454                    String keywords = searchContext.getKeywords();
455    
456                    if (Validator.isNull(keywords)) {
457                            addSearchTerm(searchQuery, searchContext, Field.DESCRIPTION, false);
458                            addSearchTerm(searchQuery, searchContext, Field.TITLE, false);
459                            addSearchTerm(searchQuery, searchContext, Field.USER_NAME, false);
460                    }
461            }
462    
463            /**
464             * @deprecated As of 7.0.0, replaced by {@link #postProcessSearchQuery(
465             *             BooleanQuery, BooleanFilter, SearchContext)}
466             */
467            @Deprecated
468            @Override
469            public void postProcessSearchQuery(
470                            BooleanQuery searchQuery, SearchContext searchContext)
471                    throws Exception {
472            }
473    
474            @Override
475            public void registerIndexerPostProcessor(
476                    IndexerPostProcessor indexerPostProcessor) {
477    
478                    List<IndexerPostProcessor> indexerPostProcessorsList =
479                            ListUtil.fromArray(_indexerPostProcessors);
480    
481                    indexerPostProcessorsList.add(indexerPostProcessor);
482    
483                    _indexerPostProcessors = indexerPostProcessorsList.toArray(
484                            new IndexerPostProcessor[indexerPostProcessorsList.size()]);
485            }
486    
487            @Override
488            public void reindex(Object obj) throws SearchException {
489                    try {
490                            if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
491                                    return;
492                            }
493    
494                            if (obj instanceof List<?>) {
495                                    List<?> list = (List<?>)obj;
496    
497                                    for (Object element : list) {
498                                            doReindex(element);
499                                    }
500                            }
501                            else {
502                                    doReindex(obj);
503                            }
504                    }
505                    catch (SearchException se) {
506                            throw se;
507                    }
508                    catch (Exception e) {
509                            throw new SearchException(e);
510                    }
511            }
512    
513            @Override
514            public void reindex(String className, long classPK) throws SearchException {
515                    try {
516                            if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled() ||
517                                    (classPK <= 0)) {
518    
519                                    return;
520                            }
521    
522                            doReindex(className, classPK);
523                    }
524                    catch (NoSuchModelException nsme) {
525                            if (_log.isWarnEnabled()) {
526                                    _log.warn("Unable to index " + className + " " + classPK, nsme);
527                            }
528                    }
529                    catch (SearchException se) {
530                            throw se;
531                    }
532                    catch (Exception e) {
533                            throw new SearchException(e);
534                    }
535            }
536    
537            @Override
538            public void reindex(String[] ids) throws SearchException {
539                    try {
540                            if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
541                                    return;
542                            }
543    
544                            doReindex(ids);
545                    }
546                    catch (SearchException se) {
547                            throw se;
548                    }
549                    catch (Exception e) {
550                            throw new SearchException(e);
551                    }
552            }
553    
554            @Override
555            public Hits search(SearchContext searchContext) throws SearchException {
556                    try {
557                            Hits hits = null;
558    
559                            QueryConfig queryConfig = searchContext.getQueryConfig();
560    
561                            addDefaultHighlightFieldNames(queryConfig);
562    
563                            if (ArrayUtil.isEmpty(queryConfig.getSelectedFieldNames())) {
564                                    addDefaultSelectedFieldNames(searchContext);
565                            }
566    
567                            addFacetSelectedFieldNames(searchContext, queryConfig);
568    
569                            PermissionChecker permissionChecker =
570                                    PermissionThreadLocal.getPermissionChecker();
571    
572                            if ((permissionChecker != null) &&
573                                    isUseSearchResultPermissionFilter(searchContext)) {
574    
575                                    SearchResultPermissionFilter searchResultPermissionFilter =
576                                            new DefaultSearchResultPermissionFilter(
577                                                    this, permissionChecker);
578    
579                                    hits = searchResultPermissionFilter.search(searchContext);
580                            }
581                            else {
582                                    hits = doSearch(searchContext);
583                            }
584    
585                            processHits(searchContext, hits);
586    
587                            return hits;
588                    }
589                    catch (SearchException se) {
590                            throw se;
591                    }
592                    catch (Exception e) {
593                            throw new SearchException(e);
594                    }
595            }
596    
597            @Override
598            public Hits search(
599                            SearchContext searchContext, String... selectedFieldNames)
600                    throws SearchException {
601    
602                    QueryConfig queryConfig = searchContext.getQueryConfig();
603    
604                    queryConfig.setSelectedFieldNames(selectedFieldNames);
605    
606                    return search(searchContext);
607            }
608    
609            @Override
610            public long searchCount(SearchContext searchContext)
611                    throws SearchException {
612    
613                    PermissionChecker permissionChecker =
614                            PermissionThreadLocal.getPermissionChecker();
615    
616                    if ((permissionChecker != null) &&
617                            isUseSearchResultPermissionFilter(searchContext)) {
618    
619                            Hits hits = search(searchContext);
620    
621                            return hits.getLength();
622                    }
623    
624                    QueryConfig queryConfig = searchContext.getQueryConfig();
625    
626                    queryConfig.setHighlightEnabled(false);
627                    queryConfig.setHitsProcessingEnabled(false);
628                    queryConfig.setScoreEnabled(false);
629                    queryConfig.setQueryIndexingEnabled(false);
630                    queryConfig.setQuerySuggestionEnabled(false);
631    
632                    searchContext.setSearchEngineId(getSearchEngineId());
633    
634                    BooleanQuery fullQuery = getFullQuery(searchContext);
635    
636                    fullQuery.setQueryConfig(queryConfig);
637    
638                    return SearchEngineUtil.searchCount(searchContext, fullQuery);
639            }
640    
641            public void setCommitImmediately(boolean commitImmediately) {
642                    _commitImmediately = commitImmediately;
643            }
644    
645            public void setSelectAllLocales(boolean selectAllLocales) {
646                    _selectAllLocales = selectAllLocales;
647            }
648    
649            @Override
650            public void unregisterIndexerPostProcessor(
651                    IndexerPostProcessor indexerPostProcessor) {
652    
653                    List<IndexerPostProcessor> indexerPostProcessorsList =
654                            ListUtil.fromArray(_indexerPostProcessors);
655    
656                    indexerPostProcessorsList.remove(indexerPostProcessor);
657    
658                    _indexerPostProcessors = indexerPostProcessorsList.toArray(
659                            new IndexerPostProcessor[indexerPostProcessorsList.size()]);
660            }
661    
662            protected void addAssetFields(
663                    Document document, String className, long classPK) {
664    
665                    AssetRendererFactory assetRendererFactory =
666                            AssetRendererFactoryRegistryUtil.getAssetRendererFactoryByClassName(
667                                    className);
668    
669                    if ((assetRendererFactory == null) ||
670                            !assetRendererFactory.isSelectable()) {
671    
672                            return;
673                    }
674    
675                    AssetEntry assetEntry = AssetEntryLocalServiceUtil.fetchEntry(
676                            className, classPK);
677    
678                    if (assetEntry == null) {
679                            return;
680                    }
681    
682                    if (!document.hasField(Field.CREATE_DATE)) {
683                            document.addDate(Field.CREATE_DATE, assetEntry.getCreateDate());
684                    }
685    
686                    if (assetEntry.getExpirationDate() != null) {
687                            document.addDate(
688                                    Field.EXPIRATION_DATE, assetEntry.getExpirationDate());
689                    }
690                    else {
691                            document.addDate(Field.EXPIRATION_DATE, new Date(Long.MAX_VALUE));
692                    }
693    
694                    if (!document.hasField(Field.MODIFIED_DATE)) {
695                            document.addDate(Field.MODIFIED_DATE, assetEntry.getModifiedDate());
696                    }
697    
698                    document.addNumber(Field.PRIORITY, assetEntry.getPriority());
699    
700                    if (assetEntry.getPublishDate() != null) {
701                            document.addDate(Field.PUBLISH_DATE, assetEntry.getPublishDate());
702                    }
703                    else {
704                            document.addDate(Field.PUBLISH_DATE, new Date(0));
705                    }
706    
707                    RatingsStats ratingsStats = RatingsStatsLocalServiceUtil.getStats(
708                            className, classPK);
709    
710                    document.addNumber(Field.RATINGS, ratingsStats.getAverageScore());
711    
712                    document.addNumber(Field.VIEW_COUNT, assetEntry.getViewCount());
713    
714                    document.addLocalizedKeyword(
715                            "localized_title",
716                            populateMap(assetEntry, assetEntry.getTitleMap()), true, true);
717                    document.addKeyword("visible", assetEntry.isVisible());
718            }
719    
720            protected void addDefaultHighlightFieldNames(QueryConfig queryConfig) {
721                    queryConfig.addHighlightFieldNames(Field.ASSET_CATEGORY_TITLES);
722    
723                    if (queryConfig.isHighlightEnabled()) {
724                            queryConfig.addHighlightFieldNames(
725                                    Field.CONTENT, Field.DESCRIPTION, Field.TITLE);
726                    }
727            }
728    
729            protected void addDefaultSelectedFieldNames(SearchContext searchContext) {
730                    QueryConfig queryConfig = searchContext.getQueryConfig();
731    
732                    Set<String> selectedFieldNames = null;
733    
734                    if (!ArrayUtil.isEmpty(getDefaultSelectedFieldNames())) {
735                            selectedFieldNames = SetUtil.fromArray(
736                                    getDefaultSelectedFieldNames());
737    
738                            if (searchContext.isIncludeAttachments() ||
739                                    searchContext.isIncludeDiscussions()) {
740    
741                                    selectedFieldNames.add(Field.CLASS_NAME_ID);
742                                    selectedFieldNames.add(Field.CLASS_PK);
743                            }
744                    }
745    
746                    if (!ArrayUtil.isEmpty(getDefaultSelectedLocalizedFieldNames())) {
747                            if (selectedFieldNames == null) {
748                                    selectedFieldNames = new HashSet<>();
749                            }
750    
751                            if (isSelectAllLocales()) {
752                                    addSelectedLocalizedFieldNames(
753                                            selectedFieldNames,
754                                            LocaleUtil.toLanguageIds(
755                                                    LanguageUtil.getSupportedLocales()));
756                            }
757                            else {
758                                    addSelectedLocalizedFieldNames(
759                                            selectedFieldNames,
760                                            LocaleUtil.toLanguageId(queryConfig.getLocale()));
761                            }
762                    }
763    
764                    if ((selectedFieldNames != null) && !selectedFieldNames.isEmpty()) {
765                            queryConfig.setSelectedFieldNames(
766                                    selectedFieldNames.toArray(
767                                            new String[selectedFieldNames.size()]));
768                    }
769            }
770    
771            /**
772             * @deprecated As of 7.0.0
773             */
774            @Deprecated
775            protected void addFacetClause(
776                            SearchContext searchContext, BooleanFilter facetBooleanFilter,
777                            Collection<Facet> facets)
778                    throws ParseException {
779    
780                    BooleanQuery facetBooleanQuery = new BooleanQueryImpl();
781    
782                    for (Facet facet : facets) {
783                            BooleanClause<Query> facetBooleanClause = facet.getFacetClause();
784    
785                            if (facetBooleanClause != null) {
786                                    facetBooleanQuery.add(
787                                            facetBooleanClause.getClause(),
788                                            facetBooleanClause.getBooleanClauseOccur());
789                            }
790                    }
791    
792                    if (!facetBooleanQuery.hasClauses()) {
793                            return;
794                    }
795    
796                    QueryFilter queryFilter = new QueryFilter(facetBooleanQuery);
797    
798                    facetBooleanFilter.add(queryFilter, BooleanClauseOccur.MUST);
799            }
800    
801            protected void addFacetSelectedFieldNames(
802                    SearchContext searchContext, QueryConfig queryConfig) {
803    
804                    String[] selectedFieldNames = queryConfig.getSelectedFieldNames();
805    
806                    if (ArrayUtil.isEmpty(selectedFieldNames) ||
807                            (selectedFieldNames.length == 1) &&
808                            selectedFieldNames[0].equals(Field.ANY)) {
809    
810                            return;
811                    }
812    
813                    Set<String> selectedFieldNameSet = SetUtil.fromArray(
814                            selectedFieldNames);
815    
816                    Map<String, Facet> facets = searchContext.getFacets();
817    
818                    selectedFieldNameSet.addAll(facets.keySet());
819    
820                    selectedFieldNames = selectedFieldNameSet.toArray(
821                            new String[selectedFieldNameSet.size()]);
822    
823                    queryConfig.setSelectedFieldNames(selectedFieldNames);
824            }
825    
826            protected void addSearchAssetCategoryIds(
827                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
828                    throws Exception {
829    
830                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
831    
832                    multiValueFacet.setFieldName(Field.ASSET_CATEGORY_IDS);
833                    multiValueFacet.setStatic(true);
834                    multiValueFacet.setValues(searchContext.getAssetCategoryIds());
835    
836                    searchContext.addFacet(multiValueFacet);
837            }
838    
839            protected void addSearchAssetCategoryTitles(
840                    Document document, String field, List<AssetCategory> assetCategories) {
841    
842                    Map<Locale, List<String>> assetCategoryTitles = new HashMap<>();
843    
844                    Locale defaultLocale = LocaleUtil.getDefault();
845    
846                    for (AssetCategory assetCategory : assetCategories) {
847                            Map<Locale, String> titleMap = assetCategory.getTitleMap();
848    
849                            for (Map.Entry<Locale, String> entry : titleMap.entrySet()) {
850                                    Locale locale = entry.getKey();
851                                    String title = entry.getValue();
852    
853                                    if (Validator.isNull(title)) {
854                                            continue;
855                                    }
856    
857                                    List<String> titles = assetCategoryTitles.get(locale);
858    
859                                    if (titles == null) {
860                                            titles = new ArrayList<>();
861    
862                                            assetCategoryTitles.put(locale, titles);
863                                    }
864    
865                                    titles.add(StringUtil.toLowerCase(title));
866                            }
867                    }
868    
869                    for (Map.Entry<Locale, List<String>> entry :
870                                    assetCategoryTitles.entrySet()) {
871    
872                            Locale locale = entry.getKey();
873                            List<String> titles = entry.getValue();
874    
875                            String[] titlesArray = titles.toArray(new String[titles.size()]);
876    
877                            if (locale.equals(defaultLocale)) {
878                                    document.addText(field, titlesArray);
879                            }
880    
881                            document.addText(
882                                    field.concat(StringPool.UNDERLINE).concat(locale.toString()),
883                                    titlesArray);
884                    }
885            }
886    
887            protected void addSearchAssetTagNames(
888                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
889                    throws Exception {
890    
891                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
892    
893                    multiValueFacet.setFieldName(Field.ASSET_TAG_NAMES);
894                    multiValueFacet.setStatic(true);
895                    multiValueFacet.setValues(searchContext.getAssetTagNames());
896    
897                    searchContext.addFacet(multiValueFacet);
898            }
899    
900            protected Filter addSearchClassTypeIds(
901                            BooleanFilter contextBooleanFilter, SearchContext searchContext)
902                    throws Exception {
903    
904                    long[] classTypeIds = searchContext.getClassTypeIds();
905    
906                    if (ArrayUtil.isEmpty(classTypeIds)) {
907                            return null;
908                    }
909    
910                    TermsFilter classTypeIdsTermsFilter = new TermsFilter(
911                            Field.CLASS_TYPE_ID);
912    
913                    classTypeIdsTermsFilter.addValues(
914                            ArrayUtil.toStringArray(classTypeIds));
915    
916                    return contextBooleanFilter.add(
917                            classTypeIdsTermsFilter, BooleanClauseOccur.MUST);
918            }
919    
920            protected void addSearchEntryClassNames(
921                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
922                    throws Exception {
923    
924                    Facet facet = new AssetEntriesFacet(searchContext);
925    
926                    facet.setStatic(true);
927    
928                    searchContext.addFacet(facet);
929            }
930    
931            protected Map<String, Query> addSearchExpando(
932                            BooleanQuery searchQuery, SearchContext searchContext,
933                            String keywords)
934                    throws Exception {
935    
936                    Map<String, Query> expandoQueries = new HashMap<>();
937    
938                    ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
939                            searchContext.getCompanyId(), getClassName(searchContext));
940    
941                    Set<String> attributeNames = SetUtil.fromEnumeration(
942                            expandoBridge.getAttributeNames());
943    
944                    for (String attributeName : attributeNames) {
945                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
946                                    attributeName);
947    
948                            int indexType = GetterUtil.getInteger(
949                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
950    
951                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
952                                    String fieldName = getExpandoFieldName(
953                                            searchContext, expandoBridge, attributeName);
954    
955                                    if (Validator.isNotNull(keywords)) {
956                                            if (searchContext.isAndSearch()) {
957                                                    Query query = searchQuery.addRequiredTerm(
958                                                            fieldName, keywords);
959    
960                                                    expandoQueries.put(attributeName, query);
961                                            }
962                                            else {
963                                                    Query query = searchQuery.addTerm(fieldName, keywords);
964    
965                                                    expandoQueries.put(attributeName, query);
966                                            }
967                                    }
968                            }
969                    }
970    
971                    return expandoQueries;
972            }
973    
974            protected void addSearchFolderId(
975                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
976                    throws Exception {
977    
978                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
979    
980                    multiValueFacet.setFieldName(Field.TREE_PATH);
981                    multiValueFacet.setStatic(true);
982    
983                    long[] folderIds = searchContext.getFolderIds();
984    
985                    if (ArrayUtil.isNotEmpty(folderIds)) {
986                            folderIds = ArrayUtil.remove(folderIds, _DEFAULT_FOLDER_ID);
987    
988                            multiValueFacet.setValues(folderIds);
989                    }
990    
991                    searchContext.addFacet(multiValueFacet);
992            }
993    
994            protected void addSearchGroupId(
995                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
996                    throws Exception {
997    
998                    Facet facet = new ScopeFacet(searchContext);
999    
1000                    facet.setStatic(true);
1001    
1002                    searchContext.addFacet(facet);
1003            }
1004    
1005            protected Map<String, Query> addSearchKeywords(
1006                            BooleanQuery searchQuery, SearchContext searchContext)
1007                    throws Exception {
1008    
1009                    String keywords = searchContext.getKeywords();
1010    
1011                    if (Validator.isNull(keywords)) {
1012                            return Collections.emptyMap();
1013                    }
1014    
1015                    addSearchExpando(searchQuery, searchContext, keywords);
1016    
1017                    addSearchLocalizedTerm(
1018                            searchQuery, searchContext, Field.ASSET_CATEGORY_TITLES,
1019                            searchContext.isLike());
1020    
1021                    return searchQuery.addTerms(
1022                            Field.KEYWORDS, keywords, searchContext.isLike());
1023            }
1024    
1025            protected void addSearchLayout(
1026                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
1027                    throws Exception {
1028    
1029                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
1030    
1031                    multiValueFacet.setFieldName(Field.LAYOUT_UUID);
1032                    multiValueFacet.setStatic(true);
1033    
1034                    searchContext.addFacet(multiValueFacet);
1035            }
1036    
1037            protected Map<String, Query> addSearchLocalizedTerm(
1038                            BooleanQuery searchQuery, SearchContext searchContext, String field,
1039                            boolean like)
1040                    throws Exception {
1041    
1042                    Map<String, Query> queries = new HashMap<>();
1043    
1044                    Query query = addSearchTerm(searchQuery, searchContext, field, like);
1045    
1046                    queries.put(field, query);
1047    
1048                    String localizedFieldName = DocumentImpl.getLocalizedName(
1049                            searchContext.getLocale(), field);
1050    
1051                    Query localizedQuery = addSearchTerm(
1052                            searchQuery, searchContext, localizedFieldName, like);
1053    
1054                    queries.put(localizedFieldName, localizedQuery);
1055    
1056                    return queries;
1057            }
1058    
1059            protected Query addSearchTerm(
1060                            BooleanQuery searchQuery, SearchContext searchContext, String field,
1061                            boolean like)
1062                    throws Exception {
1063    
1064                    if (Validator.isNull(field)) {
1065                            return null;
1066                    }
1067    
1068                    String value = null;
1069    
1070                    Serializable serializable = searchContext.getAttribute(field);
1071    
1072                    if (serializable != null) {
1073                            Class<?> clazz = serializable.getClass();
1074    
1075                            if (clazz.isArray()) {
1076                                    value = StringUtil.merge((Object[])serializable);
1077                            }
1078                            else {
1079                                    value = GetterUtil.getString(serializable);
1080                            }
1081                    }
1082                    else {
1083                            value = GetterUtil.getString(serializable);
1084                    }
1085    
1086                    if (Validator.isNotNull(value) &&
1087                            (searchContext.getFacet(field) != null)) {
1088    
1089                            return null;
1090                    }
1091    
1092                    if (Validator.isNull(value)) {
1093                            value = searchContext.getKeywords();
1094                    }
1095    
1096                    if (Validator.isNull(value)) {
1097                            return null;
1098                    }
1099    
1100                    Query query = null;
1101    
1102                    if (searchContext.isAndSearch()) {
1103                            query = searchQuery.addRequiredTerm(field, value, like);
1104                    }
1105                    else {
1106                            query = searchQuery.addTerm(field, value, like);
1107                    }
1108    
1109                    return query;
1110            }
1111    
1112            protected void addSearchUserId(
1113                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
1114                    throws Exception {
1115    
1116                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
1117    
1118                    multiValueFacet.setFieldName(Field.USER_ID);
1119                    multiValueFacet.setStatic(true);
1120    
1121                    long userId = GetterUtil.getLong(
1122                            searchContext.getAttribute(Field.USER_ID));
1123    
1124                    if (userId > 0) {
1125                            multiValueFacet.setValues(new long[] {userId});
1126                    }
1127    
1128                    searchContext.addFacet(multiValueFacet);
1129            }
1130    
1131            protected void addSelectedLocalizedFieldNames(
1132                    Set<String> selectedFieldNames, String... languageIds) {
1133    
1134                    for (String defaultLocalizedSelectedFieldName :
1135                                    getDefaultSelectedLocalizedFieldNames()) {
1136    
1137                            selectedFieldNames.add(defaultLocalizedSelectedFieldName);
1138    
1139                            for (String languageId : languageIds) {
1140                                    String localizedFieldName = LocalizationUtil.getLocalizedName(
1141                                            defaultLocalizedSelectedFieldName, languageId);
1142    
1143                                    selectedFieldNames.add(localizedFieldName);
1144                            }
1145                    }
1146            }
1147    
1148            protected void addStagingGroupKeyword(Document document, long groupId) {
1149                    if (!isStagingAware()) {
1150                            return;
1151                    }
1152    
1153                    document.addKeyword(Field.STAGING_GROUP, isStagingGroup(groupId));
1154            }
1155    
1156            protected void addStatus(
1157                            BooleanFilter contextBooleanFilter, SearchContext searchContext)
1158                    throws Exception {
1159    
1160                    int status = GetterUtil.getInteger(
1161                            searchContext.getAttribute(Field.STATUS),
1162                            WorkflowConstants.STATUS_APPROVED);
1163    
1164                    if (status != WorkflowConstants.STATUS_ANY) {
1165                            contextBooleanFilter.addRequiredTerm(Field.STATUS, status);
1166                    }
1167                    else {
1168                            contextBooleanFilter.addTerm(
1169                                    Field.STATUS, String.valueOf(WorkflowConstants.STATUS_IN_TRASH),
1170                                    BooleanClauseOccur.MUST_NOT);
1171                    }
1172            }
1173    
1174            protected void addTrashFields(
1175                    Document document, TrashedModel trashedModel) {
1176    
1177                    TrashEntry trashEntry = null;
1178    
1179                    try {
1180                            trashEntry = trashedModel.getTrashEntry();
1181                    }
1182                    catch (PortalException pe) {
1183                            if (_log.isDebugEnabled()) {
1184                                    _log.debug("Unable to get trash entry for " + trashedModel);
1185                            }
1186                    }
1187    
1188                    if (trashEntry == null) {
1189                            document.addDate(Field.REMOVED_DATE, new Date());
1190    
1191                            ServiceContext serviceContext =
1192                                    ServiceContextThreadLocal.getServiceContext();
1193    
1194                            if (serviceContext != null) {
1195                                    try {
1196                                            User user = UserLocalServiceUtil.getUser(
1197                                                    serviceContext.getUserId());
1198    
1199                                            document.addKeyword(
1200                                                    Field.REMOVED_BY_USER_NAME, user.getFullName(), true);
1201                                    }
1202                                    catch (PortalException pe) {
1203                                            if (_log.isDebugEnabled()) {
1204                                                    _log.debug(
1205                                                            "Unable to locate user: " +
1206                                                                    serviceContext.getUserId(),
1207                                                            pe);
1208                                            }
1209                                    }
1210                            }
1211                    }
1212                    else {
1213                            document.addDate(Field.REMOVED_DATE, trashEntry.getCreateDate());
1214                            document.addKeyword(
1215                                    Field.REMOVED_BY_USER_NAME, trashEntry.getUserName(), true);
1216    
1217                            if (trashedModel.isInTrash() &&
1218                                    !trashedModel.isInTrashExplicitly()) {
1219    
1220                                    document.addKeyword(
1221                                            Field.ROOT_ENTRY_CLASS_NAME, trashEntry.getClassName());
1222                                    document.addKeyword(
1223                                            Field.ROOT_ENTRY_CLASS_PK, trashEntry.getClassPK());
1224                            }
1225                    }
1226    
1227                    TrashHandler trashHandler = trashedModel.getTrashHandler();
1228    
1229                    try {
1230                            TrashRenderer trashRenderer = null;
1231    
1232                            if ((trashHandler != null) && (trashEntry != null)) {
1233                                    trashRenderer = trashHandler.getTrashRenderer(
1234                                            trashEntry.getClassPK());
1235                            }
1236    
1237                            if (trashRenderer != null) {
1238                                    document.addKeyword(Field.TYPE, trashRenderer.getType(), true);
1239                            }
1240                    }
1241                    catch (PortalException pe) {
1242                            if (_log.isDebugEnabled()) {
1243                                    _log.debug(
1244                                            "Unable to get trash renderer for " +
1245                                                    trashEntry.getClassName());
1246                            }
1247                    }
1248            }
1249    
1250            protected BooleanQuery createFullQuery(
1251                            BooleanFilter fullQueryBooleanFilter, SearchContext searchContext)
1252                    throws Exception {
1253    
1254                    BooleanQuery searchQuery = new BooleanQueryImpl();
1255    
1256                    addSearchKeywords(searchQuery, searchContext);
1257                    postProcessSearchQuery(
1258                            searchQuery, fullQueryBooleanFilter, searchContext);
1259    
1260                    for (IndexerPostProcessor indexerPostProcessor :
1261                                    _indexerPostProcessors) {
1262    
1263                            indexerPostProcessor.postProcessSearchQuery(
1264                                    searchQuery, fullQueryBooleanFilter, searchContext);
1265                    }
1266    
1267                    doPostProcessSearchQuery(this, searchQuery, searchContext);
1268    
1269                    Map<String, Facet> facets = searchContext.getFacets();
1270    
1271                    BooleanFilter facetBooleanFilter = new BooleanFilter();
1272    
1273                    for (Facet facet : facets.values()) {
1274                            BooleanClause<Filter> filterBooleanClause =
1275                                    facet.getFacetFilterBooleanClause();
1276    
1277                            if (filterBooleanClause != null) {
1278                                    facetBooleanFilter.add(
1279                                            filterBooleanClause.getClause(),
1280                                            filterBooleanClause.getBooleanClauseOccur());
1281                            }
1282                    }
1283    
1284                    addFacetClause(searchContext, facetBooleanFilter, facets.values());
1285    
1286                    if (facetBooleanFilter.hasClauses()) {
1287                            fullQueryBooleanFilter.add(
1288                                    facetBooleanFilter, BooleanClauseOccur.MUST);
1289                    }
1290    
1291                    BooleanQuery fullBooleanQuery = new BooleanQueryImpl();
1292    
1293                    if (fullQueryBooleanFilter.hasClauses()) {
1294                            fullBooleanQuery.setPreBooleanFilter(fullQueryBooleanFilter);
1295                    }
1296    
1297                    if (searchQuery.hasClauses()) {
1298                            fullBooleanQuery.add(searchQuery, BooleanClauseOccur.MUST);
1299                    }
1300    
1301                    BooleanClause<Query>[] booleanClauses =
1302                            searchContext.getBooleanClauses();
1303    
1304                    if (booleanClauses != null) {
1305                            for (BooleanClause<Query> booleanClause : booleanClauses) {
1306                                    fullBooleanQuery.add(
1307                                            booleanClause.getClause(),
1308                                            booleanClause.getBooleanClauseOccur());
1309                            }
1310                    }
1311    
1312                    postProcessFullQuery(fullBooleanQuery, searchContext);
1313    
1314                    for (IndexerPostProcessor indexerPostProcessor :
1315                                    _indexerPostProcessors) {
1316    
1317                            indexerPostProcessor.postProcessFullQuery(
1318                                    fullBooleanQuery, searchContext);
1319                    }
1320    
1321                    return fullBooleanQuery;
1322            }
1323    
1324            protected Summary createSummary(Document document) {
1325                    return createSummary(document, Field.TITLE, Field.CONTENT);
1326            }
1327    
1328            protected Summary createSummary(
1329                    Document document, String titleField, String contentField) {
1330    
1331                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1332    
1333                    String title = document.get(prefix + titleField, titleField);
1334                    String content = document.get(prefix + contentField, contentField);
1335    
1336                    return new Summary(title, content);
1337            }
1338    
1339            protected void deleteDocument(long companyId, long field1)
1340                    throws Exception {
1341    
1342                    deleteDocument(companyId, String.valueOf(field1));
1343            }
1344    
1345            protected void deleteDocument(long companyId, long field1, String field2)
1346                    throws Exception {
1347    
1348                    deleteDocument(companyId, String.valueOf(field1), field2);
1349            }
1350    
1351            protected void deleteDocument(long companyId, String field1)
1352                    throws Exception {
1353    
1354                    Document document = new DocumentImpl();
1355    
1356                    document.addUID(getClassName(), field1);
1357    
1358                    SearchEngineUtil.deleteDocument(
1359                            getSearchEngineId(), companyId, document.get(Field.UID),
1360                            _commitImmediately);
1361            }
1362    
1363            protected void deleteDocument(long companyId, String field1, String field2)
1364                    throws Exception {
1365    
1366                    Document document = new DocumentImpl();
1367    
1368                    document.addUID(getClassName(), field1, field2);
1369    
1370                    SearchEngineUtil.deleteDocument(
1371                            getSearchEngineId(), companyId, document.get(Field.UID),
1372                            _commitImmediately);
1373            }
1374    
1375            protected abstract void doDelete(Object obj) throws Exception;
1376    
1377            protected abstract Document doGetDocument(Object obj) throws Exception;
1378    
1379            protected String doGetSortField(String orderByCol) {
1380                    return orderByCol;
1381            }
1382    
1383            protected abstract Summary doGetSummary(
1384                            Document document, Locale locale, String snippet,
1385                            PortletRequest portletRequest, PortletResponse portletResponse)
1386                    throws Exception;
1387    
1388            /**
1389             * @deprecated As of 7.0.0, added strictly to support backwards
1390             *             compatibility of {@link Indexer#postProcessSearchQuery(
1391             *             BooleanQuery, SearchContext)}
1392             */
1393            @Deprecated
1394            protected void doPostProcessSearchQuery(
1395                            Indexer indexer, BooleanQuery searchQuery,
1396                            SearchContext searchContext)
1397                    throws Exception {
1398    
1399                    indexer.postProcessSearchQuery(searchQuery, searchContext);
1400    
1401                    for (IndexerPostProcessor indexerPostProcessor :
1402                                    indexer.getIndexerPostProcessors()) {
1403    
1404                            indexerPostProcessor.postProcessSearchQuery(
1405                                    searchQuery, searchContext);
1406                    }
1407            }
1408    
1409            protected abstract void doReindex(Object obj) throws Exception;
1410    
1411            protected abstract void doReindex(String className, long classPK)
1412                    throws Exception;
1413    
1414            protected abstract void doReindex(String[] ids) throws Exception;
1415    
1416            protected Hits doSearch(SearchContext searchContext)
1417                    throws SearchException {
1418    
1419                    searchContext.setSearchEngineId(getSearchEngineId());
1420    
1421                    Query fullQuery = getFullQuery(searchContext);
1422    
1423                    if (!fullQuery.hasChildren()) {
1424                            BooleanFilter preBooleanFilter = fullQuery.getPreBooleanFilter();
1425    
1426                            fullQuery = new MatchAllQuery();
1427    
1428                            fullQuery.setPreBooleanFilter(preBooleanFilter);
1429                    }
1430    
1431                    QueryConfig queryConfig = searchContext.getQueryConfig();
1432    
1433                    fullQuery.setQueryConfig(queryConfig);
1434    
1435                    return SearchEngineUtil.search(searchContext, fullQuery);
1436            }
1437    
1438            protected Document getBaseModelDocument(
1439                    String portletId, BaseModel<?> baseModel) {
1440    
1441                    return getBaseModelDocument(portletId, baseModel, baseModel);
1442            }
1443    
1444            protected Document getBaseModelDocument(
1445                    String portletId, BaseModel<?> baseModel,
1446                    BaseModel<?> workflowedBaseModel) {
1447    
1448                    Document document = newDocument();
1449    
1450                    String className = baseModel.getModelClassName();
1451    
1452                    long classPK = 0;
1453                    long resourcePrimKey = 0;
1454    
1455                    if (baseModel instanceof ResourcedModel) {
1456                            ResourcedModel resourcedModel = (ResourcedModel)baseModel;
1457    
1458                            classPK = resourcedModel.getResourcePrimKey();
1459                            resourcePrimKey = resourcedModel.getResourcePrimKey();
1460                    }
1461                    else {
1462                            classPK = (Long)baseModel.getPrimaryKeyObj();
1463                    }
1464    
1465                    DocumentHelper documentHelper = new DocumentHelper(document);
1466    
1467                    documentHelper.setEntryKey(className, classPK);
1468    
1469                    document.addUID(className, classPK);
1470    
1471                    List<AssetCategory> assetCategories =
1472                            AssetCategoryLocalServiceUtil.getCategories(className, classPK);
1473    
1474                    long[] assetCategoryIds = ListUtil.toLongArray(
1475                            assetCategories, AssetCategory.CATEGORY_ID_ACCESSOR);
1476    
1477                    document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
1478    
1479                    addSearchAssetCategoryTitles(
1480                            document, Field.ASSET_CATEGORY_TITLES, assetCategories);
1481    
1482                    long classNameId = PortalUtil.getClassNameId(className);
1483    
1484                    List<AssetTag> assetTags = AssetTagLocalServiceUtil.getTags(
1485                            classNameId, classPK);
1486    
1487                    String[] assetTagNames = ListUtil.toArray(
1488                            assetTags, AssetTag.NAME_ACCESSOR);
1489    
1490                    document.addText(Field.ASSET_TAG_NAMES, assetTagNames);
1491    
1492                    long[] assetTagsIds = ListUtil.toLongArray(
1493                            assetTags, AssetTag.TAG_ID_ACCESSOR);
1494    
1495                    document.addKeyword(Field.ASSET_TAG_IDS, assetTagsIds);
1496    
1497                    if (resourcePrimKey > 0) {
1498                            document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
1499                    }
1500    
1501                    if (baseModel instanceof AttachedModel) {
1502                            AttachedModel attachedModel = (AttachedModel)baseModel;
1503    
1504                            documentHelper.setAttachmentOwnerKey(
1505                                    attachedModel.getClassNameId(), attachedModel.getClassPK());
1506                    }
1507    
1508                    if (baseModel instanceof AuditedModel) {
1509                            AuditedModel auditedModel = (AuditedModel)baseModel;
1510    
1511                            document.addKeyword(Field.COMPANY_ID, auditedModel.getCompanyId());
1512                            document.addDate(Field.CREATE_DATE, auditedModel.getCreateDate());
1513                            document.addDate(
1514                                    Field.MODIFIED_DATE, auditedModel.getModifiedDate());
1515                            document.addKeyword(Field.USER_ID, auditedModel.getUserId());
1516    
1517                            String userName = PortalUtil.getUserName(
1518                                    auditedModel.getUserId(), auditedModel.getUserName());
1519    
1520                            document.addKeyword(Field.USER_NAME, userName, true);
1521                    }
1522    
1523                    GroupedModel groupedModel = null;
1524    
1525                    if (baseModel instanceof GroupedModel) {
1526                            groupedModel = (GroupedModel)baseModel;
1527    
1528                            document.addKeyword(
1529                                    Field.GROUP_ID, getSiteGroupId(groupedModel.getGroupId()));
1530                            document.addKeyword(
1531                                    Field.SCOPE_GROUP_ID, groupedModel.getGroupId());
1532                    }
1533    
1534                    if (workflowedBaseModel instanceof WorkflowedModel) {
1535                            WorkflowedModel workflowedModel =
1536                                    (WorkflowedModel)workflowedBaseModel;
1537    
1538                            document.addKeyword(Field.STATUS, workflowedModel.getStatus());
1539                    }
1540    
1541                    if ((groupedModel != null) && (baseModel instanceof TrashedModel)) {
1542                            TrashedModel trashedModel = (TrashedModel)baseModel;
1543    
1544                            if (trashedModel.isInTrash()) {
1545                                    addTrashFields(document, trashedModel);
1546                            }
1547                    }
1548    
1549                    addAssetFields(document, className, classPK);
1550    
1551                    ExpandoBridgeIndexerUtil.addAttributes(
1552                            document, baseModel.getExpandoBridge());
1553    
1554                    return document;
1555            }
1556    
1557            protected String getClassName(SearchContext searchContext) {
1558                    return getClassName();
1559            }
1560    
1561            protected String[] getDefaultSelectedFieldNames() {
1562                    return _defaultSelectedFieldNames;
1563            }
1564    
1565            protected String[] getDefaultSelectedLocalizedFieldNames() {
1566                    return _defaultSelectedLocalizedFieldNames;
1567            }
1568    
1569            protected String getExpandoFieldName(
1570                    SearchContext searchContext, ExpandoBridge expandoBridge,
1571                    String attributeName) {
1572    
1573                    ExpandoColumn expandoColumn =
1574                            ExpandoColumnLocalServiceUtil.getDefaultTableColumn(
1575                                    expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1576                                    attributeName);
1577    
1578                    String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
1579                            attributeName);
1580    
1581                    if (expandoColumn.getType() ==
1582                                    ExpandoColumnConstants.STRING_LOCALIZED) {
1583    
1584                            fieldName = DocumentImpl.getLocalizedName(
1585                                    searchContext.getLocale(), fieldName);
1586                    }
1587    
1588                    return fieldName;
1589            }
1590    
1591            protected Locale getLocale(PortletRequest portletRequest) {
1592                    if (portletRequest != null) {
1593                            return portletRequest.getLocale();
1594                    }
1595    
1596                    return LocaleUtil.getMostRelevantLocale();
1597            }
1598    
1599            protected Set<String> getLocalizedCountryNames(Country country) {
1600                    Set<String> countryNames = new HashSet<>();
1601    
1602                    for (Locale locale : LanguageUtil.getAvailableLocales()) {
1603                            String countryName = country.getName(locale);
1604    
1605                            countryName = StringUtil.toLowerCase(countryName);
1606    
1607                            countryNames.add(countryName);
1608                    }
1609    
1610                    return countryNames;
1611            }
1612    
1613            /**
1614             * @deprecated As of 7.0.0 replaced by {@link #getClassName}
1615             */
1616            @Deprecated
1617            protected String getPortletId(SearchContext searchContext) {
1618                    return StringPool.BLANK;
1619            }
1620    
1621            protected Group getSiteGroup(long groupId) {
1622                    Group group = null;
1623    
1624                    try {
1625                            group = GroupLocalServiceUtil.getGroup(groupId);
1626    
1627                            if (group.isLayout()) {
1628                                    group = group.getParentGroup();
1629                            }
1630                    }
1631                    catch (PortalException pe) {
1632                            if (_log.isDebugEnabled()) {
1633                                    _log.debug("Unable to get site group", pe);
1634                            }
1635                    }
1636    
1637                    return group;
1638            }
1639    
1640            protected long getSiteGroupId(long groupId) {
1641                    Group group = getSiteGroup(groupId);
1642    
1643                    if (group == null) {
1644                            return groupId;
1645                    }
1646    
1647                    return group.getGroupId();
1648            }
1649    
1650            protected Locale getSnippetLocale(Document document, Locale locale) {
1651                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1652    
1653                    String localizedAssetCategoryTitlesName =
1654                            prefix +
1655                            DocumentImpl.getLocalizedName(locale, Field.ASSET_CATEGORY_TITLES);
1656                    String localizedContentName =
1657                            prefix + DocumentImpl.getLocalizedName(locale, Field.CONTENT);
1658                    String localizedDescriptionName =
1659                            prefix + DocumentImpl.getLocalizedName(locale, Field.DESCRIPTION);
1660                    String localizedTitleName =
1661                            prefix + DocumentImpl.getLocalizedName(locale, Field.TITLE);
1662    
1663                    if ((document.getField(localizedAssetCategoryTitlesName) != null) ||
1664                            (document.getField(localizedContentName) != null) ||
1665                            (document.getField(localizedDescriptionName) != null) ||
1666                            (document.getField(localizedTitleName) != null)) {
1667    
1668                            return locale;
1669                    }
1670    
1671                    return null;
1672            }
1673    
1674            protected boolean isStagingGroup(long groupId) {
1675                    Group group = getSiteGroup(groupId);
1676    
1677                    if (group == null) {
1678                            return false;
1679                    }
1680    
1681                    return group.isStagingGroup();
1682            }
1683    
1684            protected boolean isUseSearchResultPermissionFilter(
1685                    SearchContext searchContext) {
1686    
1687                    return isFilterSearch();
1688            }
1689    
1690            protected boolean isVisible(int entryStatus, int queryStatus) {
1691                    if (((queryStatus != WorkflowConstants.STATUS_ANY) &&
1692                             (entryStatus == queryStatus)) ||
1693                            (entryStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1694    
1695                            return true;
1696                    }
1697    
1698                    return false;
1699            }
1700    
1701            protected Document newDocument() {
1702                    return (Document)_document.clone();
1703            }
1704    
1705            protected void populateAddresses(
1706                            Document document, List<Address> addresses, long regionId,
1707                            long countryId)
1708                    throws PortalException {
1709    
1710                    List<String> cities = new ArrayList<>();
1711    
1712                    List<String> countries = new ArrayList<>();
1713    
1714                    if (countryId > 0) {
1715                            try {
1716                                    Country country = CountryServiceUtil.getCountry(countryId);
1717    
1718                                    countries.addAll(getLocalizedCountryNames(country));
1719                            }
1720                            catch (NoSuchCountryException nsce) {
1721                                    if (_log.isWarnEnabled()) {
1722                                            _log.warn(nsce.getMessage());
1723                                    }
1724                            }
1725                    }
1726    
1727                    List<String> regions = new ArrayList<>();
1728    
1729                    if (regionId > 0) {
1730                            try {
1731                                    Region region = RegionServiceUtil.getRegion(regionId);
1732    
1733                                    regions.add(StringUtil.toLowerCase(region.getName()));
1734                            }
1735                            catch (NoSuchRegionException nsre) {
1736                                    if (_log.isWarnEnabled()) {
1737                                            _log.warn(nsre.getMessage());
1738                                    }
1739                            }
1740                    }
1741    
1742                    List<String> streets = new ArrayList<>();
1743                    List<String> zips = new ArrayList<>();
1744    
1745                    for (Address address : addresses) {
1746                            cities.add(StringUtil.toLowerCase(address.getCity()));
1747                            countries.addAll(getLocalizedCountryNames(address.getCountry()));
1748                            regions.add(StringUtil.toLowerCase(address.getRegion().getName()));
1749                            streets.add(StringUtil.toLowerCase(address.getStreet1()));
1750                            streets.add(StringUtil.toLowerCase(address.getStreet2()));
1751                            streets.add(StringUtil.toLowerCase(address.getStreet3()));
1752                            zips.add(StringUtil.toLowerCase(address.getZip()));
1753                    }
1754    
1755                    document.addText("city", cities.toArray(new String[cities.size()]));
1756                    document.addText(
1757                            "country", countries.toArray(new String[countries.size()]));
1758                    document.addText("region", regions.toArray(new String[regions.size()]));
1759                    document.addText("street", streets.toArray(new String[streets.size()]));
1760                    document.addText("zip", zips.toArray(new String[zips.size()]));
1761            }
1762    
1763            protected Map<Locale, String> populateMap(
1764                    AssetEntry assetEntry, Map<Locale, String> map) {
1765    
1766                    String defaultValue = map.get(
1767                            LocaleUtil.fromLanguageId(assetEntry.getDefaultLanguageId()));
1768    
1769                    for (Locale availableLocale : LanguageUtil.getAvailableLocales(
1770                                    assetEntry.getGroupId())) {
1771    
1772                            if (!map.containsKey(availableLocale) ||
1773                                    Validator.isNull(map.get(availableLocale))) {
1774    
1775                                    map.put(availableLocale, defaultValue);
1776                            }
1777                    }
1778    
1779                    return map;
1780            }
1781    
1782            protected void postProcessFullQuery(
1783                            BooleanQuery fullQuery, SearchContext searchContext)
1784                    throws Exception {
1785            }
1786    
1787            protected void processHits(SearchContext searchContext, Hits hits)
1788                    throws SearchException {
1789    
1790                    HitsProcessor hitsProcessor =
1791                            HitsProcessorRegistryUtil.getDefaultHitsProcessor();
1792    
1793                    if (hitsProcessor != null) {
1794                            hitsProcessor.process(searchContext, hits);
1795                    }
1796            }
1797    
1798            protected void resetFullQuery(SearchContext searchContext) {
1799                    searchContext.clearFullQueryEntryClassNames();
1800    
1801                    for (Indexer indexer : IndexerRegistryUtil.getIndexers()) {
1802                            if (indexer instanceof RelatedEntryIndexer) {
1803                                    RelatedEntryIndexer relatedEntryIndexer =
1804                                            (RelatedEntryIndexer)indexer;
1805    
1806                                    relatedEntryIndexer.updateFullQuery(searchContext);
1807                            }
1808                    }
1809            }
1810    
1811            protected void setDefaultSelectedFieldNames(
1812                    String... defaultLocalizedFieldNames) {
1813    
1814                    _defaultSelectedFieldNames = defaultLocalizedFieldNames;
1815            }
1816    
1817            protected void setDefaultSelectedLocalizedFieldNames(
1818                    String... defaultLocalizedFieldNames) {
1819    
1820                    _defaultSelectedLocalizedFieldNames = defaultLocalizedFieldNames;
1821            }
1822    
1823            protected void setFilterSearch(boolean filterSearch) {
1824                    _filterSearch = filterSearch;
1825            }
1826    
1827            protected void setIndexerEnabled(boolean indexerEnabled) {
1828                    _indexerEnabled = indexerEnabled;
1829            }
1830    
1831            protected void setPermissionAware(boolean permissionAware) {
1832                    _permissionAware = permissionAware;
1833            }
1834    
1835            protected void setStagingAware(boolean stagingAware) {
1836                    _stagingAware = stagingAware;
1837            }
1838    
1839            private static final long _DEFAULT_FOLDER_ID = 0L;
1840    
1841            private static final Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
1842    
1843            private boolean _commitImmediately;
1844            private String[] _defaultSelectedFieldNames;
1845            private String[] _defaultSelectedLocalizedFieldNames;
1846            private final Document _document = new DocumentImpl();
1847            private boolean _filterSearch;
1848            private boolean _indexerEnabled = true;
1849            private IndexerPostProcessor[] _indexerPostProcessors =
1850                    new IndexerPostProcessor[0];
1851            private boolean _permissionAware;
1852            private String _searchEngineId;
1853            private boolean _selectAllLocales;
1854            private boolean _stagingAware = true;
1855    
1856    }