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