001    /**
002     * Copyright (c) 2000-2011 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.dao.orm.QueryUtil;
021    import com.liferay.portal.kernel.exception.PortalException;
022    import com.liferay.portal.kernel.exception.SystemException;
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.util.GetterUtil;
030    import com.liferay.portal.kernel.util.ListUtil;
031    import com.liferay.portal.kernel.util.PropsKeys;
032    import com.liferay.portal.kernel.util.PropsUtil;
033    import com.liferay.portal.kernel.util.SetUtil;
034    import com.liferay.portal.kernel.util.Time;
035    import com.liferay.portal.kernel.util.UnicodeProperties;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.model.Address;
038    import com.liferay.portal.model.AttachedModel;
039    import com.liferay.portal.model.AuditedModel;
040    import com.liferay.portal.model.BaseModel;
041    import com.liferay.portal.model.Country;
042    import com.liferay.portal.model.Group;
043    import com.liferay.portal.model.GroupedModel;
044    import com.liferay.portal.model.Region;
045    import com.liferay.portal.model.ResourcedModel;
046    import com.liferay.portal.model.WorkflowedModel;
047    import com.liferay.portal.security.permission.ActionKeys;
048    import com.liferay.portal.security.permission.PermissionChecker;
049    import com.liferay.portal.security.permission.PermissionThreadLocal;
050    import com.liferay.portal.service.CountryServiceUtil;
051    import com.liferay.portal.service.GroupLocalServiceUtil;
052    import com.liferay.portal.service.RegionServiceUtil;
053    import com.liferay.portal.util.PortalUtil;
054    import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
055    import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
056    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
057    import com.liferay.portlet.dynamicdatamapping.util.DDMIndexerUtil;
058    import com.liferay.portlet.expando.model.ExpandoBridge;
059    import com.liferay.portlet.expando.model.ExpandoColumnConstants;
060    import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;
061    import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
062    
063    import java.util.ArrayList;
064    import java.util.List;
065    import java.util.Locale;
066    import java.util.Map;
067    import java.util.Set;
068    
069    import javax.portlet.PortletURL;
070    
071    /**
072     * @author Brian Wing Shun Chan
073     * @author Hugo Huijser
074     * @author Ryan Park
075     * @author Raymond Augé
076     */
077    public abstract class BaseIndexer implements Indexer {
078    
079            public static final int INDEX_FILTER_SEARCH_LIMIT = GetterUtil.getInteger(
080                    PropsUtil.get(PropsKeys.INDEX_FILTER_SEARCH_LIMIT));
081    
082            private static final boolean _FILTER_SEARCH = false;
083    
084            public void delete(long companyId, String uid) throws SearchException {
085                    try {
086                            SearchEngineUtil.deleteDocument(companyId, uid);
087                    }
088                    catch (SearchException se) {
089                            throw se;
090                    }
091                    catch (Exception e) {
092                            throw new SearchException(e);
093                    }
094            }
095    
096            public void delete(Object obj) throws SearchException {
097                    try {
098                            doDelete(obj);
099                    }
100                    catch (SearchException se) {
101                            throw se;
102                    }
103                    catch (Exception e) {
104                            throw new SearchException(e);
105                    }
106            }
107    
108            public Document getDocument(Object obj) throws SearchException {
109                    try {
110                            Document document = doGetDocument(obj);
111    
112                            for (IndexerPostProcessor indexerPostProcessor :
113                                            _indexerPostProcessors) {
114    
115                                    indexerPostProcessor.postProcessDocument(document, obj);
116                            }
117    
118                            if (document == null) {
119                                    return null;
120                            }
121    
122                            Map<String, Field> fields = document.getFields();
123    
124                            Field groupIdField = fields.get(Field.GROUP_ID);
125    
126                            if (groupIdField != null) {
127                                    long groupId = GetterUtil.getLong(groupIdField.getValue());
128    
129                                    addStagingGroupKeyword(document, groupId);
130                            }
131    
132                            return document;
133                    }
134                    catch (SearchException se) {
135                            throw se;
136                    }
137                    catch (Exception e) {
138                            throw new SearchException(e);
139                    }
140            }
141    
142            public BooleanQuery getFacetQuery(
143                            String className, SearchContext searchContext)
144                    throws Exception {
145    
146                    BooleanQuery facetQuery = BooleanQueryFactoryUtil.create(searchContext);
147    
148                    facetQuery.addExactTerm(Field.ENTRY_CLASS_NAME, className);
149    
150                    if (searchContext.getUserId() > 0) {
151                            SearchPermissionChecker searchPermissionChecker =
152                                    SearchEngineUtil.getSearchPermissionChecker();
153    
154                            facetQuery =
155                                    (BooleanQuery)searchPermissionChecker.getPermissionQuery(
156                                            searchContext.getCompanyId(), searchContext.getGroupIds(),
157                                            searchContext.getUserId(), className, facetQuery,
158                                            searchContext);
159                    }
160    
161                    return facetQuery;
162            }
163    
164            public BooleanQuery getFullQuery(SearchContext searchContext)
165                    throws SearchException {
166    
167                    try {
168                            searchContext.setSearchEngineId(getSearchEngineId());
169    
170                            searchContext.setEntryClassNames(
171                                    new String[] {getClassName(searchContext)});
172    
173                            BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
174                                    searchContext);
175    
176                            addSearchAssetCategoryIds(contextQuery, searchContext);
177                            addSearchAssetTagNames(contextQuery, searchContext);
178                            addSearchEntryClassNames(contextQuery, searchContext);
179                            addSearchGroupId(contextQuery, searchContext);
180    
181                            BooleanQuery fullQuery = createFullQuery(
182                                    contextQuery, searchContext);
183    
184                            fullQuery.setQueryConfig(searchContext.getQueryConfig());
185    
186                            return fullQuery;
187                    }
188                    catch (SearchException se) {
189                            throw se;
190                    }
191                    catch (Exception e) {
192                            throw new SearchException(e);
193                    }
194            }
195    
196            public IndexerPostProcessor[] getIndexerPostProcessors() {
197                    return _indexerPostProcessors;
198            }
199    
200            public String getSearchEngineId() {
201                    return SearchEngineUtil.SYSTEM_ENGINE_ID;
202            }
203    
204            public String getSortField(String orderByCol) {
205                    return doGetSortField(orderByCol);
206            }
207    
208            public Summary getSummary(
209                            Document document, Locale locale, String snippet,
210                            PortletURL portletURL)
211                    throws SearchException {
212    
213                    try {
214                            Summary summary = doGetSummary(
215                                    document, locale, snippet, portletURL);
216    
217                            for (IndexerPostProcessor indexerPostProcessor :
218                                            _indexerPostProcessors) {
219    
220                                    indexerPostProcessor.postProcessSummary(
221                                            summary, document, locale, snippet, portletURL);
222                            }
223    
224                            return summary;
225                    }
226                    catch (SearchException se) {
227                            throw se;
228                    }
229                    catch (Exception e) {
230                            throw new SearchException(e);
231                    }
232            }
233    
234            public boolean hasPermission(
235                            PermissionChecker permissionChecker, long entryClassPK,
236                            String actionId)
237                    throws Exception {
238    
239                    return true;
240            }
241    
242            public boolean isFilterSearch() {
243                    return _FILTER_SEARCH;
244            }
245    
246            public boolean isStagingAware() {
247                    return _stagingAware;
248            }
249    
250            public void postProcessContextQuery(
251                            BooleanQuery contextQuery, SearchContext searchContext)
252                    throws Exception {
253            }
254    
255            public void postProcessSearchQuery(
256                            BooleanQuery searchQuery, SearchContext searchContext)
257                    throws Exception {
258            }
259    
260            public void registerIndexerPostProcessor(
261                    IndexerPostProcessor indexerPostProcessor) {
262    
263                    List<IndexerPostProcessor> indexerPostProcessorsList =
264                            ListUtil.fromArray(_indexerPostProcessors);
265    
266                    indexerPostProcessorsList.add(indexerPostProcessor);
267    
268                    _indexerPostProcessors = indexerPostProcessorsList.toArray(
269                            new IndexerPostProcessor[indexerPostProcessorsList.size()]);
270            }
271    
272            public void reindex(Object obj) throws SearchException {
273                    try {
274                            if (SearchEngineUtil.isIndexReadOnly()) {
275                                    return;
276                            }
277    
278                            doReindex(obj);
279                    }
280                    catch (SearchException se) {
281                            throw se;
282                    }
283                    catch (Exception e) {
284                            throw new SearchException(e);
285                    }
286            }
287    
288            public void reindex(String className, long classPK) throws SearchException {
289                    try {
290                            if (SearchEngineUtil.isIndexReadOnly()) {
291                                    return;
292                            }
293    
294                            doReindex(className, classPK);
295                    }
296                    catch (NoSuchModelException nsme) {
297                            if (_log.isWarnEnabled()) {
298                                    _log.warn("Unable to index " + className + " " + classPK);
299                            }
300                    }
301                    catch (SearchException se) {
302                            throw se;
303                    }
304                    catch (Exception e) {
305                            throw new SearchException(e);
306                    }
307            }
308    
309            public void reindex(String[] ids) throws SearchException {
310                    try {
311                            if (SearchEngineUtil.isIndexReadOnly()) {
312                                    return;
313                            }
314    
315                            doReindex(ids);
316                    }
317                    catch (SearchException se) {
318                            throw se;
319                    }
320                    catch (Exception e) {
321                            throw new SearchException(e);
322                    }
323            }
324    
325            public Hits search(SearchContext searchContext) throws SearchException {
326                    try {
327                            BooleanQuery fullQuery = getFullQuery(searchContext);
328    
329                            fullQuery.setQueryConfig(searchContext.getQueryConfig());
330    
331                            PermissionChecker permissionChecker =
332                                    PermissionThreadLocal.getPermissionChecker();
333    
334                            int start = searchContext.getStart();
335                            int end = searchContext.getEnd();
336    
337                            if (isFilterSearch() && (permissionChecker != null)) {
338                                    searchContext.setStart(0);
339                                    searchContext.setEnd(end + INDEX_FILTER_SEARCH_LIMIT);
340                            }
341    
342                            Hits hits = SearchEngineUtil.search(searchContext, fullQuery);
343    
344                            searchContext.setStart(start);
345                            searchContext.setEnd(end);
346    
347                            if (isFilterSearch() && (permissionChecker != null)) {
348                                    hits = filterSearch(hits, permissionChecker, searchContext);
349                            }
350    
351                            return hits;
352                    }
353                    catch (SearchException se) {
354                            throw se;
355                    }
356                    catch (Exception e) {
357                            throw new SearchException(e);
358                    }
359            }
360    
361            public void unregisterIndexerPostProcessor(
362                    IndexerPostProcessor indexerPostProcessor) {
363    
364                    List<IndexerPostProcessor> indexerPostProcessorsList =
365                            ListUtil.fromArray(_indexerPostProcessors);
366    
367                    ListUtil.remove(indexerPostProcessorsList, indexerPostProcessor);
368    
369                    _indexerPostProcessors = indexerPostProcessorsList.toArray(
370                            new IndexerPostProcessor[indexerPostProcessorsList.size()]);
371            }
372    
373            protected void addLocalizedSearchTerm(
374                            BooleanQuery searchQuery, SearchContext searchContext,
375                            String field, boolean like)
376                    throws Exception {
377    
378                    addSearchTerm(searchQuery, searchContext, field, like);
379                    addSearchTerm(
380                            searchQuery, searchContext,
381                            DocumentImpl.getLocalizedName(searchContext.getLocale(), field),
382                            like);
383            }
384    
385            protected void addSearchAssetCategoryIds(
386                            BooleanQuery contextQuery, SearchContext searchContext)
387                    throws Exception {
388    
389                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
390    
391                    multiValueFacet.setFieldName(Field.ASSET_CATEGORY_IDS);
392                    multiValueFacet.setStatic(true);
393    
394                    searchContext.addFacet(multiValueFacet);
395            }
396    
397            protected void addSearchAssetTagNames(
398                            BooleanQuery contextQuery, SearchContext searchContext)
399                    throws Exception {
400    
401                    MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
402    
403                    multiValueFacet.setFieldName(Field.ASSET_TAG_NAMES);
404                    multiValueFacet.setStatic(true);
405    
406                    searchContext.addFacet(multiValueFacet);
407            }
408    
409            protected void addSearchDDMStruture(
410                            BooleanQuery searchQuery, SearchContext searchContext,
411                            DDMStructure ddmStructure)
412                    throws Exception {
413    
414                    Set<String> fieldNames = ddmStructure.getFieldNames();
415    
416                    for (String fieldName : fieldNames) {
417                            String name = DDMIndexerUtil.encodeName(
418                                    ddmStructure.getStructureId(), fieldName);
419    
420                            addSearchTerm(searchQuery, searchContext, name, false);
421                    }
422            }
423    
424            protected void addSearchEntryClassNames(
425                            BooleanQuery contextQuery, SearchContext searchContext)
426                    throws Exception {
427    
428                    Facet facet = new AssetEntriesFacet(searchContext);
429    
430                    facet.setStatic(true);
431    
432                    searchContext.addFacet(facet);
433            }
434    
435            protected void addSearchExpando(
436                            BooleanQuery searchQuery, SearchContext searchContext,
437                            String keywords)
438                    throws Exception {
439    
440                    ExpandoBridge expandoBridge =
441                            ExpandoBridgeFactoryUtil.getExpandoBridge(
442                                    searchContext.getCompanyId(), getClassName(searchContext));
443    
444                    Set<String> attributeNames = SetUtil.fromEnumeration(
445                            expandoBridge.getAttributeNames());
446    
447                    for (String attributeName : attributeNames) {
448                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
449                                    attributeName);
450    
451                            int indexType = GetterUtil.getInteger(
452                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
453    
454                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
455                                    String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
456                                            attributeName);
457    
458                                    if (Validator.isNotNull(keywords)) {
459                                            if (searchContext.isAndSearch()) {
460                                                    searchQuery.addRequiredTerm(fieldName, keywords);
461                                            }
462                                            else {
463                                                    searchQuery.addTerm(fieldName, keywords);
464                                            }
465                                    }
466                            }
467                    }
468            }
469    
470            protected void addSearchGroupId(
471                            BooleanQuery contextQuery, SearchContext searchContext)
472                    throws Exception {
473    
474                    Facet facet = new ScopeFacet(searchContext);
475    
476                    facet.setStatic(true);
477    
478                    searchContext.addFacet(facet);
479            }
480    
481            protected void addSearchKeywords(
482                            BooleanQuery searchQuery, SearchContext searchContext)
483                    throws Exception {
484    
485                    String keywords = searchContext.getKeywords();
486    
487                    if (Validator.isNull(keywords)) {
488                            return;
489                    }
490    
491                    searchQuery.addTerms(Field.KEYWORDS, keywords);
492    
493                    addSearchExpando(searchQuery, searchContext, keywords);
494            }
495    
496            protected void addSearchTerm(
497                            BooleanQuery searchQuery, SearchContext searchContext,
498                            String field, boolean like)
499                    throws Exception {
500    
501                    if (Validator.isNull(field)) {
502                            return;
503                    }
504    
505                    String value = String.valueOf(searchContext.getAttribute(field));
506    
507                    if (Validator.isNull(value)) {
508                            value = searchContext.getKeywords();
509                    }
510    
511                    if (Validator.isNull(value)) {
512                            return;
513                    }
514    
515                    if (searchContext.isAndSearch()) {
516                            searchQuery.addRequiredTerm(field, value, like);
517                    }
518                    else {
519                            searchQuery.addTerm(field, value, like);
520                    }
521            }
522    
523            protected void addStagingGroupKeyword(Document document, long groupId)
524                    throws Exception {
525    
526                    if (!isStagingAware()) {
527                            return;
528                    }
529    
530                    boolean stagingGroup = false;
531    
532                    Group group = GroupLocalServiceUtil.getGroup(groupId);
533    
534                    if (group.isLayout()) {
535                            group = GroupLocalServiceUtil.getGroup(group.getParentGroupId());
536                    }
537    
538                    if (group.isStagingGroup()) {
539                            stagingGroup = true;
540                    }
541    
542                    document.addKeyword(Field.STAGING_GROUP, stagingGroup);
543            }
544    
545            protected BooleanQuery createFullQuery(
546                            BooleanQuery contextQuery, SearchContext searchContext)
547                    throws Exception {
548    
549                    BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
550                            searchContext);
551    
552                    addSearchKeywords(searchQuery, searchContext);
553                    postProcessSearchQuery(searchQuery, searchContext);
554    
555                    for (IndexerPostProcessor indexerPostProcessor :
556                                    _indexerPostProcessors) {
557    
558                            indexerPostProcessor.postProcessSearchQuery(
559                                    searchQuery, searchContext);
560                    }
561    
562                    Map<String, Facet> facets = searchContext.getFacets();
563    
564                    for (Facet facet : facets.values()) {
565                            BooleanClause facetClause = facet.getFacetClause();
566    
567                            if (facetClause != null) {
568                                    contextQuery.add(
569                                            facetClause.getQuery(),
570                                            facetClause.getBooleanClauseOccur());
571                            }
572                    }
573    
574                    BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
575    
576                    fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
577    
578                    if (!searchQuery.clauses().isEmpty()) {
579                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
580                    }
581    
582                    BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
583    
584                    if (booleanClauses != null) {
585                            for (BooleanClause booleanClause : booleanClauses) {
586                                    fullQuery.add(
587                                            booleanClause.getQuery(),
588                                            booleanClause.getBooleanClauseOccur());
589                            }
590                    }
591    
592                    postProcessFullQuery(fullQuery, searchContext);
593    
594                    for (IndexerPostProcessor indexerPostProcessor :
595                                    _indexerPostProcessors) {
596    
597                            indexerPostProcessor.postProcessFullQuery(fullQuery, searchContext);
598                    }
599    
600                    return fullQuery;
601            }
602    
603            protected void deleteDocument(long companyId, long field1)
604                    throws Exception {
605    
606                    deleteDocument(companyId, String.valueOf(field1));
607            }
608    
609            protected void deleteDocument(long companyId, long field1, String field2)
610                    throws Exception {
611    
612                    deleteDocument(companyId, String.valueOf(field1), field2);
613            }
614    
615            protected void deleteDocument(long companyId, String field1)
616                    throws Exception {
617    
618                    Document document = new DocumentImpl();
619    
620                    document.addUID(getPortletId(), field1);
621    
622                    SearchEngineUtil.deleteDocument(companyId, document.get(Field.UID));
623            }
624    
625            protected void deleteDocument(long companyId, String field1, String field2)
626                    throws Exception {
627    
628                    Document document = new DocumentImpl();
629    
630                    document.addUID(getPortletId(), field1, field2);
631    
632                    SearchEngineUtil.deleteDocument(companyId, document.get(Field.UID));
633            }
634    
635            protected abstract void doDelete(Object obj) throws Exception;
636    
637            protected abstract Document doGetDocument(Object obj) throws Exception;
638    
639            protected String doGetSortField(String orderByCol) {
640                    return orderByCol;
641            }
642    
643            protected abstract Summary doGetSummary(
644                            Document document, Locale locale, String snippet,
645                            PortletURL portletURL)
646                    throws Exception;
647    
648            protected abstract void doReindex(Object obj) throws Exception;
649    
650            protected abstract void doReindex(String className, long classPK)
651                    throws Exception;
652    
653            protected abstract void doReindex(String[] ids) throws Exception;
654    
655            protected Hits filterSearch(
656                    Hits hits, PermissionChecker permissionChecker,
657                    SearchContext searchContext) {
658    
659                    List<Document> docs = new ArrayList<Document>();
660                    List<Float> scores = new ArrayList<Float>();
661    
662                    int start = searchContext.getStart();
663                    int end = searchContext.getEnd();
664    
665                    String paginationType = GetterUtil.getString(
666                            searchContext.getAttribute("paginationType"), "more");
667    
668                    boolean hasMore = false;
669    
670                    Document[] documents = hits.getDocs();
671    
672                    for (int i = 0; i < documents.length; i++) {
673                            try {
674                                    Document document = documents[i];
675    
676                                    String entryClassName = document.get(Field.ENTRY_CLASS_NAME);
677                                    long entryClassPK = GetterUtil.getLong(
678                                            document.get(Field.ENTRY_CLASS_PK));
679    
680                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
681                                            entryClassName);
682    
683                                    if ((indexer.isFilterSearch() && indexer.hasPermission(
684                                                    permissionChecker, entryClassPK, ActionKeys.VIEW)) ||
685                                            !indexer.isFilterSearch()) {
686    
687                                            docs.add(document);
688                                            scores.add(hits.score(i));
689                                    }
690                            }
691                            catch (Exception e) {
692                            }
693    
694                            if (paginationType.equals("more") && (docs.size() > end)) {
695                                    hasMore = true;
696    
697                                    break;
698                            }
699                    }
700    
701                    int length = docs.size();
702    
703                    if (hasMore) {
704                            length = length + (end - start);
705                    }
706    
707                    hits.setLength(length);
708    
709                    if ((start != QueryUtil.ALL_POS) && (end != QueryUtil.ALL_POS)) {
710                            if (end > length) {
711                                    end = length;
712                            }
713    
714                            docs = docs.subList(start, end);
715                    }
716    
717                    hits.setDocs(docs.toArray(new Document[docs.size()]));
718                    hits.setScores(scores.toArray(new Float[docs.size()]));
719    
720                    hits.setSearchTime(
721                            (float)(System.currentTimeMillis() - hits.getStart()) /
722                                    Time.SECOND);
723    
724                    return hits;
725            }
726    
727            protected Document getBaseModelDocument(
728                            String portletId, BaseModel<?> baseModel)
729                    throws SystemException {
730    
731                    Document document = new DocumentImpl();
732    
733                    String className = baseModel.getModelClassName();
734    
735                    long classPK = 0;
736                    long resourcePrimKey = 0;
737    
738                    if (baseModel instanceof ResourcedModel) {
739                            ResourcedModel resourcedModel = (ResourcedModel)baseModel;
740    
741                            classPK = resourcedModel.getResourcePrimKey();
742                            resourcePrimKey = resourcedModel.getResourcePrimKey();
743                    }
744                    else {
745                            classPK = (Long)baseModel.getPrimaryKeyObj();
746                    }
747    
748                    document.addUID(portletId, classPK);
749    
750                    long[] assetCategoryIds = AssetCategoryLocalServiceUtil.getCategoryIds(
751                            className, classPK);
752    
753                    document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
754    
755                    String[] assetCategoryNames =
756                            AssetCategoryLocalServiceUtil.getCategoryNames(
757                                    className, classPK);
758    
759                    document.addText(Field.ASSET_CATEGORY_NAMES, assetCategoryNames);
760    
761                    String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(
762                            className, classPK);
763    
764                    document.addText(Field.ASSET_TAG_NAMES, assetTagNames);
765    
766                    document.addKeyword(Field.ENTRY_CLASS_NAME, className);
767                    document.addKeyword(Field.ENTRY_CLASS_PK, classPK);
768                    document.addKeyword(Field.PORTLET_ID, portletId);
769    
770                    if (resourcePrimKey > 0) {
771                            document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
772                    }
773    
774                    if (baseModel instanceof AttachedModel) {
775                            AttachedModel attachedModel = (AttachedModel)baseModel;
776    
777                            document.addKeyword(
778                                    Field.CLASS_NAME_ID, attachedModel.getClassNameId());
779                            document.addKeyword(Field.CLASS_PK, attachedModel.getClassPK());
780                    }
781    
782                    if (baseModel instanceof AuditedModel) {
783                            AuditedModel auditedModel = (AuditedModel)baseModel;
784    
785                            document.addKeyword(Field.COMPANY_ID, auditedModel.getCompanyId());
786                            document.addDate(Field.CREATE_DATE, auditedModel.getCreateDate());
787                            document.addDate(
788                                    Field.MODIFIED_DATE, auditedModel.getModifiedDate());
789                            document.addKeyword(Field.USER_ID, auditedModel.getUserId());
790    
791                            String userName = PortalUtil.getUserName(
792                                    auditedModel.getUserId(), auditedModel.getUserName());
793    
794                            document.addKeyword(Field.USER_NAME, userName, true);
795                    }
796    
797                    if (baseModel instanceof GroupedModel) {
798                            GroupedModel groupedModel = (GroupedModel)baseModel;
799    
800                            document.addKeyword(
801                                    Field.GROUP_ID, getParentGroupId(groupedModel.getGroupId()));
802                            document.addKeyword(
803                                    Field.SCOPE_GROUP_ID, groupedModel.getGroupId());
804                    }
805    
806                    if (baseModel instanceof WorkflowedModel) {
807                            WorkflowedModel workflowedModel = (WorkflowedModel)baseModel;
808    
809                            document.addKeyword(Field.STATUS, workflowedModel.getStatus());
810                    }
811    
812                    ExpandoBridgeIndexerUtil.addAttributes(
813                            document, baseModel.getExpandoBridge());
814    
815                    return document;
816            }
817    
818            protected String getClassName(SearchContext searchContext) {
819                    String[] classNames = getClassNames();
820    
821                    if (classNames.length != 1) {
822                            throw new UnsupportedOperationException(
823                                    "Search method needs to be manually implemented for " +
824                                            "indexers with more than one class name");
825                    }
826    
827                    return classNames[0];
828            }
829    
830            protected long getParentGroupId(long groupId) {
831                    long parentGroupId = groupId;
832    
833                    try {
834                            Group group = GroupLocalServiceUtil.getGroup(groupId);
835    
836                            if (group.isLayout()) {
837                                    parentGroupId = group.getParentGroupId();
838                            }
839                    }
840                    catch (Exception e) {
841                    }
842    
843                    return parentGroupId;
844            }
845    
846            protected abstract String getPortletId(SearchContext searchContext);
847    
848            protected void populateAddresses(
849                            Document document, List<Address> addresses, long regionId,
850                            long countryId)
851                    throws PortalException, SystemException {
852    
853                    List<String> cities = new ArrayList<String>();
854    
855                    List<String> countries = new ArrayList<String>();
856    
857                    if (countryId > 0) {
858                            try {
859                                    Country country = CountryServiceUtil.getCountry(countryId);
860    
861                                    countries.add(country.getName().toLowerCase());
862                            }
863                            catch (NoSuchCountryException nsce) {
864                                    if (_log.isWarnEnabled()) {
865                                            _log.warn(nsce.getMessage());
866                                    }
867                            }
868                    }
869    
870                    List<String> regions = new ArrayList<String>();
871    
872                    if (regionId > 0) {
873                            try {
874                                    Region region = RegionServiceUtil.getRegion(regionId);
875    
876                                    regions.add(region.getName().toLowerCase());
877                            }
878                            catch (NoSuchRegionException nsre) {
879                                    if (_log.isWarnEnabled()) {
880                                            _log.warn(nsre.getMessage());
881                                    }
882                            }
883                    }
884    
885                    List<String> streets = new ArrayList<String>();
886                    List<String> zips = new ArrayList<String>();
887    
888                    for (Address address : addresses) {
889                            cities.add(address.getCity().toLowerCase());
890                            countries.add(address.getCountry().getName().toLowerCase());
891                            regions.add(address.getRegion().getName().toLowerCase());
892                            streets.add(address.getStreet1().toLowerCase());
893                            streets.add(address.getStreet2().toLowerCase());
894                            streets.add(address.getStreet3().toLowerCase());
895                            zips.add(address.getZip().toLowerCase());
896                    }
897    
898                    document.addText("city", cities.toArray(new String[cities.size()]));
899                    document.addText(
900                            "country", countries.toArray(new String[countries.size()]));
901                    document.addText("region", regions.toArray(new String[regions.size()]));
902                    document.addText("street", streets.toArray(new String[streets.size()]));
903                    document.addText("zip", zips.toArray(new String[zips.size()]));
904            }
905    
906            protected void postProcessFullQuery(
907                            BooleanQuery fullQuery, SearchContext searchContext)
908                    throws Exception {
909            }
910    
911            protected void setStagingAware(boolean stagingAware) {
912                    _stagingAware = stagingAware;
913            }
914    
915            private static Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
916    
917            private IndexerPostProcessor[] _indexerPostProcessors =
918                    new IndexerPostProcessor[0];
919            private boolean _stagingAware = true;
920    
921    }