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 if (!isStagingAware()) {
1158 return;
1159 }
1160
1161 document.addKeyword(Field.STAGING_GROUP, isStagingGroup(groupId));
1162 }
1163
1164 protected void addStatus(
1165 BooleanQuery contextQuery, SearchContext searchContext)
1166 throws Exception {
1167
1168 int status = GetterUtil.getInteger(
1169 searchContext.getAttribute(Field.STATUS),
1170 WorkflowConstants.STATUS_APPROVED);
1171
1172 if (status != WorkflowConstants.STATUS_ANY) {
1173 contextQuery.addRequiredTerm(Field.STATUS, status);
1174 }
1175 else {
1176 BooleanQuery statusQuery = BooleanQueryFactoryUtil.create(
1177 searchContext);
1178
1179 statusQuery.addTerm(
1180 Field.STATUS, WorkflowConstants.STATUS_IN_TRASH);
1181
1182 contextQuery.add(statusQuery, BooleanClauseOccur.MUST_NOT);
1183 }
1184 }
1185
1186 protected void addTrashFields(Document document, TrashedModel trashedModel)
1187 throws SystemException {
1188
1189 TrashEntry trashEntry = null;
1190
1191 try {
1192 trashEntry = trashedModel.getTrashEntry();
1193 }
1194 catch (PortalException pe) {
1195 if (_log.isDebugEnabled()) {
1196 _log.debug("Unable to get trash entry for " + trashedModel);
1197 }
1198 }
1199
1200 if (trashEntry == null) {
1201 document.addDate(Field.REMOVED_DATE, new Date());
1202
1203 ServiceContext serviceContext =
1204 ServiceContextThreadLocal.getServiceContext();
1205
1206 if (serviceContext != null) {
1207 try {
1208 User user = UserLocalServiceUtil.getUser(
1209 serviceContext.getUserId());
1210
1211 document.addKeyword(
1212 Field.REMOVED_BY_USER_NAME, user.getFullName(), true);
1213 }
1214 catch (PortalException pe) {
1215 }
1216 }
1217 }
1218 else {
1219 document.addDate(Field.REMOVED_DATE, trashEntry.getCreateDate());
1220 document.addKeyword(
1221 Field.REMOVED_BY_USER_NAME, trashEntry.getUserName(), true);
1222
1223 if (trashedModel.isInTrash() &&
1224 !_isInTrashExplicitly(trashedModel)) {
1225
1226 document.addKeyword(
1227 Field.ROOT_ENTRY_CLASS_NAME, trashEntry.getClassName());
1228 document.addKeyword(
1229 Field.ROOT_ENTRY_CLASS_PK, trashEntry.getClassPK());
1230 }
1231 }
1232
1233 TrashHandler trashHandler = trashedModel.getTrashHandler();
1234
1235 try {
1236 TrashRenderer trashRenderer = null;
1237
1238 if ((trashHandler != null) && (trashEntry != null)) {
1239 trashRenderer = trashHandler.getTrashRenderer(
1240 trashEntry.getClassPK());
1241 }
1242
1243 if (trashRenderer != null) {
1244 document.addKeyword(Field.TYPE, trashRenderer.getType(), true);
1245 }
1246 }
1247 catch (PortalException pe) {
1248 if (_log.isDebugEnabled()) {
1249 _log.debug(
1250 "Unable to get trash renderer for " +
1251 trashEntry.getClassName());
1252 }
1253 }
1254 }
1255
1256 protected BooleanQuery createFullQuery(
1257 BooleanQuery contextQuery, SearchContext searchContext)
1258 throws Exception {
1259
1260 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
1261 searchContext);
1262
1263 addSearchKeywords(searchQuery, searchContext);
1264 postProcessSearchQuery(searchQuery, searchContext);
1265
1266 for (IndexerPostProcessor indexerPostProcessor :
1267 _indexerPostProcessors) {
1268
1269 indexerPostProcessor.postProcessSearchQuery(
1270 searchQuery, searchContext);
1271 }
1272
1273 Map<String, Facet> facets = searchContext.getFacets();
1274
1275 for (Facet facet : facets.values()) {
1276 BooleanClause facetClause = facet.getFacetClause();
1277
1278 if (facetClause != null) {
1279 contextQuery.add(
1280 facetClause.getQuery(),
1281 facetClause.getBooleanClauseOccur());
1282 }
1283 }
1284
1285 BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
1286
1287 fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
1288
1289 if (searchQuery.hasClauses()) {
1290 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1291 }
1292
1293 BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
1294
1295 if (booleanClauses != null) {
1296 for (BooleanClause booleanClause : booleanClauses) {
1297 fullQuery.add(
1298 booleanClause.getQuery(),
1299 booleanClause.getBooleanClauseOccur());
1300 }
1301 }
1302
1303 postProcessFullQuery(fullQuery, searchContext);
1304
1305 for (IndexerPostProcessor indexerPostProcessor :
1306 _indexerPostProcessors) {
1307
1308 indexerPostProcessor.postProcessFullQuery(fullQuery, searchContext);
1309 }
1310
1311 return fullQuery;
1312 }
1313
1314 protected Summary createLocalizedSummary(Document document, Locale locale) {
1315 return createLocalizedSummary(
1316 document, locale, Field.TITLE, Field.CONTENT);
1317 }
1318
1319 protected Summary createLocalizedSummary(
1320 Document document, Locale locale, String titleField,
1321 String contentField) {
1322
1323 Locale snippetLocale = getSnippetLocale(document, locale);
1324
1325 String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1326
1327 String title = document.get(
1328 snippetLocale, prefix + titleField, titleField);
1329
1330 String content = document.get(
1331 snippetLocale, prefix + contentField, contentField);
1332
1333 return new Summary(snippetLocale, title, content, null);
1334 }
1335
1336 protected Summary createSummary(Document document) {
1337 return createSummary(document, Field.TITLE, Field.CONTENT);
1338 }
1339
1340 protected Summary createSummary(
1341 Document document, String titleField, String contentField) {
1342
1343 String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1344
1345 String title = document.get(prefix + titleField, titleField);
1346 String content = document.get(prefix + contentField, contentField);
1347
1348 return new Summary(title, content, null);
1349 }
1350
1351 protected void deleteDocument(long companyId, long field1)
1352 throws Exception {
1353
1354 deleteDocument(companyId, String.valueOf(field1));
1355 }
1356
1357 protected void deleteDocument(long companyId, long field1, String field2)
1358 throws Exception {
1359
1360 deleteDocument(companyId, String.valueOf(field1), field2);
1361 }
1362
1363 protected void deleteDocument(long companyId, String field1)
1364 throws Exception {
1365
1366 Document document = new DocumentImpl();
1367
1368 document.addUID(getPortletId(), field1);
1369
1370 SearchEngineUtil.deleteDocument(
1371 getSearchEngineId(), companyId, document.get(Field.UID),
1372 _commitImmediately);
1373 }
1374
1375 protected void deleteDocument(long companyId, String field1, String field2)
1376 throws Exception {
1377
1378 Document document = new DocumentImpl();
1379
1380 document.addUID(getPortletId(), field1, field2);
1381
1382 SearchEngineUtil.deleteDocument(
1383 getSearchEngineId(), companyId, document.get(Field.UID),
1384 _commitImmediately);
1385 }
1386
1387 protected abstract void doDelete(Object obj) throws Exception;
1388
1389 protected abstract Document doGetDocument(Object obj) throws Exception;
1390
1391 protected String doGetSortField(String orderByCol) {
1392 return orderByCol;
1393 }
1394
1395 protected abstract Summary doGetSummary(
1396 Document document, Locale locale, String snippet,
1397 PortletURL portletURL)
1398 throws Exception;
1399
1400 protected abstract void doReindex(Object obj) throws Exception;
1401
1402 protected abstract void doReindex(String className, long classPK)
1403 throws Exception;
1404
1405 protected abstract void doReindex(String[] ids) throws Exception;
1406
1407 protected void doReindexDDMStructures(List<Long> structureIds)
1408 throws Exception {
1409 }
1410
1411 protected Hits doSearch(SearchContext searchContext)
1412 throws SearchException {
1413
1414 searchContext.setSearchEngineId(getSearchEngineId());
1415
1416 BooleanQuery fullQuery = getFullQuery(searchContext);
1417
1418 QueryConfig queryConfig = searchContext.getQueryConfig();
1419
1420 fullQuery.setQueryConfig(queryConfig);
1421
1422 return SearchEngineUtil.search(searchContext, fullQuery);
1423 }
1424
1425
1428 protected Hits filterSearch(
1429 Hits hits, PermissionChecker permissionChecker,
1430 SearchContext searchContext) {
1431
1432 List<Document> docs = new ArrayList<Document>();
1433 List<Float> scores = new ArrayList<Float>();
1434
1435 int start = searchContext.getStart();
1436 int end = searchContext.getEnd();
1437
1438 String paginationType = GetterUtil.getString(
1439 searchContext.getAttribute("paginationType"), "more");
1440
1441 boolean hasMore = false;
1442
1443 Document[] documents = hits.getDocs();
1444
1445 int excludeDocsSize = 0;
1446
1447 for (int i = 0; i < documents.length; i++) {
1448 try {
1449 Document document = documents[i];
1450
1451 String entryClassName = document.get(Field.ENTRY_CLASS_NAME);
1452 long entryClassPK = GetterUtil.getLong(
1453 document.get(Field.ENTRY_CLASS_PK));
1454
1455 Indexer indexer = IndexerRegistryUtil.getIndexer(
1456 entryClassName);
1457
1458 if ((indexer.isFilterSearch() &&
1459 indexer.hasPermission(
1460 permissionChecker, entryClassName, entryClassPK,
1461 ActionKeys.VIEW)) ||
1462 !indexer.isFilterSearch() ||
1463 !indexer.isPermissionAware()) {
1464
1465 docs.add(document);
1466 scores.add(hits.score(i));
1467 }
1468 else {
1469 excludeDocsSize++;
1470 }
1471 }
1472 catch (Exception e) {
1473 excludeDocsSize++;
1474 }
1475
1476 if (paginationType.equals("more") && (end > 0) &&
1477 (end < documents.length) && (docs.size() >= end)) {
1478
1479 hasMore = true;
1480
1481 break;
1482 }
1483 }
1484
1485 int length = docs.size();
1486
1487 if (hasMore) {
1488 length = documents.length - excludeDocsSize;
1489 }
1490
1491 hits.setLength(length);
1492
1493 if ((start != QueryUtil.ALL_POS) && (end != QueryUtil.ALL_POS)) {
1494 if (end > length) {
1495 end = length;
1496 }
1497
1498 if (start > end) {
1499 start = length;
1500 }
1501
1502 docs = docs.subList(start, end);
1503 }
1504
1505 hits.setDocs(docs.toArray(new Document[docs.size()]));
1506 hits.setScores(scores.toArray(new Float[scores.size()]));
1507
1508 hits.setSearchTime(
1509 (float)(System.currentTimeMillis() - hits.getStart()) /
1510 Time.SECOND);
1511
1512 return hits;
1513 }
1514
1515 protected Document getBaseModelDocument(
1516 String portletId, BaseModel<?> baseModel)
1517 throws SystemException {
1518
1519 return getBaseModelDocument(portletId, baseModel, baseModel);
1520 }
1521
1522 protected Document getBaseModelDocument(
1523 String portletId, BaseModel<?> baseModel,
1524 BaseModel<?> workflowedBaseModel)
1525 throws SystemException {
1526
1527 Document document = newDocument();
1528
1529 String className = baseModel.getModelClassName();
1530
1531 long classPK = 0;
1532 long resourcePrimKey = 0;
1533
1534 if (baseModel instanceof ResourcedModel) {
1535 ResourcedModel resourcedModel = (ResourcedModel)baseModel;
1536
1537 classPK = resourcedModel.getResourcePrimKey();
1538 resourcePrimKey = resourcedModel.getResourcePrimKey();
1539 }
1540 else {
1541 classPK = (Long)baseModel.getPrimaryKeyObj();
1542 }
1543
1544 document.addUID(portletId, classPK);
1545
1546 List<AssetCategory> assetCategories =
1547 AssetCategoryLocalServiceUtil.getCategories(className, classPK);
1548
1549 long[] assetCategoryIds = StringUtil.split(
1550 ListUtil.toString(
1551 assetCategories, AssetCategory.CATEGORY_ID_ACCESSOR),
1552 0L);
1553
1554 document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
1555
1556 addSearchAssetCategoryTitles(
1557 document, Field.ASSET_CATEGORY_TITLES, assetCategories);
1558
1559 long classNameId = PortalUtil.getClassNameId(className);
1560
1561 List<AssetTag> assetTags = AssetTagLocalServiceUtil.getTags(
1562 classNameId, classPK);
1563
1564 String[] assetTagNames = StringUtil.split(
1565 ListUtil.toString(assetTags, AssetTag.NAME_ACCESSOR));
1566
1567 document.addText(Field.ASSET_TAG_NAMES, assetTagNames);
1568
1569 long[] assetTagsIds = StringUtil.split(
1570 ListUtil.toString(assetTags, AssetTag.TAG_ID_ACCESSOR), 0L);
1571
1572 document.addKeyword(Field.ASSET_TAG_IDS, assetTagsIds);
1573
1574 document.addKeyword(Field.ENTRY_CLASS_NAME, className);
1575 document.addKeyword(Field.ENTRY_CLASS_PK, classPK);
1576 document.addKeyword(Field.PORTLET_ID, portletId);
1577
1578 if (resourcePrimKey > 0) {
1579 document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
1580 }
1581
1582 if (baseModel instanceof AttachedModel) {
1583 AttachedModel attachedModel = (AttachedModel)baseModel;
1584
1585 document.addKeyword(
1586 Field.CLASS_NAME_ID, attachedModel.getClassNameId());
1587 document.addKeyword(Field.CLASS_PK, attachedModel.getClassPK());
1588 }
1589
1590 if (baseModel instanceof AuditedModel) {
1591 AuditedModel auditedModel = (AuditedModel)baseModel;
1592
1593 document.addKeyword(Field.COMPANY_ID, auditedModel.getCompanyId());
1594 document.addDate(Field.CREATE_DATE, auditedModel.getCreateDate());
1595 document.addDate(
1596 Field.MODIFIED_DATE, auditedModel.getModifiedDate());
1597 document.addKeyword(Field.USER_ID, auditedModel.getUserId());
1598
1599 String userName = PortalUtil.getUserName(
1600 auditedModel.getUserId(), auditedModel.getUserName());
1601
1602 document.addKeyword(Field.USER_NAME, userName, true);
1603 }
1604
1605 GroupedModel groupedModel = null;
1606
1607 if (baseModel instanceof GroupedModel) {
1608 groupedModel = (GroupedModel)baseModel;
1609
1610 document.addKeyword(
1611 Field.GROUP_ID, getSiteGroupId(groupedModel.getGroupId()));
1612 document.addKeyword(
1613 Field.SCOPE_GROUP_ID, groupedModel.getGroupId());
1614 }
1615
1616 if (workflowedBaseModel instanceof WorkflowedModel) {
1617 WorkflowedModel workflowedModel =
1618 (WorkflowedModel)workflowedBaseModel;
1619
1620 document.addKeyword(Field.STATUS, workflowedModel.getStatus());
1621 }
1622
1623 if ((groupedModel != null) && (baseModel instanceof TrashedModel)) {
1624 TrashedModel trashedModel = (TrashedModel)baseModel;
1625
1626 if (trashedModel.isInTrash()) {
1627 addTrashFields(document, trashedModel);
1628 }
1629 }
1630
1631 addAssetFields(document, className, classPK);
1632
1633 ExpandoBridgeIndexerUtil.addAttributes(
1634 document, baseModel.getExpandoBridge());
1635
1636 return document;
1637 }
1638
1639 protected String getClassName(SearchContext searchContext) {
1640 String[] classNames = getClassNames();
1641
1642 return classNames[0];
1643 }
1644
1645 protected Set<String> getLocalizedCountryNames(Country country) {
1646 Set<String> countryNames = new HashSet<String>();
1647
1648 Locale[] locales = LanguageUtil.getAvailableLocales();
1649
1650 for (Locale locale : locales) {
1651 String countryName = country.getName(locale);
1652
1653 countryName = StringUtil.toLowerCase(countryName);
1654
1655 countryNames.add(countryName);
1656 }
1657
1658 return countryNames;
1659 }
1660
1661
1664 protected long getParentGroupId(long groupId) {
1665 return getSiteGroupId(groupId);
1666 }
1667
1668 protected abstract String getPortletId(SearchContext searchContext);
1669
1670 protected Group getSiteGroup(long groupId) {
1671 Group group = null;
1672
1673 try {
1674 group = GroupLocalServiceUtil.getGroup(groupId);
1675
1676 if (group.isLayout()) {
1677 group = group.getParentGroup();
1678 }
1679 }
1680 catch (Exception e) {
1681 if (_log.isDebugEnabled()) {
1682 _log.debug("Unable to get site group", e);
1683 }
1684 }
1685
1686 return group;
1687 }
1688
1689 protected long getSiteGroupId(long groupId) {
1690 Group group = getSiteGroup(groupId);
1691
1692 if (group == null) {
1693 return groupId;
1694 }
1695
1696 return group.getGroupId();
1697 }
1698
1699 protected Locale getSnippetLocale(Document document, Locale locale) {
1700 String prefix = Field.SNIPPET + StringPool.UNDERLINE;
1701
1702 String localizedAssetCategoryTitlesName =
1703 prefix +
1704 DocumentImpl.getLocalizedName(locale, Field.ASSET_CATEGORY_TITLES);
1705 String localizedContentName =
1706 prefix + DocumentImpl.getLocalizedName(locale, Field.CONTENT);
1707 String localizedDescriptionName =
1708 prefix + DocumentImpl.getLocalizedName(locale, Field.DESCRIPTION);
1709 String localizedTitleName =
1710 prefix + DocumentImpl.getLocalizedName(locale, Field.TITLE);
1711
1712 if ((document.getField(localizedAssetCategoryTitlesName) != null) ||
1713 (document.getField(localizedContentName) != null) ||
1714 (document.getField(localizedDescriptionName) != null) ||
1715 (document.getField(localizedTitleName) != null)) {
1716
1717 return locale;
1718 }
1719
1720 return null;
1721 }
1722
1723 protected boolean isStagingGroup(long groupId) {
1724 Group group = getSiteGroup(groupId);
1725
1726 if (group == null) {
1727 return false;
1728 }
1729
1730 return group.isStagingGroup();
1731 }
1732
1733 protected boolean isUseSearchResultPermissionFilter(
1734 SearchContext searchContext) {
1735
1736 return isFilterSearch();
1737 }
1738
1739 protected boolean isVisible(int entryStatus, int queryStatus) {
1740 if (((queryStatus != WorkflowConstants.STATUS_ANY) &&
1741 (entryStatus == queryStatus)) ||
1742 (entryStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1743
1744 return true;
1745 }
1746
1747 return false;
1748 }
1749
1750 protected Document newDocument() {
1751 return (Document)_document.clone();
1752 }
1753
1754 protected void populateAddresses(
1755 Document document, List<Address> addresses, long regionId,
1756 long countryId)
1757 throws PortalException, SystemException {
1758
1759 List<String> cities = new ArrayList<String>();
1760
1761 List<String> countries = new ArrayList<String>();
1762
1763 if (countryId > 0) {
1764 try {
1765 Country country = CountryServiceUtil.getCountry(countryId);
1766
1767 countries.addAll(getLocalizedCountryNames(country));
1768 }
1769 catch (NoSuchCountryException nsce) {
1770 if (_log.isWarnEnabled()) {
1771 _log.warn(nsce.getMessage());
1772 }
1773 }
1774 }
1775
1776 List<String> regions = new ArrayList<String>();
1777
1778 if (regionId > 0) {
1779 try {
1780 Region region = RegionServiceUtil.getRegion(regionId);
1781
1782 regions.add(StringUtil.toLowerCase(region.getName()));
1783 }
1784 catch (NoSuchRegionException nsre) {
1785 if (_log.isWarnEnabled()) {
1786 _log.warn(nsre.getMessage());
1787 }
1788 }
1789 }
1790
1791 List<String> streets = new ArrayList<String>();
1792 List<String> zips = new ArrayList<String>();
1793
1794 for (Address address : addresses) {
1795 cities.add(StringUtil.toLowerCase(address.getCity()));
1796 countries.addAll(getLocalizedCountryNames(address.getCountry()));
1797 regions.add(StringUtil.toLowerCase(address.getRegion().getName()));
1798 streets.add(StringUtil.toLowerCase(address.getStreet1()));
1799 streets.add(StringUtil.toLowerCase(address.getStreet2()));
1800 streets.add(StringUtil.toLowerCase(address.getStreet3()));
1801 zips.add(StringUtil.toLowerCase(address.getZip()));
1802 }
1803
1804 document.addText("city", cities.toArray(new String[cities.size()]));
1805 document.addText(
1806 "country", countries.toArray(new String[countries.size()]));
1807 document.addText("region", regions.toArray(new String[regions.size()]));
1808 document.addText("street", streets.toArray(new String[streets.size()]));
1809 document.addText("zip", zips.toArray(new String[zips.size()]));
1810 }
1811
1812 protected Map<Locale, String> populateMap(
1813 AssetEntry assetEntry, Map<Locale, String> map) {
1814
1815 Locale[] availableLocales = LanguageUtil.getAvailableLocales(
1816 assetEntry.getGroupId());
1817
1818 String defaultValue = map.get(
1819 LocaleUtil.fromLanguageId(assetEntry.getDefaultLanguageId()));
1820
1821 for (Locale availableLocale : availableLocales) {
1822 if (!map.containsKey(availableLocale) ||
1823 Validator.isNull(map.get(availableLocale))) {
1824
1825 map.put(availableLocale, defaultValue);
1826 }
1827 }
1828
1829 return map;
1830 }
1831
1832 protected void postProcessFullQuery(
1833 BooleanQuery fullQuery, SearchContext searchContext)
1834 throws Exception {
1835 }
1836
1837 protected void processHits(SearchContext searchContext, Hits hits)
1838 throws SearchException {
1839
1840 HitsProcessor hitsProcessor =
1841 HitsProcessorRegistryUtil.getDefaultHitsProcessor();
1842
1843 if (hitsProcessor != null) {
1844 hitsProcessor.process(searchContext, hits);
1845 }
1846 }
1847
1848 protected void setFilterSearch(boolean filterSearch) {
1849 _filterSearch = filterSearch;
1850 }
1851
1852 protected void setIndexerEnabled(boolean indexerEnabled) {
1853 _indexerEnabled = indexerEnabled;
1854 }
1855
1856 protected void setPermissionAware(boolean permissionAware) {
1857 _permissionAware = permissionAware;
1858 }
1859
1860 protected void setSortableTextFields(String[] sortableTextFields) {
1861 _document.setSortableTextFields(sortableTextFields);
1862 }
1863
1864 protected void setStagingAware(boolean stagingAware) {
1865 _stagingAware = stagingAware;
1866 }
1867
1868 private boolean _isInTrashExplicitly(TrashedModel trashedModel)
1869 throws SystemException {
1870
1871 if (!trashedModel.isInTrash()) {
1872 return false;
1873 }
1874
1875 ClassedModel classedModel = (ClassedModel)trashedModel;
1876
1877 TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
1878 classedModel.getModelClassName(),
1879 trashedModel.getTrashEntryClassPK());
1880
1881 if (trashEntry != null) {
1882 return true;
1883 }
1884
1885 return false;
1886 }
1887
1888 private static Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
1889
1890 private boolean _commitImmediately;
1891 private Document _document = new DocumentImpl();
1892 private boolean _filterSearch;
1893 private boolean _indexerEnabled = true;
1894 private IndexerPostProcessor[] _indexerPostProcessors =
1895 new IndexerPostProcessor[0];
1896 private boolean _permissionAware;
1897 private String _searchEngineId;
1898 private boolean _stagingAware = true;
1899
1900 }