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