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.HitsProcessorRegistryUtil;
035    import com.liferay.portal.kernel.trash.TrashHandler;
036    import com.liferay.portal.kernel.trash.TrashRenderer;
037    import com.liferay.portal.kernel.util.ArrayUtil;
038    import com.liferay.portal.kernel.util.GetterUtil;
039    import com.liferay.portal.kernel.util.HashUtil;
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<T> implements Indexer<T> {
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(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                                    SearchEngineUtil.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 = SearchEngineUtil.getSearchEngine(
318                                    searchEngineId);
319    
320                            if (searchEngine != null) {
321                                    _searchEngineId = searchEngineId;
322                            }
323                    }
324    
325                    if (_searchEngineId == null) {
326                            _searchEngineId = SearchEngineUtil.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 (SearchEngineUtil.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 (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled() ||
550                                    (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 (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
574                                    return;
575                            }
576    
577                            doReindex(ids);
578                    }
579                    catch (SearchException se) {
580                            throw se;
581                    }
582                    catch (Exception e) {
583                            throw new SearchException(e);
584                    }
585            }
586    
587            @Override
588            public void reindex(T object) throws SearchException {
589                    try {
590                            if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
591                                    return;
592                            }
593    
594                            if (object == null) {
595                                    return;
596                            }
597    
598                            doReindex(object);
599                    }
600                    catch (SearchException se) {
601                            throw se;
602                    }
603                    catch (Exception e) {
604                            throw new SearchException(e);
605                    }
606            }
607    
608            @Override
609            public Hits search(SearchContext searchContext) throws SearchException {
610                    try {
611                            Hits hits = null;
612    
613                            QueryConfig queryConfig = searchContext.getQueryConfig();
614    
615                            addDefaultHighlightFieldNames(queryConfig);
616    
617                            if (ArrayUtil.isEmpty(queryConfig.getSelectedFieldNames())) {
618                                    addDefaultSelectedFieldNames(searchContext);
619                            }
620    
621                            addFacetSelectedFieldNames(searchContext, queryConfig);
622    
623                            PermissionChecker permissionChecker =
624                                    PermissionThreadLocal.getPermissionChecker();
625    
626                            if ((permissionChecker != null) &&
627                                    isUseSearchResultPermissionFilter(searchContext)) {
628    
629                                    SearchResultPermissionFilter searchResultPermissionFilter =
630                                            new DefaultSearchResultPermissionFilter(
631                                                    this, permissionChecker);
632    
633                                    hits = searchResultPermissionFilter.search(searchContext);
634                            }
635                            else {
636                                    hits = doSearch(searchContext);
637                            }
638    
639                            processHits(searchContext, hits);
640    
641                            return hits;
642                    }
643                    catch (SearchException se) {
644                            throw se;
645                    }
646                    catch (Exception e) {
647                            throw new SearchException(e);
648                    }
649            }
650    
651            @Override
652            public Hits search(
653                            SearchContext searchContext, String... selectedFieldNames)
654                    throws SearchException {
655    
656                    QueryConfig queryConfig = searchContext.getQueryConfig();
657    
658                    queryConfig.setSelectedFieldNames(selectedFieldNames);
659    
660                    return search(searchContext);
661            }
662    
663            @Override
664            public long searchCount(SearchContext searchContext)
665                    throws SearchException {
666    
667                    PermissionChecker permissionChecker =
668                            PermissionThreadLocal.getPermissionChecker();
669    
670                    if ((permissionChecker != null) &&
671                            isUseSearchResultPermissionFilter(searchContext)) {
672    
673                            Hits hits = search(searchContext);
674    
675                            return hits.getLength();
676                    }
677    
678                    QueryConfig queryConfig = searchContext.getQueryConfig();
679    
680                    queryConfig.setHighlightEnabled(false);
681                    queryConfig.setHitsProcessingEnabled(false);
682                    queryConfig.setScoreEnabled(false);
683                    queryConfig.setQueryIndexingEnabled(false);
684                    queryConfig.setQuerySuggestionEnabled(false);
685    
686                    searchContext.setSearchEngineId(getSearchEngineId());
687    
688                    BooleanQuery fullQuery = getFullQuery(searchContext);
689    
690                    fullQuery.setQueryConfig(queryConfig);
691    
692                    return SearchEngineUtil.searchCount(searchContext, fullQuery);
693            }
694    
695            public void setCommitImmediately(boolean commitImmediately) {
696                    _commitImmediately = commitImmediately;
697            }
698    
699            @Override
700            public void setIndexerEnabled(boolean indexerEnabled) {
701                    _indexerEnabled = indexerEnabled;
702            }
703    
704            public void setSelectAllLocales(boolean selectAllLocales) {
705                    _selectAllLocales = selectAllLocales;
706            }
707    
708            @Override
709            public void unregisterIndexerPostProcessor(
710                    IndexerPostProcessor indexerPostProcessor) {
711    
712                    List<IndexerPostProcessor> indexerPostProcessorsList =
713                            ListUtil.fromArray(_indexerPostProcessors);
714    
715                    indexerPostProcessorsList.remove(indexerPostProcessor);
716    
717                    _indexerPostProcessors = indexerPostProcessorsList.toArray(
718                            new IndexerPostProcessor[indexerPostProcessorsList.size()]);
719            }
720    
721            protected void addAssetFields(
722                    Document document, String className, long classPK) {
723    
724                    AssetRendererFactory<?> assetRendererFactory =
725                            AssetRendererFactoryRegistryUtil.getAssetRendererFactoryByClassName(
726                                    className);
727    
728                    if ((assetRendererFactory == null) ||
729                            !assetRendererFactory.isSelectable()) {
730    
731                            return;
732                    }
733    
734                    AssetEntry assetEntry = AssetEntryLocalServiceUtil.fetchEntry(
735                            className, classPK);
736    
737                    if (assetEntry == null) {
738                            return;
739                    }
740    
741                    if (!document.hasField(Field.CREATE_DATE)) {
742                            document.addDate(Field.CREATE_DATE, assetEntry.getCreateDate());
743                    }
744    
745                    if (assetEntry.getExpirationDate() != null) {
746                            document.addDate(
747                                    Field.EXPIRATION_DATE, assetEntry.getExpirationDate());
748                    }
749                    else {
750                            document.addDate(Field.EXPIRATION_DATE, new Date(Long.MAX_VALUE));
751                    }
752    
753                    if (!document.hasField(Field.MODIFIED_DATE)) {
754                            document.addDate(Field.MODIFIED_DATE, assetEntry.getModifiedDate());
755                    }
756    
757                    document.addNumber(Field.PRIORITY, assetEntry.getPriority());
758    
759                    if (assetEntry.getPublishDate() != null) {
760                            document.addDate(Field.PUBLISH_DATE, assetEntry.getPublishDate());
761                    }
762                    else {
763                            document.addDate(Field.PUBLISH_DATE, new Date(0));
764                    }
765    
766                    RatingsStats ratingsStats = RatingsStatsLocalServiceUtil.fetchStats(
767                            className, classPK);
768    
769                    if (ratingsStats != null) {
770                            document.addNumber(Field.RATINGS, ratingsStats.getAverageScore());
771                    }
772                    else {
773                            document.addNumber(Field.RATINGS, 0.0f);
774                    }
775    
776                    document.addNumber(Field.VIEW_COUNT, assetEntry.getViewCount());
777    
778                    document.addLocalizedKeyword(
779                            "localized_title",
780                            populateMap(assetEntry, assetEntry.getTitleMap()), true, true);
781                    document.addKeyword("visible", assetEntry.isVisible());
782            }
783    
784            protected void addDefaultHighlightFieldNames(QueryConfig queryConfig) {
785                    queryConfig.addHighlightFieldNames(Field.ASSET_CATEGORY_TITLES);
786    
787                    if (queryConfig.isHighlightEnabled()) {
788                            queryConfig.addHighlightFieldNames(
789                                    Field.CONTENT, Field.DESCRIPTION, Field.TITLE);
790                    }
791            }
792    
793            protected void addDefaultSelectedFieldNames(SearchContext searchContext) {
794                    QueryConfig queryConfig = searchContext.getQueryConfig();
795    
796                    Set<String> selectedFieldNames = null;
797    
798                    if (!ArrayUtil.isEmpty(getDefaultSelectedFieldNames())) {
799                            selectedFieldNames = SetUtil.fromArray(
800                                    getDefaultSelectedFieldNames());
801    
802                            if (searchContext.isIncludeAttachments() ||
803                                    searchContext.isIncludeDiscussions()) {
804    
805                                    selectedFieldNames.add(Field.CLASS_NAME_ID);
806                                    selectedFieldNames.add(Field.CLASS_PK);
807                            }
808                    }
809    
810                    if (!ArrayUtil.isEmpty(getDefaultSelectedLocalizedFieldNames())) {
811                            if (selectedFieldNames == null) {
812                                    selectedFieldNames = new HashSet<>();
813                            }
814    
815                            if (isSelectAllLocales()) {
816                                    addSelectedLocalizedFieldNames(
817                                            selectedFieldNames,
818                                            LocaleUtil.toLanguageIds(
819                                                    LanguageUtil.getSupportedLocales()));
820                            }
821                            else {
822                                    addSelectedLocalizedFieldNames(
823                                            selectedFieldNames,
824                                            LocaleUtil.toLanguageId(queryConfig.getLocale()));
825                            }
826                    }
827    
828                    if ((selectedFieldNames != null) && !selectedFieldNames.isEmpty()) {
829                            queryConfig.setSelectedFieldNames(
830                                    selectedFieldNames.toArray(
831                                            new String[selectedFieldNames.size()]));
832                    }
833            }
834    
835            /**
836             * @deprecated As of 7.0.0
837             */
838            @Deprecated
839            protected void addFacetClause(
840                            SearchContext searchContext, BooleanFilter facetBooleanFilter,
841                            Collection<Facet> facets)
842                    throws ParseException {
843    
844                    BooleanQuery facetBooleanQuery = new BooleanQueryImpl();
845    
846                    for (Facet facet : facets) {
847                            BooleanClause<Query> facetBooleanClause = facet.getFacetClause();
848    
849                            if (facetBooleanClause != null) {
850                                    facetBooleanQuery.add(
851                                            facetBooleanClause.getClause(),
852                                            facetBooleanClause.getBooleanClauseOccur());
853                            }
854                    }
855    
856                    if (!facetBooleanQuery.hasClauses()) {
857                            return;
858                    }
859    
860                    QueryFilter queryFilter = new QueryFilter(facetBooleanQuery);
861    
862                    facetBooleanFilter.add(queryFilter, BooleanClauseOccur.MUST);
863            }
864    
865            protected void addFacetSelectedFieldNames(
866                    SearchContext searchContext, QueryConfig queryConfig) {
867    
868                    String[] selectedFieldNames = queryConfig.getSelectedFieldNames();
869    
870                    if (ArrayUtil.isEmpty(selectedFieldNames) ||
871                            (selectedFieldNames.length == 1) &&
872                            selectedFieldNames[0].equals(Field.ANY)) {
873    
874                            return;
875                    }
876    
877                    Set<String> selectedFieldNameSet = SetUtil.fromArray(
878                            selectedFieldNames);
879    
880                    Map<String, Facet> facets = searchContext.getFacets();
881    
882                    selectedFieldNameSet.addAll(facets.keySet());
883    
884                    selectedFieldNames = selectedFieldNameSet.toArray(
885                            new String[selectedFieldNameSet.size()]);
886    
887                    queryConfig.setSelectedFieldNames(selectedFieldNames);
888            }
889    
890            protected void addSearchAssetCategoryIds(
891                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
892                    throws Exception {
893    
894                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
895    
896                    multiValueFacet.setFieldName(Field.ASSET_CATEGORY_IDS);
897                    multiValueFacet.setStatic(true);
898                    multiValueFacet.setValues(searchContext.getAssetCategoryIds());
899    
900                    searchContext.addFacet(multiValueFacet);
901            }
902    
903            protected void addSearchAssetCategoryTitles(
904                    Document document, String field, List<AssetCategory> assetCategories) {
905    
906                    Map<Locale, List<String>> assetCategoryTitles = new HashMap<>();
907    
908                    Locale defaultLocale = LocaleUtil.getDefault();
909    
910                    for (AssetCategory assetCategory : assetCategories) {
911                            Map<Locale, String> titleMap = assetCategory.getTitleMap();
912    
913                            for (Map.Entry<Locale, String> entry : titleMap.entrySet()) {
914                                    Locale locale = entry.getKey();
915                                    String title = entry.getValue();
916    
917                                    if (Validator.isNull(title)) {
918                                            continue;
919                                    }
920    
921                                    List<String> titles = assetCategoryTitles.get(locale);
922    
923                                    if (titles == null) {
924                                            titles = new ArrayList<>();
925    
926                                            assetCategoryTitles.put(locale, titles);
927                                    }
928    
929                                    titles.add(StringUtil.toLowerCase(title));
930                            }
931                    }
932    
933                    for (Map.Entry<Locale, List<String>> entry :
934                                    assetCategoryTitles.entrySet()) {
935    
936                            Locale locale = entry.getKey();
937                            List<String> titles = entry.getValue();
938    
939                            String[] titlesArray = titles.toArray(new String[titles.size()]);
940    
941                            if (locale.equals(defaultLocale)) {
942                                    document.addText(field, titlesArray);
943                            }
944    
945                            document.addText(
946                                    field.concat(StringPool.UNDERLINE).concat(locale.toString()),
947                                    titlesArray);
948                    }
949            }
950    
951            protected void addSearchAssetTagNames(
952                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
953                    throws Exception {
954    
955                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
956    
957                    multiValueFacet.setFieldName(Field.ASSET_TAG_NAMES);
958                    multiValueFacet.setStatic(true);
959                    multiValueFacet.setValues(searchContext.getAssetTagNames());
960    
961                    searchContext.addFacet(multiValueFacet);
962            }
963    
964            protected Filter addSearchClassTypeIds(
965                            BooleanFilter contextBooleanFilter, SearchContext searchContext)
966                    throws Exception {
967    
968                    long[] classTypeIds = searchContext.getClassTypeIds();
969    
970                    if (ArrayUtil.isEmpty(classTypeIds)) {
971                            return null;
972                    }
973    
974                    TermsFilter classTypeIdsTermsFilter = new TermsFilter(
975                            Field.CLASS_TYPE_ID);
976    
977                    classTypeIdsTermsFilter.addValues(
978                            ArrayUtil.toStringArray(classTypeIds));
979    
980                    return contextBooleanFilter.add(
981                            classTypeIdsTermsFilter, BooleanClauseOccur.MUST);
982            }
983    
984            protected void addSearchEntryClassNames(
985                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
986                    throws Exception {
987    
988                    Facet facet = new AssetEntriesFacet(searchContext);
989    
990                    facet.setStatic(true);
991    
992                    searchContext.addFacet(facet);
993            }
994    
995            protected Map<String, Query> addSearchExpando(
996                            BooleanQuery searchQuery, SearchContext searchContext,
997                            String keywords)
998                    throws Exception {
999    
1000                    Map<String, Query> expandoQueries = new HashMap<>();
1001    
1002                    ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
1003                            searchContext.getCompanyId(), getClassName(searchContext));
1004    
1005                    Set<String> attributeNames = SetUtil.fromEnumeration(
1006                            expandoBridge.getAttributeNames());
1007    
1008                    for (String attributeName : attributeNames) {
1009                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
1010                                    attributeName);
1011    
1012                            int indexType = GetterUtil.getInteger(
1013                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
1014    
1015                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
1016                                    String fieldName = getExpandoFieldName(
1017                                            searchContext, expandoBridge, attributeName);
1018    
1019                                    if (Validator.isNotNull(keywords)) {
1020                                            if (searchContext.isAndSearch()) {
1021                                                    Query query = searchQuery.addRequiredTerm(
1022                                                            fieldName, keywords);
1023    
1024                                                    expandoQueries.put(attributeName, query);
1025                                            }
1026                                            else {
1027                                                    Query query = searchQuery.addTerm(fieldName, keywords);
1028    
1029                                                    expandoQueries.put(attributeName, query);
1030                                            }
1031                                    }
1032                            }
1033                    }
1034    
1035                    return expandoQueries;
1036            }
1037    
1038            protected void addSearchFolderId(
1039                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
1040                    throws Exception {
1041    
1042                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
1043    
1044                    multiValueFacet.setFieldName(Field.TREE_PATH);
1045                    multiValueFacet.setStatic(true);
1046    
1047                    long[] folderIds = searchContext.getFolderIds();
1048    
1049                    if (ArrayUtil.isNotEmpty(folderIds)) {
1050                            folderIds = ArrayUtil.remove(folderIds, _DEFAULT_FOLDER_ID);
1051    
1052                            multiValueFacet.setValues(folderIds);
1053                    }
1054    
1055                    searchContext.addFacet(multiValueFacet);
1056            }
1057    
1058            protected void addSearchGroupId(
1059                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
1060                    throws Exception {
1061    
1062                    Facet facet = new ScopeFacet(searchContext);
1063    
1064                    facet.setStatic(true);
1065    
1066                    searchContext.addFacet(facet);
1067            }
1068    
1069            protected Map<String, Query> addSearchKeywords(
1070                            BooleanQuery searchQuery, SearchContext searchContext)
1071                    throws Exception {
1072    
1073                    String keywords = searchContext.getKeywords();
1074    
1075                    if (Validator.isNull(keywords)) {
1076                            return Collections.emptyMap();
1077                    }
1078    
1079                    addSearchExpando(searchQuery, searchContext, keywords);
1080    
1081                    addSearchLocalizedTerm(
1082                            searchQuery, searchContext, Field.ASSET_CATEGORY_TITLES,
1083                            searchContext.isLike());
1084    
1085                    return searchQuery.addTerms(
1086                            Field.KEYWORDS, keywords, searchContext.isLike());
1087            }
1088    
1089            protected void addSearchLayout(
1090                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
1091                    throws Exception {
1092    
1093                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
1094    
1095                    multiValueFacet.setFieldName(Field.LAYOUT_UUID);
1096                    multiValueFacet.setStatic(true);
1097    
1098                    searchContext.addFacet(multiValueFacet);
1099            }
1100    
1101            protected Map<String, Query> addSearchLocalizedTerm(
1102                            BooleanQuery searchQuery, SearchContext searchContext, String field,
1103                            boolean like)
1104                    throws Exception {
1105    
1106                    Map<String, Query> queries = new HashMap<>();
1107    
1108                    Query query = addSearchTerm(searchQuery, searchContext, field, like);
1109    
1110                    queries.put(field, query);
1111    
1112                    String localizedFieldName = DocumentImpl.getLocalizedName(
1113                            searchContext.getLocale(), field);
1114    
1115                    Query localizedQuery = addSearchTerm(
1116                            searchQuery, searchContext, localizedFieldName, like);
1117    
1118                    queries.put(localizedFieldName, localizedQuery);
1119    
1120                    return queries;
1121            }
1122    
1123            protected Query addSearchTerm(
1124                            BooleanQuery searchQuery, SearchContext searchContext, String field,
1125                            boolean like)
1126                    throws Exception {
1127    
1128                    if (Validator.isNull(field)) {
1129                            return null;
1130                    }
1131    
1132                    String value = null;
1133    
1134                    Serializable serializable = searchContext.getAttribute(field);
1135    
1136                    if (serializable != null) {
1137                            Class<?> clazz = serializable.getClass();
1138    
1139                            if (clazz.isArray()) {
1140                                    value = StringUtil.merge((Object[])serializable);
1141                            }
1142                            else {
1143                                    value = GetterUtil.getString(serializable);
1144                            }
1145                    }
1146                    else {
1147                            value = GetterUtil.getString(serializable);
1148                    }
1149    
1150                    if (Validator.isNotNull(value) &&
1151                            (searchContext.getFacet(field) != null)) {
1152    
1153                            return null;
1154                    }
1155    
1156                    if (Validator.isNull(value)) {
1157                            value = searchContext.getKeywords();
1158                    }
1159    
1160                    if (Validator.isNull(value)) {
1161                            return null;
1162                    }
1163    
1164                    Query query = null;
1165    
1166                    if (searchContext.isAndSearch()) {
1167                            query = searchQuery.addRequiredTerm(field, value, like);
1168                    }
1169                    else {
1170                            query = searchQuery.addTerm(field, value, like);
1171                    }
1172    
1173                    return query;
1174            }
1175    
1176            protected void addSearchUserId(
1177                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
1178                    throws Exception {
1179    
1180                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
1181    
1182                    multiValueFacet.setFieldName(Field.USER_ID);
1183                    multiValueFacet.setStatic(true);
1184    
1185                    long userId = GetterUtil.getLong(
1186                            searchContext.getAttribute(Field.USER_ID));
1187    
1188                    if (userId > 0) {
1189                            multiValueFacet.setValues(new long[] {userId});
1190                    }
1191    
1192                    searchContext.addFacet(multiValueFacet);
1193            }
1194    
1195            protected void addSelectedLocalizedFieldNames(
1196                    Set<String> selectedFieldNames, String... languageIds) {
1197    
1198                    for (String defaultLocalizedSelectedFieldName :
1199                                    getDefaultSelectedLocalizedFieldNames()) {
1200    
1201                            selectedFieldNames.add(defaultLocalizedSelectedFieldName);
1202    
1203                            for (String languageId : languageIds) {
1204                                    String localizedFieldName = LocalizationUtil.getLocalizedName(
1205                                            defaultLocalizedSelectedFieldName, languageId);
1206    
1207                                    selectedFieldNames.add(localizedFieldName);
1208                            }
1209                    }
1210            }
1211    
1212            protected void addStagingGroupKeyword(Document document, long groupId) {
1213                    if (!isStagingAware()) {
1214                            return;
1215                    }
1216    
1217                    document.addKeyword(Field.STAGING_GROUP, isStagingGroup(groupId));
1218            }
1219    
1220            protected void addStatus(
1221                            BooleanFilter contextBooleanFilter, SearchContext searchContext)
1222                    throws Exception {
1223    
1224                    int[] statuses = GetterUtil.getIntegerValues(
1225                            searchContext.getAttribute(Field.STATUS), null);
1226    
1227                    if (ArrayUtil.isEmpty(statuses)) {
1228                            int status = GetterUtil.getInteger(
1229                                    searchContext.getAttribute(Field.STATUS),
1230                                    WorkflowConstants.STATUS_APPROVED);
1231    
1232                            statuses = new int[] {status};
1233                    }
1234    
1235                    if (!ArrayUtil.contains(statuses, WorkflowConstants.STATUS_ANY)) {
1236                            TermsFilter statusesTermsFilter = new TermsFilter(Field.STATUS);
1237    
1238                            statusesTermsFilter.addValues(ArrayUtil.toStringArray(statuses));
1239    
1240                            contextBooleanFilter.add(
1241                                    statusesTermsFilter, BooleanClauseOccur.MUST);
1242                    }
1243                    else {
1244                            contextBooleanFilter.addTerm(
1245                                    Field.STATUS, String.valueOf(WorkflowConstants.STATUS_IN_TRASH),
1246                                    BooleanClauseOccur.MUST_NOT);
1247                    }
1248            }
1249    
1250            protected void addTrashFields(
1251                    Document document, TrashedModel trashedModel) {
1252    
1253                    TrashEntry trashEntry = null;
1254    
1255                    try {
1256                            trashEntry = trashedModel.getTrashEntry();
1257                    }
1258                    catch (PortalException pe) {
1259                            if (_log.isDebugEnabled()) {
1260                                    _log.debug("Unable to get trash entry for " + trashedModel);
1261                            }
1262                    }
1263    
1264                    if (trashEntry == null) {
1265                            document.addDate(Field.REMOVED_DATE, new Date());
1266    
1267                            ServiceContext serviceContext =
1268                                    ServiceContextThreadLocal.getServiceContext();
1269    
1270                            if (serviceContext != null) {
1271                                    try {
1272                                            User user = UserLocalServiceUtil.getUser(
1273                                                    serviceContext.getUserId());
1274    
1275                                            document.addKeyword(
1276                                                    Field.REMOVED_BY_USER_NAME, user.getFullName(), true);
1277                                    }
1278                                    catch (PortalException pe) {
1279                                            if (_log.isDebugEnabled()) {
1280                                                    _log.debug(
1281                                                            "Unable to locate user: " +
1282                                                                    serviceContext.getUserId(),
1283                                                            pe);
1284                                            }
1285                                    }
1286                            }
1287                    }
1288                    else {
1289                            document.addDate(Field.REMOVED_DATE, trashEntry.getCreateDate());
1290                            document.addKeyword(
1291                                    Field.REMOVED_BY_USER_NAME, trashEntry.getUserName(), true);
1292    
1293                            if (trashedModel.isInTrash() &&
1294                                    !trashedModel.isInTrashExplicitly()) {
1295    
1296                                    document.addKeyword(
1297                                            Field.ROOT_ENTRY_CLASS_NAME, trashEntry.getClassName());
1298                                    document.addKeyword(
1299                                            Field.ROOT_ENTRY_CLASS_PK, trashEntry.getClassPK());
1300                            }
1301                    }
1302    
1303                    TrashHandler trashHandler = trashedModel.getTrashHandler();
1304    
1305                    try {
1306                            TrashRenderer trashRenderer = null;
1307    
1308                            if ((trashHandler != null) && (trashEntry != null)) {
1309                                    trashRenderer = trashHandler.getTrashRenderer(
1310                                            trashEntry.getClassPK());
1311                            }
1312    
1313                            if (trashRenderer != null) {
1314                                    document.addKeyword(Field.TYPE, trashRenderer.getType(), true);
1315                            }
1316                    }
1317                    catch (PortalException pe) {
1318                            if (_log.isDebugEnabled()) {
1319                                    _log.debug(
1320                                            "Unable to get trash renderer for " +
1321                                                    trashEntry.getClassName());
1322                            }
1323                    }
1324            }
1325    
1326            protected BooleanQuery createFullQuery(
1327                            BooleanFilter fullQueryBooleanFilter, SearchContext searchContext)
1328                    throws Exception {
1329    
1330                    BooleanQuery searchQuery = new BooleanQueryImpl();
1331    
1332                    addSearchKeywords(searchQuery, searchContext);
1333                    postProcessSearchQuery(
1334                            searchQuery, fullQueryBooleanFilter, searchContext);
1335    
1336                    for (IndexerPostProcessor indexerPostProcessor :
1337                                    _indexerPostProcessors) {
1338    
1339                            indexerPostProcessor.postProcessSearchQuery(
1340                                    searchQuery, fullQueryBooleanFilter, searchContext);
1341                    }
1342    
1343                    doPostProcessSearchQuery(this, searchQuery, searchContext);
1344    
1345                    Map<String, Facet> facets = searchContext.getFacets();
1346    
1347                    BooleanFilter facetBooleanFilter = new BooleanFilter();
1348    
1349                    for (Facet facet : facets.values()) {
1350                            BooleanClause<Filter> filterBooleanClause =
1351                                    facet.getFacetFilterBooleanClause();
1352    
1353                            if (filterBooleanClause != null) {
1354                                    facetBooleanFilter.add(
1355                                            filterBooleanClause.getClause(),
1356                                            filterBooleanClause.getBooleanClauseOccur());
1357                            }
1358                    }
1359    
1360                    addFacetClause(searchContext, facetBooleanFilter, facets.values());
1361    
1362                    if (facetBooleanFilter.hasClauses()) {
1363                            fullQueryBooleanFilter.add(
1364                                    facetBooleanFilter, BooleanClauseOccur.MUST);
1365                    }
1366    
1367                    BooleanQuery fullBooleanQuery = new BooleanQueryImpl();
1368    
1369                    if (fullQueryBooleanFilter.hasClauses()) {
1370                            fullBooleanQuery.setPreBooleanFilter(fullQueryBooleanFilter);
1371                    }
1372    
1373                    if (searchQuery.hasClauses()) {
1374                            fullBooleanQuery.add(searchQuery, BooleanClauseOccur.MUST);
1375                    }
1376    
1377                    BooleanClause<Query>[] booleanClauses =
1378                            searchContext.getBooleanClauses();
1379    
1380                    if (booleanClauses != null) {
1381                            for (BooleanClause<Query> booleanClause : booleanClauses) {
1382                                    fullBooleanQuery.add(
1383                                            booleanClause.getClause(),
1384                                            booleanClause.getBooleanClauseOccur());
1385                            }
1386                    }
1387    
1388                    postProcessFullQuery(fullBooleanQuery, searchContext);
1389    
1390                    for (IndexerPostProcessor indexerPostProcessor :
1391                                    _indexerPostProcessors) {
1392    
1393                            indexerPostProcessor.postProcessFullQuery(
1394                                    fullBooleanQuery, searchContext);
1395                    }
1396    
1397                    return fullBooleanQuery;
1398            }
1399    
1400            protected Summary createSummary(Document document) {
1401                    return createSummary(document, Field.TITLE, Field.CONTENT);
1402            }
1403    
1404            protected Summary createSummary(
1405                    Document document, String titleField, String contentField) {
1406    
1407                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1408    
1409                    String title = document.get(prefix + titleField, titleField);
1410                    String content = document.get(prefix + contentField, contentField);
1411    
1412                    return new Summary(title, content);
1413            }
1414    
1415            protected void deleteDocument(long companyId, long field1)
1416                    throws Exception {
1417    
1418                    deleteDocument(companyId, String.valueOf(field1));
1419            }
1420    
1421            protected void deleteDocument(long companyId, long field1, String field2)
1422                    throws Exception {
1423    
1424                    deleteDocument(companyId, String.valueOf(field1), field2);
1425            }
1426    
1427            protected void deleteDocument(long companyId, String field1)
1428                    throws Exception {
1429    
1430                    Document document = new DocumentImpl();
1431    
1432                    document.addUID(getClassName(), field1);
1433    
1434                    SearchEngineUtil.deleteDocument(
1435                            getSearchEngineId(), companyId, document.get(Field.UID),
1436                            _commitImmediately);
1437            }
1438    
1439            protected void deleteDocument(long companyId, String field1, String field2)
1440                    throws Exception {
1441    
1442                    Document document = new DocumentImpl();
1443    
1444                    document.addUID(getClassName(), field1, field2);
1445    
1446                    SearchEngineUtil.deleteDocument(
1447                            getSearchEngineId(), companyId, document.get(Field.UID),
1448                            _commitImmediately);
1449            }
1450    
1451            protected abstract void doDelete(T object) throws Exception;
1452    
1453            protected abstract Document doGetDocument(T object) throws Exception;
1454    
1455            protected String doGetSortField(String orderByCol) {
1456                    return orderByCol;
1457            }
1458    
1459            protected abstract Summary doGetSummary(
1460                            Document document, Locale locale, String snippet,
1461                            PortletRequest portletRequest, PortletResponse portletResponse)
1462                    throws Exception;
1463    
1464            /**
1465             * @deprecated As of 7.0.0, added strictly to support backwards
1466             *             compatibility of {@link
1467             *             Indexer#postProcessSearchQuery(BooleanQuery, SearchContext)}
1468             */
1469            @Deprecated
1470            protected void doPostProcessSearchQuery(
1471                            Indexer<?> indexer, BooleanQuery searchQuery,
1472                            SearchContext searchContext)
1473                    throws Exception {
1474    
1475                    indexer.postProcessSearchQuery(searchQuery, searchContext);
1476    
1477                    for (IndexerPostProcessor indexerPostProcessor :
1478                                    indexer.getIndexerPostProcessors()) {
1479    
1480                            indexerPostProcessor.postProcessSearchQuery(
1481                                    searchQuery, searchContext);
1482                    }
1483            }
1484    
1485            protected abstract void doReindex(String className, long classPK)
1486                    throws Exception;
1487    
1488            protected abstract void doReindex(String[] ids) throws Exception;
1489    
1490            protected abstract void doReindex(T object) throws Exception;
1491    
1492            protected Hits doSearch(SearchContext searchContext)
1493                    throws SearchException {
1494    
1495                    searchContext.setSearchEngineId(getSearchEngineId());
1496    
1497                    Query fullQuery = getFullQuery(searchContext);
1498    
1499                    if (!fullQuery.hasChildren()) {
1500                            BooleanFilter preBooleanFilter = fullQuery.getPreBooleanFilter();
1501    
1502                            fullQuery = new MatchAllQuery();
1503    
1504                            fullQuery.setPreBooleanFilter(preBooleanFilter);
1505                    }
1506    
1507                    QueryConfig queryConfig = searchContext.getQueryConfig();
1508    
1509                    fullQuery.setQueryConfig(queryConfig);
1510    
1511                    return SearchEngineUtil.search(searchContext, fullQuery);
1512            }
1513    
1514            protected Document getBaseModelDocument(
1515                    String portletId, BaseModel<?> baseModel) {
1516    
1517                    return getBaseModelDocument(portletId, baseModel, baseModel);
1518            }
1519    
1520            protected Document getBaseModelDocument(
1521                    String portletId, BaseModel<?> baseModel,
1522                    BaseModel<?> workflowedBaseModel) {
1523    
1524                    Document document = newDocument();
1525    
1526                    String className = baseModel.getModelClassName();
1527    
1528                    long classPK = 0;
1529                    long resourcePrimKey = 0;
1530    
1531                    if (baseModel instanceof ResourcedModel) {
1532                            ResourcedModel resourcedModel = (ResourcedModel)baseModel;
1533    
1534                            classPK = resourcedModel.getResourcePrimKey();
1535                            resourcePrimKey = resourcedModel.getResourcePrimKey();
1536                    }
1537                    else {
1538                            classPK = (Long)baseModel.getPrimaryKeyObj();
1539                    }
1540    
1541                    DocumentHelper documentHelper = new DocumentHelper(document);
1542    
1543                    documentHelper.setEntryKey(className, classPK);
1544    
1545                    document.addUID(className, classPK);
1546    
1547                    List<AssetCategory> assetCategories =
1548                            AssetCategoryLocalServiceUtil.getCategories(className, classPK);
1549    
1550                    long[] assetCategoryIds = ListUtil.toLongArray(
1551                            assetCategories, AssetCategory.CATEGORY_ID_ACCESSOR);
1552    
1553                    document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
1554    
1555                    addSearchAssetCategoryTitles(
1556                            document, Field.ASSET_CATEGORY_TITLES, assetCategories);
1557    
1558                    long classNameId = PortalUtil.getClassNameId(className);
1559    
1560                    List<AssetTag> assetTags = AssetTagLocalServiceUtil.getTags(
1561                            classNameId, classPK);
1562    
1563                    String[] assetTagNames = ListUtil.toArray(
1564                            assetTags, AssetTag.NAME_ACCESSOR);
1565    
1566                    document.addText(Field.ASSET_TAG_NAMES, assetTagNames);
1567    
1568                    long[] assetTagsIds = ListUtil.toLongArray(
1569                            assetTags, AssetTag.TAG_ID_ACCESSOR);
1570    
1571                    document.addKeyword(Field.ASSET_TAG_IDS, assetTagsIds);
1572    
1573                    if (resourcePrimKey > 0) {
1574                            document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
1575                    }
1576    
1577                    if (baseModel instanceof AttachedModel) {
1578                            AttachedModel attachedModel = (AttachedModel)baseModel;
1579    
1580                            documentHelper.setAttachmentOwnerKey(
1581                                    attachedModel.getClassNameId(), attachedModel.getClassPK());
1582                    }
1583    
1584                    if (baseModel instanceof AuditedModel) {
1585                            AuditedModel auditedModel = (AuditedModel)baseModel;
1586    
1587                            document.addKeyword(Field.COMPANY_ID, auditedModel.getCompanyId());
1588                            document.addDate(Field.CREATE_DATE, auditedModel.getCreateDate());
1589                            document.addDate(
1590                                    Field.MODIFIED_DATE, auditedModel.getModifiedDate());
1591                            document.addKeyword(Field.USER_ID, auditedModel.getUserId());
1592    
1593                            String userName = PortalUtil.getUserName(
1594                                    auditedModel.getUserId(), auditedModel.getUserName());
1595    
1596                            document.addKeyword(Field.USER_NAME, userName, true);
1597                    }
1598    
1599                    GroupedModel groupedModel = null;
1600    
1601                    if (baseModel instanceof GroupedModel) {
1602                            groupedModel = (GroupedModel)baseModel;
1603    
1604                            document.addKeyword(
1605                                    Field.GROUP_ID, getSiteGroupId(groupedModel.getGroupId()));
1606                            document.addKeyword(
1607                                    Field.SCOPE_GROUP_ID, groupedModel.getGroupId());
1608                    }
1609    
1610                    if (workflowedBaseModel instanceof WorkflowedModel) {
1611                            WorkflowedModel workflowedModel =
1612                                    (WorkflowedModel)workflowedBaseModel;
1613    
1614                            document.addKeyword(Field.STATUS, workflowedModel.getStatus());
1615                    }
1616    
1617                    if ((groupedModel != null) && (baseModel instanceof TrashedModel)) {
1618                            TrashedModel trashedModel = (TrashedModel)baseModel;
1619    
1620                            if (trashedModel.isInTrash()) {
1621                                    addTrashFields(document, trashedModel);
1622                            }
1623                    }
1624    
1625                    addAssetFields(document, className, classPK);
1626    
1627                    ExpandoBridgeIndexerUtil.addAttributes(
1628                            document, baseModel.getExpandoBridge());
1629    
1630                    return document;
1631            }
1632    
1633            protected String getClassName(SearchContext searchContext) {
1634                    return getClassName();
1635            }
1636    
1637            protected String[] getDefaultSelectedFieldNames() {
1638                    return _defaultSelectedFieldNames;
1639            }
1640    
1641            protected String[] getDefaultSelectedLocalizedFieldNames() {
1642                    return _defaultSelectedLocalizedFieldNames;
1643            }
1644    
1645            protected String getExpandoFieldName(
1646                    SearchContext searchContext, ExpandoBridge expandoBridge,
1647                    String attributeName) {
1648    
1649                    ExpandoColumn expandoColumn =
1650                            ExpandoColumnLocalServiceUtil.getDefaultTableColumn(
1651                                    expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1652                                    attributeName);
1653    
1654                    String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
1655                            attributeName);
1656    
1657                    if (expandoColumn.getType() ==
1658                                    ExpandoColumnConstants.STRING_LOCALIZED) {
1659    
1660                            fieldName = DocumentImpl.getLocalizedName(
1661                                    searchContext.getLocale(), fieldName);
1662                    }
1663    
1664                    return fieldName;
1665            }
1666    
1667            protected Locale getLocale(PortletRequest portletRequest) {
1668                    if (portletRequest != null) {
1669                            return portletRequest.getLocale();
1670                    }
1671    
1672                    return LocaleUtil.getMostRelevantLocale();
1673            }
1674    
1675            protected Set<String> getLocalizedCountryNames(Country country) {
1676                    Set<String> countryNames = new HashSet<>();
1677    
1678                    for (Locale locale : LanguageUtil.getAvailableLocales()) {
1679                            String countryName = country.getName(locale);
1680    
1681                            countryName = StringUtil.toLowerCase(countryName);
1682    
1683                            countryNames.add(countryName);
1684                    }
1685    
1686                    return countryNames;
1687            }
1688    
1689            /**
1690             * @deprecated As of 7.0.0 replaced by {@link #getClassName}
1691             */
1692            @Deprecated
1693            protected String getPortletId(SearchContext searchContext) {
1694                    return StringPool.BLANK;
1695            }
1696    
1697            protected Group getSiteGroup(long groupId) {
1698                    Group group = null;
1699    
1700                    try {
1701                            group = GroupLocalServiceUtil.getGroup(groupId);
1702    
1703                            if (group.isLayout()) {
1704                                    group = group.getParentGroup();
1705                            }
1706                    }
1707                    catch (PortalException pe) {
1708                            if (_log.isDebugEnabled()) {
1709                                    _log.debug("Unable to get site group", pe);
1710                            }
1711                    }
1712    
1713                    return group;
1714            }
1715    
1716            protected long getSiteGroupId(long groupId) {
1717                    Group group = getSiteGroup(groupId);
1718    
1719                    if (group == null) {
1720                            return groupId;
1721                    }
1722    
1723                    return group.getGroupId();
1724            }
1725    
1726            protected Locale getSnippetLocale(Document document, Locale locale) {
1727                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1728    
1729                    String localizedAssetCategoryTitlesName =
1730                            prefix +
1731                            DocumentImpl.getLocalizedName(locale, Field.ASSET_CATEGORY_TITLES);
1732                    String localizedContentName =
1733                            prefix + DocumentImpl.getLocalizedName(locale, Field.CONTENT);
1734                    String localizedDescriptionName =
1735                            prefix + DocumentImpl.getLocalizedName(locale, Field.DESCRIPTION);
1736                    String localizedTitleName =
1737                            prefix + DocumentImpl.getLocalizedName(locale, Field.TITLE);
1738    
1739                    if ((document.getField(localizedAssetCategoryTitlesName) != null) ||
1740                            (document.getField(localizedContentName) != null) ||
1741                            (document.getField(localizedDescriptionName) != null) ||
1742                            (document.getField(localizedTitleName) != null)) {
1743    
1744                            return locale;
1745                    }
1746    
1747                    return null;
1748            }
1749    
1750            protected boolean isStagingGroup(long groupId) {
1751                    Group group = getSiteGroup(groupId);
1752    
1753                    if (group == null) {
1754                            return false;
1755                    }
1756    
1757                    return group.isStagingGroup();
1758            }
1759    
1760            protected boolean isUseSearchResultPermissionFilter(
1761                    SearchContext searchContext) {
1762    
1763                    return isFilterSearch();
1764            }
1765    
1766            protected boolean isVisible(int entryStatus, int queryStatus) {
1767                    if (((queryStatus != WorkflowConstants.STATUS_ANY) &&
1768                             (entryStatus == queryStatus)) ||
1769                            (entryStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1770    
1771                            return true;
1772                    }
1773    
1774                    return false;
1775            }
1776    
1777            protected Document newDocument() {
1778                    return (Document)_document.clone();
1779            }
1780    
1781            protected void populateAddresses(
1782                            Document document, List<Address> addresses, long regionId,
1783                            long countryId)
1784                    throws PortalException {
1785    
1786                    List<String> cities = new ArrayList<>();
1787    
1788                    List<String> countries = new ArrayList<>();
1789    
1790                    if (countryId > 0) {
1791                            try {
1792                                    Country country = CountryServiceUtil.getCountry(countryId);
1793    
1794                                    countries.addAll(getLocalizedCountryNames(country));
1795                            }
1796                            catch (NoSuchCountryException nsce) {
1797                                    if (_log.isWarnEnabled()) {
1798                                            _log.warn(nsce.getMessage());
1799                                    }
1800                            }
1801                    }
1802    
1803                    List<String> regions = new ArrayList<>();
1804    
1805                    if (regionId > 0) {
1806                            try {
1807                                    Region region = RegionServiceUtil.getRegion(regionId);
1808    
1809                                    regions.add(StringUtil.toLowerCase(region.getName()));
1810                            }
1811                            catch (NoSuchRegionException nsre) {
1812                                    if (_log.isWarnEnabled()) {
1813                                            _log.warn(nsre.getMessage());
1814                                    }
1815                            }
1816                    }
1817    
1818                    List<String> streets = new ArrayList<>();
1819                    List<String> zips = new ArrayList<>();
1820    
1821                    for (Address address : addresses) {
1822                            cities.add(StringUtil.toLowerCase(address.getCity()));
1823                            countries.addAll(getLocalizedCountryNames(address.getCountry()));
1824                            regions.add(StringUtil.toLowerCase(address.getRegion().getName()));
1825                            streets.add(StringUtil.toLowerCase(address.getStreet1()));
1826                            streets.add(StringUtil.toLowerCase(address.getStreet2()));
1827                            streets.add(StringUtil.toLowerCase(address.getStreet3()));
1828                            zips.add(StringUtil.toLowerCase(address.getZip()));
1829                    }
1830    
1831                    document.addText("city", cities.toArray(new String[cities.size()]));
1832                    document.addText(
1833                            "country", countries.toArray(new String[countries.size()]));
1834                    document.addText("region", regions.toArray(new String[regions.size()]));
1835                    document.addText("street", streets.toArray(new String[streets.size()]));
1836                    document.addText("zip", zips.toArray(new String[zips.size()]));
1837            }
1838    
1839            protected Map<Locale, String> populateMap(
1840                    AssetEntry assetEntry, Map<Locale, String> map) {
1841    
1842                    String defaultValue = map.get(
1843                            LocaleUtil.fromLanguageId(assetEntry.getDefaultLanguageId()));
1844    
1845                    for (Locale availableLocale : LanguageUtil.getAvailableLocales(
1846                                    assetEntry.getGroupId())) {
1847    
1848                            if (!map.containsKey(availableLocale) ||
1849                                    Validator.isNull(map.get(availableLocale))) {
1850    
1851                                    map.put(availableLocale, defaultValue);
1852                            }
1853                    }
1854    
1855                    return map;
1856            }
1857    
1858            protected void postProcessFullQuery(
1859                            BooleanQuery fullQuery, SearchContext searchContext)
1860                    throws Exception {
1861            }
1862    
1863            protected void processHits(SearchContext searchContext, Hits hits)
1864                    throws SearchException {
1865    
1866                    HitsProcessorRegistryUtil.process(searchContext, hits);
1867            }
1868    
1869            protected void resetFullQuery(SearchContext searchContext) {
1870                    searchContext.clearFullQueryEntryClassNames();
1871    
1872                    for (Indexer<?> indexer : IndexerRegistryUtil.getIndexers()) {
1873                            if (indexer instanceof RelatedEntryIndexer) {
1874                                    RelatedEntryIndexer relatedEntryIndexer =
1875                                            (RelatedEntryIndexer)indexer;
1876    
1877                                    relatedEntryIndexer.updateFullQuery(searchContext);
1878                            }
1879                    }
1880            }
1881    
1882            protected void setDefaultSelectedFieldNames(
1883                    String... defaultLocalizedFieldNames) {
1884    
1885                    _defaultSelectedFieldNames = defaultLocalizedFieldNames;
1886            }
1887    
1888            protected void setDefaultSelectedLocalizedFieldNames(
1889                    String... defaultLocalizedFieldNames) {
1890    
1891                    _defaultSelectedLocalizedFieldNames = defaultLocalizedFieldNames;
1892            }
1893    
1894            protected void setFilterSearch(boolean filterSearch) {
1895                    _filterSearch = filterSearch;
1896            }
1897    
1898            protected void setPermissionAware(boolean permissionAware) {
1899                    _permissionAware = permissionAware;
1900            }
1901    
1902            protected void setStagingAware(boolean stagingAware) {
1903                    _stagingAware = stagingAware;
1904            }
1905    
1906            private static final long _DEFAULT_FOLDER_ID = 0L;
1907    
1908            private static final Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
1909    
1910            private boolean _commitImmediately;
1911            private String[] _defaultSelectedFieldNames;
1912            private String[] _defaultSelectedLocalizedFieldNames;
1913            private final Document _document = new DocumentImpl();
1914            private boolean _filterSearch;
1915            private Boolean _indexerEnabled;
1916            private IndexerPostProcessor[] _indexerPostProcessors =
1917                    new IndexerPostProcessor[0];
1918            private boolean _permissionAware;
1919            private String _searchEngineId;
1920            private boolean _selectAllLocales;
1921            private boolean _stagingAware = true;
1922    
1923    }