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