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