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