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