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