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