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