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