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