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