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