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