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