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", 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 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                    searchContext.setAttribute("relatedClassName", Boolean.TRUE);
605    
606                    String[] relatedEntryClassNames = (String[])searchContext.getAttribute(
607                            "relatedEntryClassNames");
608    
609                    if (ArrayUtil.isEmpty(relatedEntryClassNames)) {
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                    searchContext.setAttribute("relatedClassName", Boolean.FALSE);
639            }
640    
641            protected void addSearchArrayQuery(
642                            BooleanQuery searchQuery, SearchContext searchContext, String field)
643                    throws Exception {
644    
645                    if (Validator.isNull(field)) {
646                            return;
647                    }
648    
649                    Object fieldValues = searchContext.getAttribute(field);
650    
651                    if (fieldValues == null) {
652                            return;
653                    }
654    
655                    BooleanQuery fieldQuery = null;
656    
657                    if (fieldValues instanceof int[]) {
658                            int[] fieldValuesArray = (int[])fieldValues;
659    
660                            if (fieldValuesArray.length == 0) {
661                                    return;
662                            }
663    
664                            fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
665    
666                            for (int fieldValue : fieldValuesArray) {
667                                    fieldQuery.addTerm(field, fieldValue);
668                            }
669                    }
670                    else if (fieldValues instanceof Integer[]) {
671                            Integer[] fieldValuesArray = (Integer[])fieldValues;
672    
673                            if (fieldValuesArray.length == 0) {
674                                    return;
675                            }
676    
677                            fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
678    
679                            for (Integer fieldValue : fieldValuesArray) {
680                                    fieldQuery.addTerm(field, fieldValue);
681                            }
682                    }
683                    else if (fieldValues instanceof long[]) {
684                            long[] fieldValuesArray = (long[])fieldValues;
685    
686                            if (fieldValuesArray.length == 0) {
687                                    return;
688                            }
689    
690                            fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
691    
692                            for (long fieldValue : fieldValuesArray) {
693                                    fieldQuery.addTerm(field, fieldValue);
694                            }
695                    }
696                    else if (fieldValues instanceof Long[]) {
697                            Long[] fieldValuesArray = (Long[])fieldValues;
698    
699                            if (fieldValuesArray.length == 0) {
700                                    return;
701                            }
702    
703                            fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
704    
705                            for (Long fieldValue : fieldValuesArray) {
706                                    fieldQuery.addTerm(field, fieldValue);
707                            }
708                    }
709                    else if (fieldValues instanceof short[]) {
710                            short[] fieldValuesArray = (short[])fieldValues;
711    
712                            if (fieldValuesArray.length == 0) {
713                                    return;
714                            }
715    
716                            fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
717    
718                            for (short fieldValue : fieldValuesArray) {
719                                    fieldQuery.addTerm(field, fieldValue);
720                            }
721                    }
722                    else if (fieldValues instanceof Short[]) {
723                            Short[] fieldValuesArray = (Short[])fieldValues;
724    
725                            if (fieldValuesArray.length == 0) {
726                                    return;
727                            }
728    
729                            fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
730    
731                            for (Short fieldValue : fieldValuesArray) {
732                                    fieldQuery.addTerm(field, fieldValue);
733                            }
734                    }
735    
736                    if (fieldQuery != null) {
737                            if (searchContext.isAndSearch()) {
738                                    searchQuery.add(fieldQuery, BooleanClauseOccur.MUST);
739                            }
740                            else {
741                                    searchQuery.add(fieldQuery, BooleanClauseOccur.SHOULD);
742                            }
743                    }
744            }
745    
746            protected void addSearchAssetCategoryIds(
747                            BooleanQuery contextQuery, SearchContext searchContext)
748                    throws Exception {
749    
750                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
751    
752                    multiValueFacet.setFieldName(Field.ASSET_CATEGORY_IDS);
753                    multiValueFacet.setStatic(true);
754                    multiValueFacet.setValues(searchContext.getAssetCategoryIds());
755    
756                    searchContext.addFacet(multiValueFacet);
757            }
758    
759            protected void addSearchAssetCategoryTitles(
760                    Document document, String field, List<AssetCategory> assetCategories) {
761    
762                    Map<Locale, List<String>> assetCategoryTitles =
763                            new HashMap<Locale, List<String>>();
764    
765                    Locale defaultLocale = LocaleUtil.getDefault();
766    
767                    for (AssetCategory assetCategory : assetCategories) {
768                            Map<Locale, String> titleMap = assetCategory.getTitleMap();
769    
770                            for (Map.Entry<Locale, String> entry : titleMap.entrySet()) {
771                                    Locale locale = entry.getKey();
772                                    String title = entry.getValue();
773    
774                                    if (Validator.isNull(title)) {
775                                            continue;
776                                    }
777    
778                                    List<String> titles = assetCategoryTitles.get(locale);
779    
780                                    if (titles == null) {
781                                            titles = new ArrayList<String>();
782    
783                                            assetCategoryTitles.put(locale, titles);
784                                    }
785    
786                                    titles.add(title);
787                            }
788                    }
789    
790                    for (Map.Entry<Locale, List<String>> entry :
791                                    assetCategoryTitles.entrySet()) {
792    
793                            Locale locale = entry.getKey();
794                            List<String> titles = entry.getValue();
795    
796                            String[] titlesArray = titles.toArray(new String[0]);
797    
798                            if (locale.equals(defaultLocale)) {
799                                    document.addKeyword(field, titlesArray);
800                            }
801    
802                            document.addKeyword(
803                                    field.concat(StringPool.UNDERLINE).concat(locale.toString()),
804                                    titlesArray);
805                    }
806            }
807    
808            protected void addSearchAssetTagNames(
809                            BooleanQuery contextQuery, SearchContext searchContext)
810                    throws Exception {
811    
812                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
813    
814                    multiValueFacet.setFieldName(Field.ASSET_TAG_NAMES);
815                    multiValueFacet.setStatic(true);
816                    multiValueFacet.setValues(searchContext.getAssetTagNames());
817    
818                    searchContext.addFacet(multiValueFacet);
819            }
820    
821            protected void addSearchClassTypeIds(
822                            BooleanQuery contextQuery, SearchContext searchContext)
823                    throws Exception {
824    
825                    long[] classTypeIds = searchContext.getClassTypeIds();
826    
827                    if ((classTypeIds == null) || (classTypeIds.length <= 0)) {
828                            return;
829                    }
830    
831                    BooleanQuery classTypeIdsQuery = BooleanQueryFactoryUtil.create(
832                            searchContext);
833    
834                    for (long classTypeId : classTypeIds) {
835                            classTypeIdsQuery.addTerm(Field.CLASS_TYPE_ID, classTypeId);
836                    }
837    
838                    contextQuery.add(classTypeIdsQuery, BooleanClauseOccur.MUST);
839            }
840    
841            protected void addSearchDDMStruture(
842                            BooleanQuery searchQuery, SearchContext searchContext,
843                            DDMStructure ddmStructure)
844                    throws Exception {
845    
846                    Set<String> fieldNames = ddmStructure.getFieldNames();
847    
848                    for (String fieldName : fieldNames) {
849                            String indexType = ddmStructure.getFieldProperty(
850                                    fieldName, "indexType");
851    
852                            if (Validator.isNull(indexType)) {
853                                    continue;
854                            }
855    
856                            String name = DDMIndexerUtil.encodeName(
857                                    ddmStructure.getStructureId(), fieldName,
858                                    searchContext.getLocale());
859    
860                            boolean like = false;
861    
862                            if (indexType.equals("text")) {
863                                    like = true;
864                            }
865    
866                            addSearchTerm(searchQuery, searchContext, name, like);
867                    }
868            }
869    
870            protected void addSearchEntryClassNames(
871                            BooleanQuery contextQuery, SearchContext searchContext)
872                    throws Exception {
873    
874                    Facet facet = new AssetEntriesFacet(searchContext);
875    
876                    facet.setStatic(true);
877    
878                    searchContext.addFacet(facet);
879            }
880    
881            protected void addSearchExpando(
882                            BooleanQuery searchQuery, SearchContext searchContext,
883                            String keywords)
884                    throws Exception {
885    
886                    ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
887                            searchContext.getCompanyId(), getClassName(searchContext));
888    
889                    Set<String> attributeNames = SetUtil.fromEnumeration(
890                            expandoBridge.getAttributeNames());
891    
892                    for (String attributeName : attributeNames) {
893                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
894                                    attributeName);
895    
896                            int indexType = GetterUtil.getInteger(
897                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
898    
899                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
900                                    String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
901                                            attributeName);
902    
903                                    if (Validator.isNotNull(keywords)) {
904                                            if (searchContext.isAndSearch()) {
905                                                    searchQuery.addRequiredTerm(fieldName, keywords);
906                                            }
907                                            else {
908                                                    searchQuery.addTerm(fieldName, keywords);
909                                            }
910                                    }
911                            }
912                    }
913            }
914    
915            protected void addSearchFolderId(
916                            BooleanQuery contextQuery, SearchContext searchContext)
917                    throws Exception {
918    
919                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
920    
921                    multiValueFacet.setFieldName(Field.FOLDER_ID);
922                    multiValueFacet.setStatic(true);
923                    multiValueFacet.setValues(searchContext.getFolderIds());
924    
925                    searchContext.addFacet(multiValueFacet);
926            }
927    
928            protected void addSearchGroupId(
929                            BooleanQuery contextQuery, SearchContext searchContext)
930                    throws Exception {
931    
932                    Facet facet = new ScopeFacet(searchContext);
933    
934                    facet.setStatic(true);
935    
936                    searchContext.addFacet(facet);
937            }
938    
939            protected void addSearchKeywords(
940                            BooleanQuery searchQuery, SearchContext searchContext)
941                    throws Exception {
942    
943                    String keywords = searchContext.getKeywords();
944    
945                    if (Validator.isNull(keywords)) {
946                            return;
947                    }
948    
949                    searchQuery.addTerms(Field.KEYWORDS, keywords, searchContext.isLike());
950    
951                    addSearchExpando(searchQuery, searchContext, keywords);
952            }
953    
954            protected void addSearchLayout(
955                            BooleanQuery contextQuery, SearchContext searchContext)
956                    throws Exception {
957    
958                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
959    
960                    multiValueFacet.setFieldName(Field.LAYOUT_UUID);
961                    multiValueFacet.setStatic(true);
962    
963                    searchContext.addFacet(multiValueFacet);
964            }
965    
966            protected void addSearchLocalizedTerm(
967                            BooleanQuery searchQuery, SearchContext searchContext, String field,
968                            boolean like)
969                    throws Exception {
970    
971                    addSearchTerm(searchQuery, searchContext, field, like);
972                    addSearchTerm(
973                            searchQuery, searchContext,
974                            DocumentImpl.getLocalizedName(searchContext.getLocale(), field),
975                            like);
976            }
977    
978            protected void addSearchTerm(
979                            BooleanQuery searchQuery, SearchContext searchContext, String field,
980                            boolean like)
981                    throws Exception {
982    
983                    if (Validator.isNull(field)) {
984                            return;
985                    }
986    
987                    String value = null;
988    
989                    Serializable serializable = searchContext.getAttribute(field);
990    
991                    if (serializable != null) {
992                            Class<?> clazz = serializable.getClass();
993    
994                            if (clazz.isArray()) {
995                                    value = StringUtil.merge((Object[])serializable);
996                            }
997                            else {
998                                    value = GetterUtil.getString(serializable);
999                            }
1000                    }
1001                    else {
1002                            value = GetterUtil.getString(serializable);
1003                    }
1004    
1005                    if (Validator.isNotNull(value) &&
1006                            (searchContext.getFacet(field) != null)) {
1007    
1008                            return;
1009                    }
1010    
1011                    if (Validator.isNull(value)) {
1012                            value = searchContext.getKeywords();
1013                    }
1014    
1015                    if (Validator.isNull(value)) {
1016                            return;
1017                    }
1018    
1019                    if (searchContext.isAndSearch()) {
1020                            searchQuery.addRequiredTerm(field, value, like);
1021                    }
1022                    else {
1023                            searchQuery.addTerm(field, value, like);
1024                    }
1025            }
1026    
1027            protected void addSearchUserId(
1028                            BooleanQuery contextQuery, SearchContext searchContext)
1029                    throws Exception {
1030    
1031                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
1032    
1033                    multiValueFacet.setFieldName(Field.USER_ID);
1034                    multiValueFacet.setStatic(true);
1035    
1036                    long userId = GetterUtil.getLong(
1037                            searchContext.getAttribute(Field.USER_ID));
1038    
1039                    if (userId > 0) {
1040                            multiValueFacet.setValues(new long[] {userId});
1041                    }
1042    
1043                    searchContext.addFacet(multiValueFacet);
1044            }
1045    
1046            protected void addStagingGroupKeyword(Document document, long groupId)
1047                    throws Exception {
1048    
1049                    if (!isStagingAware()) {
1050                            return;
1051                    }
1052    
1053                    boolean stagingGroup = false;
1054    
1055                    Group group = GroupLocalServiceUtil.getGroup(groupId);
1056    
1057                    if (group.isLayout()) {
1058                            group = GroupLocalServiceUtil.getGroup(group.getParentGroupId());
1059                    }
1060    
1061                    if (group.isStagingGroup()) {
1062                            stagingGroup = true;
1063                    }
1064    
1065                    document.addKeyword(Field.STAGING_GROUP, stagingGroup);
1066            }
1067    
1068            protected void addStatus(
1069                            BooleanQuery contextQuery, SearchContext searchContext)
1070                    throws Exception {
1071    
1072                    int status = GetterUtil.getInteger(
1073                            searchContext.getAttribute(Field.STATUS),
1074                            WorkflowConstants.STATUS_APPROVED);
1075    
1076                    if (status != WorkflowConstants.STATUS_ANY) {
1077                            contextQuery.addRequiredTerm(Field.STATUS, status);
1078                    }
1079                    else {
1080                            BooleanQuery statusQuery = BooleanQueryFactoryUtil.create(
1081                                    searchContext);
1082    
1083                            statusQuery.addTerm(
1084                                    Field.STATUS, WorkflowConstants.STATUS_IN_TRASH);
1085    
1086                            contextQuery.add(statusQuery, BooleanClauseOccur.MUST_NOT);
1087                    }
1088            }
1089    
1090            protected void addTrashFields(
1091                            Document document, String className, long classPK, Date removedDate,
1092                            String removedByUserName, String type)
1093                    throws SystemException {
1094    
1095                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
1096                            className, classPK);
1097    
1098                    if (removedDate == null) {
1099                            if (trashEntry != null) {
1100                                    removedDate = trashEntry.getCreateDate();
1101                            }
1102                            else {
1103                                    removedDate = new Date();
1104                            }
1105                    }
1106    
1107                    document.addDate(Field.REMOVED_DATE, removedDate);
1108    
1109                    if (removedByUserName == null) {
1110                            if (trashEntry != null) {
1111                                    removedByUserName = trashEntry.getUserName();
1112                            }
1113                            else {
1114                                    ServiceContext serviceContext =
1115                                            ServiceContextThreadLocal.getServiceContext();
1116    
1117                                    if (serviceContext != null) {
1118                                            try {
1119                                                    User user = UserLocalServiceUtil.getUser(
1120                                                            serviceContext.getUserId());
1121    
1122                                                    removedByUserName = user.getFullName();
1123                                            }
1124                                            catch (PortalException pe) {
1125                                            }
1126                                    }
1127                            }
1128                    }
1129    
1130                    if (Validator.isNotNull(removedByUserName)) {
1131                            document.addKeyword(
1132                                    Field.REMOVED_BY_USER_NAME, removedByUserName, true);
1133                    }
1134    
1135                    if (type == null) {
1136                            if (trashEntry != null) {
1137                                    TrashHandler trashHandler =
1138                                            TrashHandlerRegistryUtil.getTrashHandler(
1139                                                    trashEntry.getClassName());
1140    
1141                                    try {
1142                                            TrashRenderer trashRenderer = trashHandler.getTrashRenderer(
1143                                                    trashEntry.getClassPK());
1144    
1145                                            type = trashRenderer.getType();
1146                                    }
1147                                    catch (PortalException pe) {
1148                                    }
1149                            }
1150                    }
1151    
1152                    if (Validator.isNotNull(type)) {
1153                            document.addKeyword(Field.TYPE, type, true);
1154                    }
1155            }
1156    
1157            protected BooleanQuery createFullQuery(
1158                            BooleanQuery contextQuery, SearchContext searchContext)
1159                    throws Exception {
1160    
1161                    BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
1162                            searchContext);
1163    
1164                    addSearchKeywords(searchQuery, searchContext);
1165                    postProcessSearchQuery(searchQuery, searchContext);
1166    
1167                    for (IndexerPostProcessor indexerPostProcessor :
1168                                    _indexerPostProcessors) {
1169    
1170                            indexerPostProcessor.postProcessSearchQuery(
1171                                    searchQuery, searchContext);
1172                    }
1173    
1174                    Map<String, Facet> facets = searchContext.getFacets();
1175    
1176                    for (Facet facet : facets.values()) {
1177                            BooleanClause facetClause = facet.getFacetClause();
1178    
1179                            if (facetClause != null) {
1180                                    contextQuery.add(
1181                                            facetClause.getQuery(),
1182                                            facetClause.getBooleanClauseOccur());
1183                            }
1184                    }
1185    
1186                    BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
1187    
1188                    fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
1189    
1190                    if (searchQuery.hasClauses()) {
1191                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1192                    }
1193    
1194                    BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
1195    
1196                    if (booleanClauses != null) {
1197                            for (BooleanClause booleanClause : booleanClauses) {
1198                                    fullQuery.add(
1199                                            booleanClause.getQuery(),
1200                                            booleanClause.getBooleanClauseOccur());
1201                            }
1202                    }
1203    
1204                    postProcessFullQuery(fullQuery, searchContext);
1205    
1206                    for (IndexerPostProcessor indexerPostProcessor :
1207                                    _indexerPostProcessors) {
1208    
1209                            indexerPostProcessor.postProcessFullQuery(fullQuery, searchContext);
1210                    }
1211    
1212                    return fullQuery;
1213            }
1214    
1215            protected Summary createLocalizedSummary(Document document, Locale locale) {
1216                    return createLocalizedSummary(
1217                            document, locale, Field.TITLE, Field.CONTENT);
1218            }
1219    
1220            protected Summary createLocalizedSummary(
1221                    Document document, Locale locale, String titleField,
1222                    String contentField) {
1223    
1224                    Locale snippetLocale = getSnippetLocale(document, locale);
1225    
1226                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1227    
1228                    String title = document.get(
1229                            snippetLocale, prefix + titleField, titleField);
1230    
1231                    String content = document.get(
1232                            snippetLocale, prefix + contentField, contentField);
1233    
1234                    return new Summary(snippetLocale, title, content, null);
1235            }
1236    
1237            protected Summary createSummary(Document document) {
1238                    return createSummary(document, Field.TITLE, Field.CONTENT);
1239            }
1240    
1241            protected Summary createSummary(
1242                    Document document, String titleField, String contentField) {
1243    
1244                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1245    
1246                    String title = document.get(prefix + titleField, titleField);
1247                    String content = document.get(prefix + contentField, contentField);
1248    
1249                    return new Summary(title, content, null);
1250            }
1251    
1252            protected void deleteDocument(long companyId, long field1)
1253                    throws Exception {
1254    
1255                    deleteDocument(companyId, String.valueOf(field1));
1256            }
1257    
1258            protected void deleteDocument(long companyId, long field1, String field2)
1259                    throws Exception {
1260    
1261                    deleteDocument(companyId, String.valueOf(field1), field2);
1262            }
1263    
1264            protected void deleteDocument(long companyId, String field1)
1265                    throws Exception {
1266    
1267                    Document document = new DocumentImpl();
1268    
1269                    document.addUID(getPortletId(), field1);
1270    
1271                    SearchEngineUtil.deleteDocument(
1272                            getSearchEngineId(), companyId, document.get(Field.UID));
1273            }
1274    
1275            protected void deleteDocument(long companyId, String field1, String field2)
1276                    throws Exception {
1277    
1278                    Document document = new DocumentImpl();
1279    
1280                    document.addUID(getPortletId(), field1, field2);
1281    
1282                    SearchEngineUtil.deleteDocument(
1283                            getSearchEngineId(), companyId, document.get(Field.UID));
1284            }
1285    
1286            protected abstract void doDelete(Object obj) throws Exception;
1287    
1288            protected abstract Document doGetDocument(Object obj) throws Exception;
1289    
1290            protected String doGetSortField(String orderByCol) {
1291                    return orderByCol;
1292            }
1293    
1294            protected abstract Summary doGetSummary(
1295                            Document document, Locale locale, String snippet,
1296                            PortletURL portletURL)
1297                    throws Exception;
1298    
1299            protected abstract void doReindex(Object obj) throws Exception;
1300    
1301            protected abstract void doReindex(String className, long classPK)
1302                    throws Exception;
1303    
1304            protected abstract void doReindex(String[] ids) throws Exception;
1305    
1306            protected void doReindexDDMStructures(List<Long> structureIds)
1307                    throws Exception {
1308            }
1309    
1310            protected Hits filterSearch(
1311                    Hits hits, PermissionChecker permissionChecker,
1312                    SearchContext searchContext) {
1313    
1314                    List<Document> docs = new ArrayList<Document>();
1315                    List<Float> scores = new ArrayList<Float>();
1316    
1317                    int start = searchContext.getStart();
1318                    int end = searchContext.getEnd();
1319    
1320                    String paginationType = GetterUtil.getString(
1321                            searchContext.getAttribute("paginationType"), "more");
1322    
1323                    boolean hasMore = false;
1324    
1325                    Document[] documents = hits.getDocs();
1326    
1327                    int excludeDocsSize = 0;
1328    
1329                    for (int i = 0; i < documents.length; i++) {
1330                            try {
1331                                    Document document = documents[i];
1332    
1333                                    String entryClassName = document.get(Field.ENTRY_CLASS_NAME);
1334                                    long entryClassPK = GetterUtil.getLong(
1335                                            document.get(Field.ENTRY_CLASS_PK));
1336    
1337                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
1338                                            entryClassName);
1339    
1340                                    if ((indexer.isFilterSearch() &&
1341                                             indexer.hasPermission(
1342                                                     permissionChecker, entryClassName, entryClassPK,
1343                                                     ActionKeys.VIEW)) ||
1344                                            !indexer.isFilterSearch() ||
1345                                            !indexer.isPermissionAware()) {
1346    
1347                                            docs.add(document);
1348                                            scores.add(hits.score(i));
1349                                    }
1350                                    else {
1351                                            excludeDocsSize++;
1352                                    }
1353                            }
1354                            catch (Exception e) {
1355                                    excludeDocsSize++;
1356                            }
1357    
1358                            if (paginationType.equals("more") && (end > 0) &&
1359                                    (end < documents.length) && (docs.size() >= end)) {
1360    
1361                                    hasMore = true;
1362    
1363                                    break;
1364                            }
1365                    }
1366    
1367                    int length = docs.size();
1368    
1369                    if (hasMore) {
1370                            length = documents.length - excludeDocsSize;
1371                    }
1372    
1373                    hits.setLength(length);
1374    
1375                    if ((start != QueryUtil.ALL_POS) && (end != QueryUtil.ALL_POS)) {
1376                            if (end > length) {
1377                                    end = length;
1378                            }
1379    
1380                            docs = docs.subList(start, end);
1381                    }
1382    
1383                    hits.setDocs(docs.toArray(new Document[docs.size()]));
1384                    hits.setScores(scores.toArray(new Float[docs.size()]));
1385    
1386                    hits.setSearchTime(
1387                            (float)(System.currentTimeMillis() - hits.getStart()) /
1388                                    Time.SECOND);
1389    
1390                    return hits;
1391            }
1392    
1393            protected Document getBaseModelDocument(
1394                            String portletId, BaseModel<?> baseModel)
1395                    throws SystemException {
1396    
1397                    return getBaseModelDocument(portletId, baseModel, baseModel);
1398            }
1399    
1400            protected Document getBaseModelDocument(
1401                            String portletId, BaseModel<?> baseModel,
1402                            BaseModel<?> workflowedBaseModel)
1403                    throws SystemException {
1404    
1405                    Document document = newDocument();
1406    
1407                    String className = baseModel.getModelClassName();
1408    
1409                    long classPK = 0;
1410                    long resourcePrimKey = 0;
1411    
1412                    if (baseModel instanceof ResourcedModel) {
1413                            ResourcedModel resourcedModel = (ResourcedModel)baseModel;
1414    
1415                            classPK = resourcedModel.getResourcePrimKey();
1416                            resourcePrimKey = resourcedModel.getResourcePrimKey();
1417                    }
1418                    else {
1419                            classPK = (Long)baseModel.getPrimaryKeyObj();
1420                    }
1421    
1422                    document.addUID(portletId, classPK);
1423    
1424                    List<AssetCategory> assetCategories =
1425                            AssetCategoryLocalServiceUtil.getCategories(className, classPK);
1426    
1427                    long[] assetCategoryIds = StringUtil.split(
1428                            ListUtil.toString(
1429                                    assetCategories, AssetCategory.CATEGORY_ID_ACCESSOR),
1430                            0L);
1431    
1432                    document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
1433    
1434                    addSearchAssetCategoryTitles(
1435                            document, Field.ASSET_CATEGORY_TITLES, assetCategories);
1436    
1437                    String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(
1438                            className, classPK);
1439    
1440                    document.addText(Field.ASSET_TAG_NAMES, assetTagNames);
1441    
1442                    List<AssetTag> assetTags = AssetTagLocalServiceUtil.getTags(
1443                            className, classPK);
1444    
1445                    long[] assetTagsIds = StringUtil.split(
1446                            ListUtil.toString(assetTags, AssetTag.TAG_ID_ACCESSOR), 0L);
1447    
1448                    document.addKeyword(Field.ASSET_TAG_IDS, assetTagsIds);
1449    
1450                    document.addKeyword(Field.ENTRY_CLASS_NAME, className);
1451                    document.addKeyword(Field.ENTRY_CLASS_PK, classPK);
1452                    document.addKeyword(Field.PORTLET_ID, portletId);
1453    
1454                    if (resourcePrimKey > 0) {
1455                            document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
1456                    }
1457    
1458                    if (baseModel instanceof AttachedModel) {
1459                            AttachedModel attachedModel = (AttachedModel)baseModel;
1460    
1461                            document.addKeyword(
1462                                    Field.CLASS_NAME_ID, attachedModel.getClassNameId());
1463                            document.addKeyword(Field.CLASS_PK, attachedModel.getClassPK());
1464                    }
1465    
1466                    if (baseModel instanceof AuditedModel) {
1467                            AuditedModel auditedModel = (AuditedModel)baseModel;
1468    
1469                            document.addKeyword(Field.COMPANY_ID, auditedModel.getCompanyId());
1470                            document.addDate(Field.CREATE_DATE, auditedModel.getCreateDate());
1471                            document.addDate(
1472                                    Field.MODIFIED_DATE, auditedModel.getModifiedDate());
1473                            document.addKeyword(Field.USER_ID, auditedModel.getUserId());
1474    
1475                            String userName = PortalUtil.getUserName(
1476                                    auditedModel.getUserId(), auditedModel.getUserName());
1477    
1478                            document.addKeyword(Field.USER_NAME, userName, true);
1479                    }
1480    
1481                    GroupedModel groupedModel = null;
1482    
1483                    if (baseModel instanceof GroupedModel) {
1484                            groupedModel = (GroupedModel)baseModel;
1485    
1486                            document.addKeyword(
1487                                    Field.GROUP_ID, getSiteGroupId(groupedModel.getGroupId()));
1488                            document.addKeyword(
1489                                    Field.SCOPE_GROUP_ID, groupedModel.getGroupId());
1490                    }
1491    
1492                    if (workflowedBaseModel instanceof WorkflowedModel) {
1493                            WorkflowedModel workflowedModel =
1494                                    (WorkflowedModel)workflowedBaseModel;
1495    
1496                            document.addKeyword(Field.STATUS, workflowedModel.getStatus());
1497    
1498                            if ((groupedModel != null) && workflowedModel.isInTrash()) {
1499                                    addTrashFields(document, className, classPK, null, null, null);
1500                            }
1501                    }
1502    
1503                    addAssetFields(document, className, classPK);
1504    
1505                    ExpandoBridgeIndexerUtil.addAttributes(
1506                            document, baseModel.getExpandoBridge());
1507    
1508                    return document;
1509            }
1510    
1511            protected String getClassName(SearchContext searchContext) {
1512                    String[] classNames = getClassNames();
1513    
1514                    return classNames[0];
1515            }
1516    
1517            protected Set<String> getLocalizedCountryNames(Country country) {
1518                    Set<String> countryNames = new HashSet<String>();
1519    
1520                    Locale[] locales = LanguageUtil.getAvailableLocales();
1521    
1522                    for (Locale locale : locales) {
1523                            String countryName = country.getName(locale);
1524    
1525                            countryName = countryName.toLowerCase();
1526    
1527                            countryNames.add(countryName);
1528                    }
1529    
1530                    return countryNames;
1531            }
1532    
1533            /**
1534             * @deprecated As of 6.2.0 renamed to {@link #getSiteGroupId(long)}
1535             */
1536            protected long getParentGroupId(long groupId) {
1537                    return getSiteGroupId(groupId);
1538            }
1539    
1540            protected abstract String getPortletId(SearchContext searchContext);
1541    
1542            protected long getSiteGroupId(long groupId) {
1543                    long siteGroupId = groupId;
1544    
1545                    try {
1546                            Group group = GroupLocalServiceUtil.getGroup(groupId);
1547    
1548                            if (group.isLayout()) {
1549                                    siteGroupId = group.getParentGroupId();
1550                            }
1551                    }
1552                    catch (Exception e) {
1553                    }
1554    
1555                    return siteGroupId;
1556            }
1557    
1558            protected Locale getSnippetLocale(Document document, Locale locale) {
1559                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1560    
1561                    String localizedContentName =
1562                            prefix + DocumentImpl.getLocalizedName(locale, Field.CONTENT);
1563                    String localizedDescriptionName =
1564                            prefix + DocumentImpl.getLocalizedName(locale, Field.DESCRIPTION);
1565                    String localizedTitleName =
1566                            prefix + DocumentImpl.getLocalizedName(locale, Field.TITLE);
1567    
1568                    if ((document.getField(localizedContentName) != null) ||
1569                            (document.getField(localizedDescriptionName) != null) ||
1570                            (document.getField(localizedTitleName) != null)) {
1571    
1572                            return locale;
1573                    }
1574    
1575                    return null;
1576            }
1577    
1578            protected Document newDocument() {
1579                    return (Document)_document.clone();
1580            }
1581    
1582            protected void populateAddresses(
1583                            Document document, List<Address> addresses, long regionId,
1584                            long countryId)
1585                    throws PortalException, SystemException {
1586    
1587                    List<String> cities = new ArrayList<String>();
1588    
1589                    List<String> countries = new ArrayList<String>();
1590    
1591                    if (countryId > 0) {
1592                            try {
1593                                    Country country = CountryServiceUtil.getCountry(countryId);
1594    
1595                                    countries.addAll(getLocalizedCountryNames(country));
1596                            }
1597                            catch (NoSuchCountryException nsce) {
1598                                    if (_log.isWarnEnabled()) {
1599                                            _log.warn(nsce.getMessage());
1600                                    }
1601                            }
1602                    }
1603    
1604                    List<String> regions = new ArrayList<String>();
1605    
1606                    if (regionId > 0) {
1607                            try {
1608                                    Region region = RegionServiceUtil.getRegion(regionId);
1609    
1610                                    regions.add(region.getName().toLowerCase());
1611                            }
1612                            catch (NoSuchRegionException nsre) {
1613                                    if (_log.isWarnEnabled()) {
1614                                            _log.warn(nsre.getMessage());
1615                                    }
1616                            }
1617                    }
1618    
1619                    List<String> streets = new ArrayList<String>();
1620                    List<String> zips = new ArrayList<String>();
1621    
1622                    for (Address address : addresses) {
1623                            cities.add(address.getCity().toLowerCase());
1624                            countries.addAll(getLocalizedCountryNames(address.getCountry()));
1625                            regions.add(address.getRegion().getName().toLowerCase());
1626                            streets.add(address.getStreet1().toLowerCase());
1627                            streets.add(address.getStreet2().toLowerCase());
1628                            streets.add(address.getStreet3().toLowerCase());
1629                            zips.add(address.getZip().toLowerCase());
1630                    }
1631    
1632                    document.addText("city", cities.toArray(new String[cities.size()]));
1633                    document.addText(
1634                            "country", countries.toArray(new String[countries.size()]));
1635                    document.addText("region", regions.toArray(new String[regions.size()]));
1636                    document.addText("street", streets.toArray(new String[streets.size()]));
1637                    document.addText("zip", zips.toArray(new String[zips.size()]));
1638            }
1639    
1640            protected void postProcessFullQuery(
1641                            BooleanQuery fullQuery, SearchContext searchContext)
1642                    throws Exception {
1643            }
1644    
1645            protected void processHits(SearchContext searchContext, Hits hits)
1646                    throws SearchException {
1647    
1648                    HitsProcessor hitsProcessor =
1649                            HitsProcessorRegistryUtil.getDefaultHitsProcessor();
1650    
1651                    if (hitsProcessor != null) {
1652                            hitsProcessor.process(searchContext, hits);
1653                    }
1654            }
1655    
1656            protected void setFilterSearch(boolean filterSearch) {
1657                    _filterSearch = filterSearch;
1658            }
1659    
1660            protected void setIndexerEnabled(boolean indexerEnabled) {
1661                    _indexerEnabled = indexerEnabled;
1662            }
1663    
1664            protected void setPermissionAware(boolean permissionAware) {
1665                    _permissionAware = permissionAware;
1666            }
1667    
1668            protected void setSortableTextFields(String[] sortableTextFields) {
1669                    _document.setSortableTextFields(sortableTextFields);
1670            }
1671    
1672            protected void setStagingAware(boolean stagingAware) {
1673                    _stagingAware = stagingAware;
1674            }
1675    
1676            private static Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
1677    
1678            private Document _document;
1679            private boolean _filterSearch;
1680            private boolean _indexerEnabled = true;
1681            private IndexerPostProcessor[] _indexerPostProcessors =
1682                    new IndexerPostProcessor[0];
1683            private boolean _permissionAware;
1684            private String _searchEngineId;
1685            private boolean _stagingAware = true;
1686    
1687    }