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 return;
301 }
302
303 if (mbMessage.isDiscussion() && mbMessage.isRoot()) {
304 return;
305 }
306
307 Document document = getDocument(mbMessage);
308
309 SearchEngineUtil.updateDocument(
310 getSearchEngineId(), mbMessage.getCompanyId(), document,
311 isCommitImmediately());
312 }
313
314 @Override
315 protected void doReindex(String className, long classPK) throws Exception {
316 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
317
318 doReindex(message);
319
320 if (message.isRoot()) {
321 List<MBMessage> messages =
322 MBMessageLocalServiceUtil.getThreadMessages(
323 message.getThreadId(), WorkflowConstants.STATUS_APPROVED);
324
325 for (MBMessage curMessage : messages) {
326 reindex(curMessage);
327 }
328 }
329 else {
330 reindex(message);
331 }
332 }
333
334 @Override
335 protected void doReindex(String[] ids) throws Exception {
336 long companyId = GetterUtil.getLong(ids[0]);
337
338 reindexCategories(companyId);
339 reindexDiscussions(companyId);
340 reindexRoot(companyId);
341 }
342
343 protected String processContent(MBMessage message) {
344 String content = message.getBody();
345
346 try {
347 if (message.isFormatBBCode()) {
348 content = BBCodeTranslatorUtil.getHTML(content);
349 }
350 }
351 catch (Exception e) {
352 _log.error(
353 "Could not parse message " + message.getMessageId() + ": " +
354 e.getMessage());
355 }
356
357 content = HtmlUtil.extractText(content);
358
359 return content;
360 }
361
362 protected void reindexCategories(final long companyId)
363 throws PortalException {
364
365 ActionableDynamicQuery actionableDynamicQuery =
366 MBCategoryLocalServiceUtil.getActionableDynamicQuery();
367
368 actionableDynamicQuery.setCompanyId(companyId);
369 actionableDynamicQuery.setPerformActionMethod(
370 new ActionableDynamicQuery.PerformActionMethod<MBCategory>() {
371
372 @Override
373 public void performAction(MBCategory category)
374 throws PortalException {
375
376 reindexMessages(
377 companyId, category.getGroupId(),
378 category.getCategoryId());
379 }
380
381 });
382
383 actionableDynamicQuery.performActions();
384 }
385
386 protected void reindexDiscussions(final long companyId)
387 throws PortalException {
388
389 ActionableDynamicQuery actionableDynamicQuery =
390 GroupLocalServiceUtil.getActionableDynamicQuery();
391
392 actionableDynamicQuery.setCompanyId(companyId);
393 actionableDynamicQuery.setPerformActionMethod(
394 new ActionableDynamicQuery.PerformActionMethod<Group>() {
395
396 @Override
397 public void performAction(Group group) throws PortalException {
398 reindexMessages(
399 companyId, group.getGroupId(),
400 MBCategoryConstants.DISCUSSION_CATEGORY_ID);
401 }
402
403 });
404
405 actionableDynamicQuery.performActions();
406 }
407
408 protected void reindexMessages(
409 long companyId, long groupId, final long categoryId)
410 throws PortalException {
411
412 final IndexableActionableDynamicQuery indexableActionableDynamicQuery =
413 MBMessageLocalServiceUtil.getIndexableActionableDynamicQuery();
414
415 indexableActionableDynamicQuery.setAddCriteriaMethod(
416 new ActionableDynamicQuery.AddCriteriaMethod() {
417
418 @Override
419 public void addCriteria(DynamicQuery dynamicQuery) {
420 Property categoryIdProperty = PropertyFactoryUtil.forName(
421 "categoryId");
422
423 dynamicQuery.add(categoryIdProperty.eq(categoryId));
424
425 Property statusProperty = PropertyFactoryUtil.forName(
426 "status");
427
428 Integer[] statuses = {
429 WorkflowConstants.STATUS_APPROVED,
430 WorkflowConstants.STATUS_IN_TRASH
431 };
432
433 dynamicQuery.add(statusProperty.in(statuses));
434 }
435
436 });
437 indexableActionableDynamicQuery.setCompanyId(companyId);
438 indexableActionableDynamicQuery.setGroupId(groupId);
439 indexableActionableDynamicQuery.setPerformActionMethod(
440 new ActionableDynamicQuery.PerformActionMethod<MBMessage>() {
441
442 @Override
443 public void performAction(MBMessage message) {
444 if (message.isDiscussion() && message.isRoot()) {
445 return;
446 }
447
448 try {
449 Document document = getDocument(message);
450
451 indexableActionableDynamicQuery.addDocuments(document);
452 }
453 catch (PortalException pe) {
454 if (_log.isWarnEnabled()) {
455 _log.warn(
456 "Unable to index message boards message " +
457 message.getMessageId(),
458 pe);
459 }
460 }
461 }
462
463 });
464 indexableActionableDynamicQuery.setSearchEngineId(getSearchEngineId());
465
466 indexableActionableDynamicQuery.performActions();
467 }
468
469 protected void reindexRoot(final long companyId) throws PortalException {
470 ActionableDynamicQuery actionableDynamicQuery =
471 GroupLocalServiceUtil.getActionableDynamicQuery();
472
473 actionableDynamicQuery.setCompanyId(companyId);
474 actionableDynamicQuery.setPerformActionMethod(
475 new ActionableDynamicQuery.PerformActionMethod<Group>() {
476
477 @Override
478 public void performAction(Group group) throws PortalException {
479 reindexMessages(
480 companyId, group.getGroupId(),
481 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID);
482 }
483
484 });
485
486 actionableDynamicQuery.performActions();
487 }
488
489 private static final Log _log = LogFactoryUtil.getLog(
490 MBMessageIndexer.class);
491
492 private final RelatedEntryIndexer _relatedEntryIndexer =
493 new BaseRelatedEntryIndexer();
494
495 }