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