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