001
014
015 package com.liferay.portlet.messageboards.util;
016
017 import com.liferay.portal.kernel.comment.Comment;
018 import com.liferay.portal.kernel.comment.CommentManagerUtil;
019 import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
020 import com.liferay.portal.kernel.dao.orm.DynamicQuery;
021 import com.liferay.portal.kernel.dao.orm.IndexableActionableDynamicQuery;
022 import com.liferay.portal.kernel.dao.orm.Property;
023 import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
024 import com.liferay.portal.kernel.exception.PortalException;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslatorUtil;
028 import com.liferay.portal.kernel.repository.model.FileEntry;
029 import com.liferay.portal.kernel.search.BaseIndexer;
030 import com.liferay.portal.kernel.search.BaseRelatedEntryIndexer;
031 import com.liferay.portal.kernel.search.BooleanClauseOccur;
032 import com.liferay.portal.kernel.search.Document;
033 import com.liferay.portal.kernel.search.Field;
034 import com.liferay.portal.kernel.search.Indexer;
035 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
036 import com.liferay.portal.kernel.search.RelatedEntryIndexer;
037 import com.liferay.portal.kernel.search.SearchContext;
038 import com.liferay.portal.kernel.search.SearchEngineUtil;
039 import com.liferay.portal.kernel.search.Summary;
040 import com.liferay.portal.kernel.search.filter.BooleanFilter;
041 import com.liferay.portal.kernel.search.filter.TermsFilter;
042 import com.liferay.portal.kernel.spring.osgi.OSGiBeanProperties;
043 import com.liferay.portal.kernel.util.GetterUtil;
044 import com.liferay.portal.kernel.util.HtmlUtil;
045 import com.liferay.portal.kernel.workflow.WorkflowConstants;
046 import com.liferay.portal.model.Group;
047 import com.liferay.portal.security.permission.ActionKeys;
048 import com.liferay.portal.security.permission.PermissionChecker;
049 import com.liferay.portal.service.GroupLocalServiceUtil;
050 import com.liferay.portlet.messageboards.model.MBCategory;
051 import com.liferay.portlet.messageboards.model.MBCategoryConstants;
052 import com.liferay.portlet.messageboards.model.MBDiscussion;
053 import com.liferay.portlet.messageboards.model.MBMessage;
054 import com.liferay.portlet.messageboards.service.MBCategoryLocalServiceUtil;
055 import com.liferay.portlet.messageboards.service.MBCategoryServiceUtil;
056 import com.liferay.portlet.messageboards.service.MBDiscussionLocalServiceUtil;
057 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
058 import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
059
060 import java.util.List;
061 import java.util.Locale;
062
063 import javax.portlet.PortletRequest;
064 import javax.portlet.PortletResponse;
065
066
072 @OSGiBeanProperties
073 public class MBMessageIndexer
074 extends BaseIndexer<MBMessage> implements RelatedEntryIndexer {
075
076 public static final String CLASS_NAME = MBMessage.class.getName();
077
078 public MBMessageIndexer() {
079 setDefaultSelectedFieldNames(
080 Field.ASSET_TAG_NAMES, Field.CLASS_NAME_ID, Field.CLASS_PK,
081 Field.COMPANY_ID, Field.CONTENT, Field.ENTRY_CLASS_NAME,
082 Field.ENTRY_CLASS_PK, Field.GROUP_ID, Field.MODIFIED_DATE,
083 Field.SCOPE_GROUP_ID, Field.TITLE, Field.UID);
084 setFilterSearch(true);
085 setPermissionAware(true);
086 }
087
088 @Override
089 public void addRelatedClassNames(
090 BooleanFilter contextFilter, SearchContext searchContext)
091 throws Exception {
092
093 _relatedEntryIndexer.addRelatedClassNames(contextFilter, searchContext);
094 }
095
096 @Override
097 public void addRelatedEntryFields(Document document, Object obj)
098 throws Exception {
099
100 FileEntry fileEntry = (FileEntry)obj;
101
102 MBMessage message = MBMessageAttachmentsUtil.fetchMessage(
103 fileEntry.getFileEntryId());
104
105 if (message == null) {
106 return;
107 }
108
109 document.addKeyword(Field.CATEGORY_ID, message.getCategoryId());
110
111 document.addKeyword("discussion", false);
112 document.addKeyword("threadId", message.getThreadId());
113 }
114
115 @Override
116 public String getClassName() {
117 return CLASS_NAME;
118 }
119
120 @Override
121 public boolean hasPermission(
122 PermissionChecker permissionChecker, String entryClassName,
123 long entryClassPK, String actionId)
124 throws Exception {
125
126 MBMessage message = MBMessageLocalServiceUtil.getMessage(entryClassPK);
127
128 if (message.isDiscussion()) {
129 Indexer<?> indexer = IndexerRegistryUtil.getIndexer(
130 message.getClassName());
131
132 return indexer.hasPermission(
133 permissionChecker, message.getClassName(), message.getClassPK(),
134 ActionKeys.VIEW);
135 }
136
137 return MBMessagePermission.contains(
138 permissionChecker, entryClassPK, ActionKeys.VIEW);
139 }
140
141 @Override
142 public boolean isVisible(long classPK, int status) throws Exception {
143 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
144
145 return isVisible(message.getStatus(), status);
146 }
147
148 @Override
149 public boolean isVisibleRelatedEntry(long classPK, int status)
150 throws Exception {
151
152 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
153
154 if (message.isDiscussion()) {
155 Indexer<?> indexer = IndexerRegistryUtil.getIndexer(
156 message.getClassName());
157
158 return indexer.isVisible(message.getClassPK(), status);
159 }
160
161 return true;
162 }
163
164 @Override
165 public void postProcessContextBooleanFilter(
166 BooleanFilter contextBooleanFilter, SearchContext searchContext)
167 throws Exception {
168
169 addStatus(contextBooleanFilter, searchContext);
170
171 boolean discussion = GetterUtil.getBoolean(
172 searchContext.getAttribute("discussion"), false);
173
174 contextBooleanFilter.addRequiredTerm("discussion", discussion);
175
176 if (searchContext.isIncludeDiscussions()) {
177 addRelatedClassNames(contextBooleanFilter, searchContext);
178 }
179
180 long threadId = GetterUtil.getLong(
181 (String)searchContext.getAttribute("threadId"));
182
183 if (threadId > 0) {
184 contextBooleanFilter.addRequiredTerm("threadId", threadId);
185 }
186
187 long[] categoryIds = searchContext.getCategoryIds();
188
189 if ((categoryIds != null) && (categoryIds.length > 0) &&
190 (categoryIds[0] !=
191 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)) {
192
193 TermsFilter categoriesTermsFilter = new TermsFilter(
194 Field.CATEGORY_ID);
195
196 for (long categoryId : categoryIds) {
197 try {
198 MBCategoryServiceUtil.getCategory(categoryId);
199 }
200 catch (PortalException pe) {
201 if (_log.isDebugEnabled()) {
202 _log.debug(
203 "Unable to get message boards category " +
204 categoryId,
205 pe);
206 }
207
208 continue;
209 }
210
211 categoriesTermsFilter.addValue(String.valueOf(categoryId));
212 }
213
214 if (!categoriesTermsFilter.isEmpty()) {
215 contextBooleanFilter.add(
216 categoriesTermsFilter, BooleanClauseOccur.MUST);
217 }
218 }
219 }
220
221 @Override
222 public void updateFullQuery(SearchContext searchContext) {
223 if (searchContext.isIncludeDiscussions()) {
224 searchContext.addFullQueryEntryClassName(MBMessage.class.getName());
225
226 searchContext.setAttribute("discussion", Boolean.TRUE);
227 }
228 }
229
230 @Override
231 protected void doDelete(MBMessage mbMessage) throws Exception {
232 deleteDocument(mbMessage.getCompanyId(), mbMessage.getMessageId());
233 }
234
235 @Override
236 protected Document doGetDocument(MBMessage mbMessage) throws Exception {
237 Document document = getBaseModelDocument(CLASS_NAME, mbMessage);
238
239 document.addKeyword(Field.CATEGORY_ID, mbMessage.getCategoryId());
240 document.addText(Field.CONTENT, processContent(mbMessage));
241 document.addKeyword(
242 Field.ROOT_ENTRY_CLASS_PK, mbMessage.getRootMessageId());
243 document.addText(Field.TITLE, mbMessage.getSubject());
244
245 if (mbMessage.isAnonymous()) {
246 document.remove(Field.USER_NAME);
247 }
248
249 MBDiscussion discussion =
250 MBDiscussionLocalServiceUtil.fetchThreadDiscussion(
251 mbMessage.getThreadId());
252
253 if (discussion == null) {
254 document.addKeyword("discussion", false);
255 }
256 else {
257 document.addKeyword("discussion", true);
258 }
259
260 document.addKeyword("threadId", mbMessage.getThreadId());
261
262 if (mbMessage.isDiscussion()) {
263 Indexer<?> indexer = IndexerRegistryUtil.getIndexer(
264 mbMessage.getClassName());
265
266 if ((indexer != null) && (indexer instanceof RelatedEntryIndexer)) {
267 RelatedEntryIndexer relatedEntryIndexer =
268 (RelatedEntryIndexer)indexer;
269
270 Comment comment = CommentManagerUtil.fetchComment(
271 mbMessage.getMessageId());
272
273 if (comment != null) {
274 relatedEntryIndexer.addRelatedEntryFields(
275 document, comment);
276
277 document.addKeyword(Field.RELATED_ENTRY, true);
278 }
279 }
280 }
281
282 return document;
283 }
284
285 @Override
286 protected Summary doGetSummary(
287 Document document, Locale locale, String snippet,
288 PortletRequest portletRequest, PortletResponse portletResponse) {
289
290 Summary summary = createSummary(document, Field.TITLE, Field.CONTENT);
291
292 summary.setMaxContentLength(200);
293
294 return summary;
295 }
296
297 @Override
298 protected void doReindex(MBMessage mbMessage) throws Exception {
299 if ((!mbMessage.isApproved() && !mbMessage.isInTrash()) ||
300 (mbMessage.isDiscussion() && mbMessage.isRoot())) {
301
302 return;
303 }
304
305 Document document = getDocument(mbMessage);
306
307 SearchEngineUtil.updateDocument(
308 getSearchEngineId(), mbMessage.getCompanyId(), document,
309 isCommitImmediately());
310 }
311
312 @Override
313 protected void doReindex(String className, long classPK) throws Exception {
314 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
315
316 doReindex(message);
317
318 if (message.isRoot()) {
319 List<MBMessage> messages =
320 MBMessageLocalServiceUtil.getThreadMessages(
321 message.getThreadId(), WorkflowConstants.STATUS_APPROVED);
322
323 for (MBMessage curMessage : messages) {
324 reindex(curMessage);
325 }
326 }
327 else {
328 reindex(message);
329 }
330 }
331
332 @Override
333 protected void doReindex(String[] ids) throws Exception {
334 long companyId = GetterUtil.getLong(ids[0]);
335
336 reindexCategories(companyId);
337 reindexDiscussions(companyId);
338 reindexRoot(companyId);
339 }
340
341 protected String processContent(MBMessage message) {
342 String content = message.getBody();
343
344 try {
345 if (message.isFormatBBCode()) {
346 content = BBCodeTranslatorUtil.getHTML(content);
347 }
348 }
349 catch (Exception e) {
350 _log.error(
351 "Could not parse message " + message.getMessageId() + ": " +
352 e.getMessage());
353 }
354
355 content = HtmlUtil.extractText(content);
356
357 return content;
358 }
359
360 protected void reindexCategories(final long companyId)
361 throws PortalException {
362
363 ActionableDynamicQuery actionableDynamicQuery =
364 MBCategoryLocalServiceUtil.getActionableDynamicQuery();
365
366 actionableDynamicQuery.setCompanyId(companyId);
367 actionableDynamicQuery.setPerformActionMethod(
368 new ActionableDynamicQuery.PerformActionMethod<MBCategory>() {
369
370 @Override
371 public void performAction(MBCategory category)
372 throws PortalException {
373
374 reindexMessages(
375 companyId, category.getGroupId(),
376 category.getCategoryId());
377 }
378
379 });
380
381 actionableDynamicQuery.performActions();
382 }
383
384 protected void reindexDiscussions(final long companyId)
385 throws PortalException {
386
387 ActionableDynamicQuery actionableDynamicQuery =
388 GroupLocalServiceUtil.getActionableDynamicQuery();
389
390 actionableDynamicQuery.setCompanyId(companyId);
391 actionableDynamicQuery.setPerformActionMethod(
392 new ActionableDynamicQuery.PerformActionMethod<Group>() {
393
394 @Override
395 public void performAction(Group group) throws PortalException {
396 reindexMessages(
397 companyId, group.getGroupId(),
398 MBCategoryConstants.DISCUSSION_CATEGORY_ID);
399 }
400
401 });
402
403 actionableDynamicQuery.performActions();
404 }
405
406 protected void reindexMessages(
407 long companyId, long groupId, final long categoryId)
408 throws PortalException {
409
410 final IndexableActionableDynamicQuery indexableActionableDynamicQuery =
411 MBMessageLocalServiceUtil.getIndexableActionableDynamicQuery();
412
413 indexableActionableDynamicQuery.setAddCriteriaMethod(
414 new ActionableDynamicQuery.AddCriteriaMethod() {
415
416 @Override
417 public void addCriteria(DynamicQuery dynamicQuery) {
418 Property categoryIdProperty = PropertyFactoryUtil.forName(
419 "categoryId");
420
421 dynamicQuery.add(categoryIdProperty.eq(categoryId));
422
423 Property statusProperty = PropertyFactoryUtil.forName(
424 "status");
425
426 Integer[] statuses = {
427 WorkflowConstants.STATUS_APPROVED,
428 WorkflowConstants.STATUS_IN_TRASH
429 };
430
431 dynamicQuery.add(statusProperty.in(statuses));
432 }
433
434 });
435 indexableActionableDynamicQuery.setCompanyId(companyId);
436 indexableActionableDynamicQuery.setGroupId(groupId);
437 indexableActionableDynamicQuery.setPerformActionMethod(
438 new ActionableDynamicQuery.PerformActionMethod<MBMessage>() {
439
440 @Override
441 public void performAction(MBMessage message) {
442 if (message.isDiscussion() && message.isRoot()) {
443 return;
444 }
445
446 try {
447 Document document = getDocument(message);
448
449 indexableActionableDynamicQuery.addDocuments(document);
450 }
451 catch (PortalException pe) {
452 if (_log.isWarnEnabled()) {
453 _log.warn(
454 "Unable to index message boards message " +
455 message.getMessageId(),
456 pe);
457 }
458 }
459 }
460
461 });
462 indexableActionableDynamicQuery.setSearchEngineId(getSearchEngineId());
463
464 indexableActionableDynamicQuery.performActions();
465 }
466
467 protected void reindexRoot(final long companyId) throws PortalException {
468 ActionableDynamicQuery actionableDynamicQuery =
469 GroupLocalServiceUtil.getActionableDynamicQuery();
470
471 actionableDynamicQuery.setCompanyId(companyId);
472 actionableDynamicQuery.setPerformActionMethod(
473 new ActionableDynamicQuery.PerformActionMethod<Group>() {
474
475 @Override
476 public void performAction(Group group) throws PortalException {
477 reindexMessages(
478 companyId, group.getGroupId(),
479 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID);
480 }
481
482 });
483
484 actionableDynamicQuery.performActions();
485 }
486
487 private static final Log _log = LogFactoryUtil.getLog(
488 MBMessageIndexer.class);
489
490 private final RelatedEntryIndexer _relatedEntryIndexer =
491 new BaseRelatedEntryIndexer();
492
493 }