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.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.search.facet.AssetEntriesFacet;
028 import com.liferay.portal.kernel.search.facet.Facet;
029 import com.liferay.portal.kernel.search.facet.MultiValueFacet;
030 import com.liferay.portal.kernel.search.facet.ScopeFacet;
031 import com.liferay.portal.kernel.trash.TrashHandler;
032 import com.liferay.portal.kernel.trash.TrashHandlerRegistryUtil;
033 import com.liferay.portal.kernel.trash.TrashRenderer;
034 import com.liferay.portal.kernel.util.GetterUtil;
035 import com.liferay.portal.kernel.util.ListUtil;
036 import com.liferay.portal.kernel.util.LocaleUtil;
037 import com.liferay.portal.kernel.util.PropsKeys;
038 import com.liferay.portal.kernel.util.PropsUtil;
039 import com.liferay.portal.kernel.util.SetUtil;
040 import com.liferay.portal.kernel.util.StringPool;
041 import com.liferay.portal.kernel.util.StringUtil;
042 import com.liferay.portal.kernel.util.Time;
043 import com.liferay.portal.kernel.util.UnicodeProperties;
044 import com.liferay.portal.kernel.util.Validator;
045 import com.liferay.portal.model.Address;
046 import com.liferay.portal.model.AttachedModel;
047 import com.liferay.portal.model.AuditedModel;
048 import com.liferay.portal.model.BaseModel;
049 import com.liferay.portal.model.Country;
050 import com.liferay.portal.model.Group;
051 import com.liferay.portal.model.GroupedModel;
052 import com.liferay.portal.model.Region;
053 import com.liferay.portal.model.ResourcedModel;
054 import com.liferay.portal.model.User;
055 import com.liferay.portal.model.WorkflowedModel;
056 import com.liferay.portal.security.permission.ActionKeys;
057 import com.liferay.portal.security.permission.PermissionChecker;
058 import com.liferay.portal.security.permission.PermissionThreadLocal;
059 import com.liferay.portal.service.CountryServiceUtil;
060 import com.liferay.portal.service.GroupLocalServiceUtil;
061 import com.liferay.portal.service.RegionServiceUtil;
062 import com.liferay.portal.service.ServiceContext;
063 import com.liferay.portal.service.ServiceContextThreadLocal;
064 import com.liferay.portal.service.UserLocalServiceUtil;
065 import com.liferay.portal.util.PortalUtil;
066 import com.liferay.portlet.asset.model.AssetCategory;
067 import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
068 import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
069 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
070 import com.liferay.portlet.dynamicdatamapping.util.DDMIndexerUtil;
071 import com.liferay.portlet.expando.model.ExpandoBridge;
072 import com.liferay.portlet.expando.model.ExpandoColumnConstants;
073 import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;
074 import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
075 import com.liferay.portlet.trash.model.TrashEntry;
076 import com.liferay.portlet.trash.service.TrashEntryLocalServiceUtil;
077
078 import java.util.ArrayList;
079 import java.util.Date;
080 import java.util.HashMap;
081 import java.util.HashSet;
082 import java.util.List;
083 import java.util.Locale;
084 import java.util.Map;
085 import java.util.Set;
086
087 import javax.portlet.PortletURL;
088
089
095 public abstract class BaseIndexer implements Indexer {
096
097 public static final int INDEX_FILTER_SEARCH_LIMIT = GetterUtil.getInteger(
098 PropsUtil.get(PropsKeys.INDEX_FILTER_SEARCH_LIMIT));
099
100 public void delete(long companyId, String uid) throws SearchException {
101 try {
102 SearchEngineUtil.deleteDocument(
103 getSearchEngineId(), companyId, uid);
104 }
105 catch (SearchException se) {
106 throw se;
107 }
108 catch (Exception e) {
109 throw new SearchException(e);
110 }
111 }
112
113 public void delete(Object obj) throws SearchException {
114 try {
115 doDelete(obj);
116 }
117 catch (SearchException se) {
118 throw se;
119 }
120 catch (Exception e) {
121 throw new SearchException(e);
122 }
123 }
124
125 public Document getDocument(Object obj) throws SearchException {
126 try {
127 Document document = doGetDocument(obj);
128
129 for (IndexerPostProcessor indexerPostProcessor :
130 _indexerPostProcessors) {
131
132 indexerPostProcessor.postProcessDocument(document, obj);
133 }
134
135 if (document == null) {
136 return null;
137 }
138
139 Map<String, Field> fields = document.getFields();
140
141 Field groupIdField = fields.get(Field.GROUP_ID);
142
143 if (groupIdField != null) {
144 long groupId = GetterUtil.getLong(groupIdField.getValue());
145
146 addStagingGroupKeyword(document, groupId);
147 }
148
149 return document;
150 }
151 catch (SearchException se) {
152 throw se;
153 }
154 catch (Exception e) {
155 throw new SearchException(e);
156 }
157 }
158
159 public BooleanQuery getFacetQuery(
160 String className, SearchContext searchContext)
161 throws Exception {
162
163 BooleanQuery facetQuery = BooleanQueryFactoryUtil.create(searchContext);
164
165 facetQuery.addExactTerm(Field.ENTRY_CLASS_NAME, className);
166
167 if (searchContext.getUserId() > 0) {
168 SearchPermissionChecker searchPermissionChecker =
169 SearchEngineUtil.getSearchPermissionChecker();
170
171 facetQuery =
172 (BooleanQuery)searchPermissionChecker.getPermissionQuery(
173 searchContext.getCompanyId(), searchContext.getGroupIds(),
174 searchContext.getUserId(), className, facetQuery,
175 searchContext);
176 }
177
178 return facetQuery;
179 }
180
181 public BooleanQuery getFullQuery(SearchContext searchContext)
182 throws SearchException {
183
184 try {
185 searchContext.setSearchEngineId(getSearchEngineId());
186
187 searchContext.setEntryClassNames(
188 new String[] {getClassName(searchContext)});
189
190 BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
191 searchContext);
192
193 addSearchAssetCategoryIds(contextQuery, searchContext);
194 addSearchAssetTagNames(contextQuery, searchContext);
195 addSearchEntryClassNames(contextQuery, searchContext);
196 addSearchGroupId(contextQuery, searchContext);
197
198 BooleanQuery fullQuery = createFullQuery(
199 contextQuery, searchContext);
200
201 fullQuery.setQueryConfig(searchContext.getQueryConfig());
202
203 return fullQuery;
204 }
205 catch (SearchException se) {
206 throw se;
207 }
208 catch (Exception e) {
209 throw new SearchException(e);
210 }
211 }
212
213 public IndexerPostProcessor[] getIndexerPostProcessors() {
214 return _indexerPostProcessors;
215 }
216
217 public String getSearchEngineId() {
218 if (_searchEngineId != null) {
219 return _searchEngineId;
220 }
221
222 Class<?> clazz = getClass();
223
224 String searchEngineId = GetterUtil.getString(
225 PropsUtil.get(
226 PropsKeys.INDEX_SEARCH_ENGINE_ID, new Filter(clazz.getName())));
227
228 if (Validator.isNotNull(searchEngineId)) {
229 SearchEngine searchEngine = SearchEngineUtil.getSearchEngine(
230 searchEngineId);
231
232 if (searchEngine != null) {
233 _searchEngineId = searchEngineId;
234 }
235 }
236
237 if (_searchEngineId == null) {
238 _searchEngineId = SearchEngineUtil.getDefaultSearchEngineId();
239 }
240
241 if (_log.isDebugEnabled()) {
242 _log.debug(
243 "Search engine ID for " + clazz.getName() + " is " +
244 searchEngineId);
245 }
246
247 return _searchEngineId;
248 }
249
250 public String getSortField(String orderByCol) {
251 String sortField = doGetSortField(orderByCol);
252
253 if (DocumentImpl.isSortableTextField(sortField)) {
254 return DocumentImpl.getSortableFieldName(sortField);
255 }
256
257 return sortField;
258 }
259
260 public Summary getSummary(
261 Document document, Locale locale, String snippet,
262 PortletURL portletURL)
263 throws SearchException {
264
265 try {
266 Summary summary = doGetSummary(
267 document, locale, snippet, portletURL);
268
269 for (IndexerPostProcessor indexerPostProcessor :
270 _indexerPostProcessors) {
271
272 indexerPostProcessor.postProcessSummary(
273 summary, document, locale, snippet, portletURL);
274 }
275
276 return summary;
277 }
278 catch (SearchException se) {
279 throw se;
280 }
281 catch (Exception e) {
282 throw new SearchException(e);
283 }
284 }
285
286 public boolean hasPermission(
287 PermissionChecker permissionChecker, String entryClassName,
288 long entryClassPK, String actionId)
289 throws Exception {
290
291 return true;
292 }
293
294 public boolean isFilterSearch() {
295 return _filterSearch;
296 }
297
298 public boolean isIndexerEnabled() {
299 return _indexerEnabled;
300 }
301
302 public boolean isPermissionAware() {
303 return _permissionAware;
304 }
305
306 public boolean isStagingAware() {
307 return _stagingAware;
308 }
309
310 public void postProcessContextQuery(
311 BooleanQuery contextQuery, SearchContext searchContext)
312 throws Exception {
313 }
314
315 public void postProcessSearchQuery(
316 BooleanQuery searchQuery, SearchContext searchContext)
317 throws Exception {
318
319 String keywords = searchContext.getKeywords();
320
321 if (Validator.isNull(keywords)) {
322 addSearchTerm(searchQuery, searchContext, Field.DESCRIPTION, false);
323 addSearchTerm(searchQuery, searchContext, Field.TITLE, false);
324 addSearchTerm(searchQuery, searchContext, Field.USER_NAME, false);
325 }
326 }
327
328 public void registerIndexerPostProcessor(
329 IndexerPostProcessor indexerPostProcessor) {
330
331 List<IndexerPostProcessor> indexerPostProcessorsList =
332 ListUtil.fromArray(_indexerPostProcessors);
333
334 indexerPostProcessorsList.add(indexerPostProcessor);
335
336 _indexerPostProcessors = indexerPostProcessorsList.toArray(
337 new IndexerPostProcessor[indexerPostProcessorsList.size()]);
338 }
339
340 public void reindex(Object obj) throws SearchException {
341 try {
342 if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
343 return;
344 }
345
346 doReindex(obj);
347 }
348 catch (SearchException se) {
349 throw se;
350 }
351 catch (Exception e) {
352 throw new SearchException(e);
353 }
354 }
355
356 public void reindex(String className, long classPK) throws SearchException {
357 try {
358 if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
359 return;
360 }
361
362 doReindex(className, classPK);
363 }
364 catch (NoSuchModelException nsme) {
365 if (_log.isWarnEnabled()) {
366 _log.warn("Unable to index " + className + " " + classPK);
367 }
368 }
369 catch (SearchException se) {
370 throw se;
371 }
372 catch (Exception e) {
373 throw new SearchException(e);
374 }
375 }
376
377 public void reindex(String[] ids) throws SearchException {
378 try {
379 if (SearchEngineUtil.isIndexReadOnly() || !isIndexerEnabled()) {
380 return;
381 }
382
383 doReindex(ids);
384 }
385 catch (SearchException se) {
386 throw se;
387 }
388 catch (Exception e) {
389 throw new SearchException(e);
390 }
391 }
392
393 public Hits search(SearchContext searchContext) throws SearchException {
394 try {
395 searchContext.setSearchEngineId(getSearchEngineId());
396
397 BooleanQuery fullQuery = getFullQuery(searchContext);
398
399 fullQuery.setQueryConfig(searchContext.getQueryConfig());
400
401 PermissionChecker permissionChecker =
402 PermissionThreadLocal.getPermissionChecker();
403
404 int end = searchContext.getEnd();
405 int start = searchContext.getStart();
406
407 if (isFilterSearch() && (permissionChecker != null)) {
408 searchContext.setEnd(end + INDEX_FILTER_SEARCH_LIMIT);
409 searchContext.setStart(0);
410 }
411
412 Hits hits = SearchEngineUtil.search(searchContext, fullQuery);
413
414 searchContext.setEnd(end);
415 searchContext.setStart(start);
416
417 if (isFilterSearch() && (permissionChecker != null)) {
418 hits = filterSearch(hits, permissionChecker, searchContext);
419 }
420
421 return hits;
422 }
423 catch (SearchException se) {
424 throw se;
425 }
426 catch (Exception e) {
427 throw new SearchException(e);
428 }
429 }
430
431 public void unregisterIndexerPostProcessor(
432 IndexerPostProcessor indexerPostProcessor) {
433
434 List<IndexerPostProcessor> indexerPostProcessorsList =
435 ListUtil.fromArray(_indexerPostProcessors);
436
437 indexerPostProcessorsList.remove(indexerPostProcessor);
438
439 _indexerPostProcessors = indexerPostProcessorsList.toArray(
440 new IndexerPostProcessor[indexerPostProcessorsList.size()]);
441 }
442
443
447 protected void addLocalizedSearchTerm(
448 BooleanQuery searchQuery, SearchContext searchContext, String field,
449 boolean like)
450 throws Exception {
451
452 addSearchLocalizedTerm(searchQuery, searchContext, field, like);
453 }
454
455 protected void addSearchArrayQuery(
456 BooleanQuery searchQuery, SearchContext searchContext, String field)
457 throws Exception {
458
459 if (Validator.isNull(field)) {
460 return;
461 }
462
463 Object fieldValues = searchContext.getAttribute(field);
464
465 if (fieldValues == null) {
466 return;
467 }
468
469 BooleanQuery fieldQuery = null;
470
471 if (fieldValues instanceof int[]) {
472 int[] fieldValuesArray = (int[])fieldValues;
473
474 if (fieldValuesArray.length == 0) {
475 return;
476 }
477
478 fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
479
480 for (int fieldValue : fieldValuesArray) {
481 fieldQuery.addTerm(field, fieldValue);
482 }
483 }
484 else if (fieldValues instanceof Integer[]) {
485 Integer[] fieldValuesArray = (Integer[])fieldValues;
486
487 if (fieldValuesArray.length == 0) {
488 return;
489 }
490
491 fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
492
493 for (Integer fieldValue : fieldValuesArray) {
494 fieldQuery.addTerm(field, fieldValue);
495 }
496 }
497 else if (fieldValues instanceof long[]) {
498 long[] fieldValuesArray = (long[])fieldValues;
499
500 if (fieldValuesArray.length == 0) {
501 return;
502 }
503
504 fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
505
506 for (long fieldValue : fieldValuesArray) {
507 fieldQuery.addTerm(field, fieldValue);
508 }
509 }
510 else if (fieldValues instanceof Long[]) {
511 Long[] fieldValuesArray = (Long[])fieldValues;
512
513 if (fieldValuesArray.length == 0) {
514 return;
515 }
516
517 fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
518
519 for (Long fieldValue : fieldValuesArray) {
520 fieldQuery.addTerm(field, fieldValue);
521 }
522 }
523 else if (fieldValues instanceof short[]) {
524 short[] fieldValuesArray = (short[])fieldValues;
525
526 if (fieldValuesArray.length == 0) {
527 return;
528 }
529
530 fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
531
532 for (short fieldValue : fieldValuesArray) {
533 fieldQuery.addTerm(field, fieldValue);
534 }
535 }
536 else if (fieldValues instanceof Short[]) {
537 Short[] fieldValuesArray = (Short[])fieldValues;
538
539 if (fieldValuesArray.length == 0) {
540 return;
541 }
542
543 fieldQuery = BooleanQueryFactoryUtil.create(searchContext);
544
545 for (Short fieldValue : fieldValuesArray) {
546 fieldQuery.addTerm(field, fieldValue);
547 }
548 }
549
550 if (fieldQuery != null) {
551 if (searchContext.isAndSearch()) {
552 searchQuery.add(fieldQuery, BooleanClauseOccur.MUST);
553 }
554 else {
555 searchQuery.add(fieldQuery, BooleanClauseOccur.SHOULD);
556 }
557 }
558 }
559
560 protected void addSearchAssetCategoryIds(
561 BooleanQuery contextQuery, SearchContext searchContext)
562 throws Exception {
563
564 MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
565
566 multiValueFacet.setFieldName(Field.ASSET_CATEGORY_IDS);
567 multiValueFacet.setStatic(true);
568
569 searchContext.addFacet(multiValueFacet);
570 }
571
572 protected void addSearchAssetCategoryTitles(
573 Document document, String field, List<AssetCategory> assetCategories) {
574
575 Map<Locale, List<String>> assetCategoryTitles =
576 new HashMap<Locale, List<String>>();
577
578 Locale defaultLocale = LocaleUtil.getDefault();
579
580 for (AssetCategory assetCategory : assetCategories) {
581 Map<Locale, String> titleMap = assetCategory.getTitleMap();
582
583 for (Map.Entry<Locale, String> entry : titleMap.entrySet()) {
584 Locale locale = entry.getKey();
585 String title = entry.getValue();
586
587 if (Validator.isNull(title)) {
588 continue;
589 }
590
591 List<String> titles = assetCategoryTitles.get(locale);
592
593 if (titles == null) {
594 titles = new ArrayList<String>();
595
596 assetCategoryTitles.put(locale, titles);
597 }
598
599 titles.add(title);
600 }
601 }
602
603 for (Map.Entry<Locale, List<String>> entry :
604 assetCategoryTitles.entrySet()) {
605
606 Locale locale = entry.getKey();
607 List<String> titles = entry.getValue();
608
609 String[] titlesArray = titles.toArray(new String[0]);
610
611 if (locale.equals(defaultLocale)) {
612 document.addKeyword(field, titlesArray);
613 }
614
615 document.addKeyword(
616 field.concat(StringPool.UNDERLINE).concat(locale.toString()),
617 titlesArray);
618 }
619 }
620
621 protected void addSearchAssetTagNames(
622 BooleanQuery contextQuery, SearchContext searchContext)
623 throws Exception {
624
625 MultiValueFacet multiValueFacet = new MultiValueFacet(searchContext);
626
627 multiValueFacet.setFieldName(Field.ASSET_TAG_NAMES);
628 multiValueFacet.setStatic(true);
629
630 searchContext.addFacet(multiValueFacet);
631 }
632
633 protected void addSearchDDMStruture(
634 BooleanQuery searchQuery, SearchContext searchContext,
635 DDMStructure ddmStructure)
636 throws Exception {
637
638 Set<String> fieldNames = ddmStructure.getFieldNames();
639
640 for (String fieldName : fieldNames) {
641 String name = DDMIndexerUtil.encodeName(
642 ddmStructure.getStructureId(), fieldName);
643
644 addSearchTerm(searchQuery, searchContext, name, false);
645 }
646 }
647
648 protected void addSearchEntryClassNames(
649 BooleanQuery contextQuery, SearchContext searchContext)
650 throws Exception {
651
652 Facet facet = new AssetEntriesFacet(searchContext);
653
654 facet.setStatic(true);
655
656 searchContext.addFacet(facet);
657 }
658
659 protected void addSearchExpando(
660 BooleanQuery searchQuery, SearchContext searchContext,
661 String keywords)
662 throws Exception {
663
664 ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
665 searchContext.getCompanyId(), getClassName(searchContext));
666
667 Set<String> attributeNames = SetUtil.fromEnumeration(
668 expandoBridge.getAttributeNames());
669
670 for (String attributeName : attributeNames) {
671 UnicodeProperties properties = expandoBridge.getAttributeProperties(
672 attributeName);
673
674 int indexType = GetterUtil.getInteger(
675 properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
676
677 if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
678 String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
679 attributeName);
680
681 if (Validator.isNotNull(keywords)) {
682 if (searchContext.isAndSearch()) {
683 searchQuery.addRequiredTerm(fieldName, keywords);
684 }
685 else {
686 searchQuery.addTerm(fieldName, keywords);
687 }
688 }
689 }
690 }
691 }
692
693 protected void addSearchGroupId(
694 BooleanQuery contextQuery, SearchContext searchContext)
695 throws Exception {
696
697 Facet facet = new ScopeFacet(searchContext);
698
699 facet.setStatic(true);
700
701 searchContext.addFacet(facet);
702 }
703
704 protected void addSearchKeywords(
705 BooleanQuery searchQuery, SearchContext searchContext)
706 throws Exception {
707
708 String keywords = searchContext.getKeywords();
709
710 if (Validator.isNull(keywords)) {
711 return;
712 }
713
714 searchQuery.addTerms(Field.KEYWORDS, keywords);
715
716 addSearchExpando(searchQuery, searchContext, keywords);
717 }
718
719 protected void addSearchLocalizedTerm(
720 BooleanQuery searchQuery, SearchContext searchContext, String field,
721 boolean like)
722 throws Exception {
723
724 addSearchTerm(searchQuery, searchContext, field, like);
725 addSearchTerm(
726 searchQuery, searchContext,
727 DocumentImpl.getLocalizedName(searchContext.getLocale(), field),
728 like);
729 }
730
731 protected void addSearchTerm(
732 BooleanQuery searchQuery, SearchContext searchContext, String field,
733 boolean like)
734 throws Exception {
735
736 if (Validator.isNull(field)) {
737 return;
738 }
739
740 String value = String.valueOf(searchContext.getAttribute(field));
741
742 if (Validator.isNull(value)) {
743 value = searchContext.getKeywords();
744 }
745
746 if (Validator.isNull(value)) {
747 return;
748 }
749
750 if (searchContext.isAndSearch()) {
751 searchQuery.addRequiredTerm(field, value, like);
752 }
753 else {
754 searchQuery.addTerm(field, value, like);
755 }
756 }
757
758 protected void addStagingGroupKeyword(Document document, long groupId)
759 throws Exception {
760
761 if (!isStagingAware()) {
762 return;
763 }
764
765 boolean stagingGroup = false;
766
767 Group group = GroupLocalServiceUtil.getGroup(groupId);
768
769 if (group.isLayout()) {
770 group = GroupLocalServiceUtil.getGroup(group.getParentGroupId());
771 }
772
773 if (group.isStagingGroup()) {
774 stagingGroup = true;
775 }
776
777 document.addKeyword(Field.STAGING_GROUP, stagingGroup);
778 }
779
780 protected void addTrashFields(
781 Document document, String className, long classPK, Date removedDate,
782 String removedByUserName, String type)
783 throws SystemException {
784
785 TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
786 className, classPK);
787
788 if (removedDate == null) {
789 if (trashEntry != null) {
790 removedDate = trashEntry.getCreateDate();
791 }
792 else {
793 removedDate = new Date();
794 }
795 }
796
797 document.addDate(Field.REMOVED_DATE, removedDate);
798
799 if (removedByUserName == null) {
800 if (trashEntry != null) {
801 removedByUserName = trashEntry.getUserName();
802 }
803 else {
804 ServiceContext serviceContext =
805 ServiceContextThreadLocal.getServiceContext();
806
807 if (serviceContext != null) {
808 try {
809 User user = UserLocalServiceUtil.getUser(
810 serviceContext.getUserId());
811
812 removedByUserName = user.getFullName();
813 }
814 catch (PortalException pe) {
815 }
816 }
817 }
818 }
819
820 if (Validator.isNotNull(removedByUserName)) {
821 document.addKeyword(
822 Field.REMOVED_BY_USER_NAME, removedByUserName, true);
823 }
824
825 if (type == null) {
826 if (trashEntry != null) {
827 TrashHandler trashHandler =
828 TrashHandlerRegistryUtil.getTrashHandler(
829 trashEntry.getClassName());
830
831 try {
832 TrashRenderer trashRenderer = trashHandler.getTrashRenderer(
833 trashEntry.getClassPK());
834
835 type = trashRenderer.getType();
836 }
837 catch (PortalException pe) {
838 }
839 }
840 }
841
842 if (Validator.isNotNull(type)) {
843 document.addKeyword(Field.TYPE, type, true);
844 }
845 }
846
847 protected BooleanQuery createFullQuery(
848 BooleanQuery contextQuery, SearchContext searchContext)
849 throws Exception {
850
851 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
852 searchContext);
853
854 addSearchKeywords(searchQuery, searchContext);
855 postProcessSearchQuery(searchQuery, searchContext);
856
857 for (IndexerPostProcessor indexerPostProcessor :
858 _indexerPostProcessors) {
859
860 indexerPostProcessor.postProcessSearchQuery(
861 searchQuery, searchContext);
862 }
863
864 Map<String, Facet> facets = searchContext.getFacets();
865
866 for (Facet facet : facets.values()) {
867 BooleanClause facetClause = facet.getFacetClause();
868
869 if (facetClause != null) {
870 contextQuery.add(
871 facetClause.getQuery(),
872 facetClause.getBooleanClauseOccur());
873 }
874 }
875
876 BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
877
878 fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
879
880 if (searchQuery.hasClauses()) {
881 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
882 }
883
884 BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
885
886 if (booleanClauses != null) {
887 for (BooleanClause booleanClause : booleanClauses) {
888 fullQuery.add(
889 booleanClause.getQuery(),
890 booleanClause.getBooleanClauseOccur());
891 }
892 }
893
894 postProcessFullQuery(fullQuery, searchContext);
895
896 for (IndexerPostProcessor indexerPostProcessor :
897 _indexerPostProcessors) {
898
899 indexerPostProcessor.postProcessFullQuery(fullQuery, searchContext);
900 }
901
902 return fullQuery;
903 }
904
905 protected Summary createLocalizedSummary(Document document, Locale locale) {
906 return createLocalizedSummary(
907 document, locale, Field.TITLE, Field.CONTENT);
908 }
909
910 protected Summary createLocalizedSummary(
911 Document document, Locale locale, String titleField,
912 String contentField) {
913
914 Locale snippetLocale = getSnippetLocale(document, locale);
915
916 String prefix = Field.SNIPPET + StringPool.UNDERLINE;
917
918 String title = document.get(
919 snippetLocale, prefix + titleField, titleField);
920
921 String content = document.get(
922 snippetLocale, prefix + contentField, contentField);
923
924 return new Summary(snippetLocale, title, content, null);
925 }
926
927 protected Summary createSummary(Document document) {
928 return createSummary(document, Field.TITLE, Field.CONTENT);
929 }
930
931 protected Summary createSummary(
932 Document document, String titleField, String contentField) {
933
934 String prefix = Field.SNIPPET + StringPool.UNDERLINE;
935
936 String title = document.get(prefix + titleField, titleField);
937 String content = document.get(prefix + contentField, contentField);
938
939 return new Summary(title, content, null);
940 }
941
942 protected void deleteDocument(long companyId, long field1)
943 throws Exception {
944
945 deleteDocument(companyId, String.valueOf(field1));
946 }
947
948 protected void deleteDocument(long companyId, long field1, String field2)
949 throws Exception {
950
951 deleteDocument(companyId, String.valueOf(field1), field2);
952 }
953
954 protected void deleteDocument(long companyId, String field1)
955 throws Exception {
956
957 Document document = new DocumentImpl();
958
959 document.addUID(getPortletId(), field1);
960
961 SearchEngineUtil.deleteDocument(
962 getSearchEngineId(), companyId, document.get(Field.UID));
963 }
964
965 protected void deleteDocument(long companyId, String field1, String field2)
966 throws Exception {
967
968 Document document = new DocumentImpl();
969
970 document.addUID(getPortletId(), field1, field2);
971
972 SearchEngineUtil.deleteDocument(
973 getSearchEngineId(), companyId, document.get(Field.UID));
974 }
975
976 protected abstract void doDelete(Object obj) throws Exception;
977
978 protected abstract Document doGetDocument(Object obj) throws Exception;
979
980 protected String doGetSortField(String orderByCol) {
981 return orderByCol;
982 }
983
984 protected abstract Summary doGetSummary(
985 Document document, Locale locale, String snippet,
986 PortletURL portletURL)
987 throws Exception;
988
989 protected abstract void doReindex(Object obj) throws Exception;
990
991 protected abstract void doReindex(String className, long classPK)
992 throws Exception;
993
994 protected abstract void doReindex(String[] ids) throws Exception;
995
996 protected Hits filterSearch(
997 Hits hits, PermissionChecker permissionChecker,
998 SearchContext searchContext) {
999
1000 List<Document> docs = new ArrayList<Document>();
1001 List<Float> scores = new ArrayList<Float>();
1002
1003 int start = searchContext.getStart();
1004 int end = searchContext.getEnd();
1005
1006 String paginationType = GetterUtil.getString(
1007 searchContext.getAttribute("paginationType"), "more");
1008
1009 boolean hasMore = false;
1010
1011 Document[] documents = hits.getDocs();
1012
1013 for (int i = 0; i < documents.length; i++) {
1014 try {
1015 Document document = documents[i];
1016
1017 String entryClassName = document.get(Field.ENTRY_CLASS_NAME);
1018 long entryClassPK = GetterUtil.getLong(
1019 document.get(Field.ENTRY_CLASS_PK));
1020
1021 Indexer indexer = IndexerRegistryUtil.getIndexer(
1022 entryClassName);
1023
1024 if ((indexer.isFilterSearch() &&
1025 indexer.hasPermission(
1026 permissionChecker, entryClassName, entryClassPK,
1027 ActionKeys.VIEW)) ||
1028 !indexer.isFilterSearch() ||
1029 !indexer.isPermissionAware()) {
1030
1031 docs.add(document);
1032 scores.add(hits.score(i));
1033 }
1034 }
1035 catch (Exception e) {
1036 }
1037
1038 if (paginationType.equals("more") && (docs.size() > end)) {
1039 hasMore = true;
1040
1041 break;
1042 }
1043 }
1044
1045 int length = docs.size();
1046
1047 if (hasMore) {
1048 length = length + (end - start);
1049 }
1050
1051 hits.setLength(length);
1052
1053 if ((start != QueryUtil.ALL_POS) && (end != QueryUtil.ALL_POS)) {
1054 if (end > length) {
1055 end = length;
1056 }
1057
1058 docs = docs.subList(start, end);
1059 }
1060
1061 hits.setDocs(docs.toArray(new Document[docs.size()]));
1062 hits.setScores(scores.toArray(new Float[docs.size()]));
1063
1064 hits.setSearchTime(
1065 (float)(System.currentTimeMillis() - hits.getStart()) /
1066 Time.SECOND);
1067
1068 return hits;
1069 }
1070
1071 protected Document getBaseModelDocument(
1072 String portletId, BaseModel<?> baseModel)
1073 throws SystemException {
1074
1075 return getBaseModelDocument(portletId, baseModel, baseModel);
1076 }
1077
1078 protected Document getBaseModelDocument(
1079 String portletId, BaseModel<?> baseModel,
1080 BaseModel<?> workflowedBaseModel)
1081 throws SystemException {
1082
1083 Document document = new DocumentImpl();
1084
1085 String className = baseModel.getModelClassName();
1086
1087 long classPK = 0;
1088 long resourcePrimKey = 0;
1089
1090 if (baseModel instanceof ResourcedModel) {
1091 ResourcedModel resourcedModel = (ResourcedModel)baseModel;
1092
1093 classPK = resourcedModel.getResourcePrimKey();
1094 resourcePrimKey = resourcedModel.getResourcePrimKey();
1095 }
1096 else {
1097 classPK = (Long)baseModel.getPrimaryKeyObj();
1098 }
1099
1100 document.addUID(portletId, classPK);
1101
1102 List<AssetCategory> assetCategories =
1103 AssetCategoryLocalServiceUtil.getCategories(className, classPK);
1104
1105 long[] assetCategoryIds = StringUtil.split(
1106 ListUtil.toString(
1107 assetCategories, AssetCategory.CATEGORY_ID_ACCESSOR),
1108 0L);
1109
1110 document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
1111
1112 addSearchAssetCategoryTitles(
1113 document, Field.ASSET_CATEGORY_TITLES, assetCategories);
1114
1115 String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(
1116 className, classPK);
1117
1118 document.addText(Field.ASSET_TAG_NAMES, assetTagNames);
1119
1120 document.addKeyword(Field.ENTRY_CLASS_NAME, className);
1121 document.addKeyword(Field.ENTRY_CLASS_PK, classPK);
1122 document.addKeyword(Field.PORTLET_ID, portletId);
1123
1124 if (resourcePrimKey > 0) {
1125 document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
1126 }
1127
1128 if (baseModel instanceof AttachedModel) {
1129 AttachedModel attachedModel = (AttachedModel)baseModel;
1130
1131 document.addKeyword(
1132 Field.CLASS_NAME_ID, attachedModel.getClassNameId());
1133 document.addKeyword(Field.CLASS_PK, attachedModel.getClassPK());
1134 }
1135
1136 if (baseModel instanceof AuditedModel) {
1137 AuditedModel auditedModel = (AuditedModel)baseModel;
1138
1139 document.addKeyword(Field.COMPANY_ID, auditedModel.getCompanyId());
1140 document.addDate(Field.CREATE_DATE, auditedModel.getCreateDate());
1141 document.addDate(
1142 Field.MODIFIED_DATE, auditedModel.getModifiedDate());
1143 document.addKeyword(Field.USER_ID, auditedModel.getUserId());
1144
1145 String userName = PortalUtil.getUserName(
1146 auditedModel.getUserId(), auditedModel.getUserName());
1147
1148 document.addKeyword(Field.USER_NAME, userName, true);
1149 }
1150
1151 GroupedModel groupedModel = null;
1152
1153 if (baseModel instanceof GroupedModel) {
1154 groupedModel = (GroupedModel)baseModel;
1155
1156 document.addKeyword(
1157 Field.GROUP_ID, getParentGroupId(groupedModel.getGroupId()));
1158 document.addKeyword(
1159 Field.SCOPE_GROUP_ID, groupedModel.getGroupId());
1160 }
1161
1162 if (workflowedBaseModel instanceof WorkflowedModel) {
1163 WorkflowedModel workflowedModel =
1164 (WorkflowedModel)workflowedBaseModel;
1165
1166 document.addKeyword(Field.STATUS, workflowedModel.getStatus());
1167
1168 if ((groupedModel != null) && workflowedModel.isInTrash()) {
1169 addTrashFields(document, className, classPK, null, null, null);
1170 }
1171 }
1172
1173 ExpandoBridgeIndexerUtil.addAttributes(
1174 document, baseModel.getExpandoBridge());
1175
1176 return document;
1177 }
1178
1179 protected String getClassName(SearchContext searchContext) {
1180 String[] classNames = getClassNames();
1181
1182 if (classNames.length != 1) {
1183 throw new UnsupportedOperationException(
1184 "Search method needs to be manually implemented for " +
1185 "indexers with more than one class name");
1186 }
1187
1188 return classNames[0];
1189 }
1190
1191 protected Set<String> getLocalizedCountryNames(Country country) {
1192 Set<String> countryNames = new HashSet<String>();
1193
1194 Locale[] locales = LanguageUtil.getAvailableLocales();
1195
1196 for (Locale locale : locales) {
1197 String countryName = country.getName(locale);
1198
1199 countryName = countryName.toLowerCase();
1200
1201 countryNames.add(countryName);
1202 }
1203
1204 return countryNames;
1205 }
1206
1207 protected long getParentGroupId(long groupId) {
1208 long parentGroupId = groupId;
1209
1210 try {
1211 Group group = GroupLocalServiceUtil.getGroup(groupId);
1212
1213 if (group.isLayout()) {
1214 parentGroupId = group.getParentGroupId();
1215 }
1216 }
1217 catch (Exception e) {
1218 }
1219
1220 return parentGroupId;
1221 }
1222
1223 protected abstract String getPortletId(SearchContext searchContext);
1224
1225 protected Locale getSnippetLocale(Document document, Locale locale) {
1226 String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1227
1228 String localizedContentName =
1229 prefix + DocumentImpl.getLocalizedName(locale, Field.CONTENT);
1230 String localizedDescriptionName =
1231 prefix + DocumentImpl.getLocalizedName(locale, Field.DESCRIPTION);
1232 String localizedTitleName =
1233 prefix + DocumentImpl.getLocalizedName(locale, Field.TITLE);
1234
1235 if ((document.getField(localizedContentName) != null) ||
1236 (document.getField(localizedDescriptionName) != null) ||
1237 (document.getField(localizedTitleName) != null)) {
1238
1239 return locale;
1240 }
1241
1242 return null;
1243 }
1244
1245 protected void populateAddresses(
1246 Document document, List<Address> addresses, long regionId,
1247 long countryId)
1248 throws PortalException, SystemException {
1249
1250 List<String> cities = new ArrayList<String>();
1251
1252 List<String> countries = new ArrayList<String>();
1253
1254 if (countryId > 0) {
1255 try {
1256 Country country = CountryServiceUtil.getCountry(countryId);
1257
1258 countries.addAll(getLocalizedCountryNames(country));
1259 }
1260 catch (NoSuchCountryException nsce) {
1261 if (_log.isWarnEnabled()) {
1262 _log.warn(nsce.getMessage());
1263 }
1264 }
1265 }
1266
1267 List<String> regions = new ArrayList<String>();
1268
1269 if (regionId > 0) {
1270 try {
1271 Region region = RegionServiceUtil.getRegion(regionId);
1272
1273 regions.add(region.getName().toLowerCase());
1274 }
1275 catch (NoSuchRegionException nsre) {
1276 if (_log.isWarnEnabled()) {
1277 _log.warn(nsre.getMessage());
1278 }
1279 }
1280 }
1281
1282 List<String> streets = new ArrayList<String>();
1283 List<String> zips = new ArrayList<String>();
1284
1285 for (Address address : addresses) {
1286 cities.add(address.getCity().toLowerCase());
1287 countries.addAll(getLocalizedCountryNames(address.getCountry()));
1288 regions.add(address.getRegion().getName().toLowerCase());
1289 streets.add(address.getStreet1().toLowerCase());
1290 streets.add(address.getStreet2().toLowerCase());
1291 streets.add(address.getStreet3().toLowerCase());
1292 zips.add(address.getZip().toLowerCase());
1293 }
1294
1295 document.addText("city", cities.toArray(new String[cities.size()]));
1296 document.addText(
1297 "country", countries.toArray(new String[countries.size()]));
1298 document.addText("region", regions.toArray(new String[regions.size()]));
1299 document.addText("street", streets.toArray(new String[streets.size()]));
1300 document.addText("zip", zips.toArray(new String[zips.size()]));
1301 }
1302
1303 protected void postProcessFullQuery(
1304 BooleanQuery fullQuery, SearchContext searchContext)
1305 throws Exception {
1306 }
1307
1308 protected void setFilterSearch(boolean filterSearch) {
1309 _filterSearch = filterSearch;
1310 }
1311
1312 protected void setIndexerEnabled(boolean indexerEnabled) {
1313 _indexerEnabled = indexerEnabled;
1314 }
1315
1316 protected void setPermissionAware(boolean permissionAware) {
1317 _permissionAware = permissionAware;
1318 }
1319
1320 protected void setStagingAware(boolean stagingAware) {
1321 _stagingAware = stagingAware;
1322 }
1323
1324 private static Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
1325
1326 private boolean _filterSearch;
1327 private boolean _indexerEnabled = true;
1328 private IndexerPostProcessor[] _indexerPostProcessors =
1329 new IndexerPostProcessor[0];
1330 private boolean _permissionAware;
1331 private String _searchEngineId;
1332 private boolean _stagingAware = true;
1333
1334 }