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