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