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.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.PortletKeys;
046 import com.liferay.portlet.messageboards.NoSuchDiscussionException;
047 import com.liferay.portlet.messageboards.asset.MBMessageAssetRendererFactory;
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.model.MBThread;
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 java.util.ArrayList;
060 import java.util.Collection;
061 import java.util.List;
062 import java.util.Locale;
063
064 import javax.portlet.PortletURL;
065
066
072 public class MBMessageIndexer extends BaseIndexer {
073
074 public static final String[] CLASS_NAMES = {MBMessage.class.getName()};
075
076 public static final String PORTLET_ID = PortletKeys.MESSAGE_BOARDS;
077
078 public MBMessageIndexer() {
079 setFilterSearch(true);
080 setPermissionAware(true);
081 }
082
083 public String[] getClassNames() {
084 return CLASS_NAMES;
085 }
086
087 public String getPortletId() {
088 return PORTLET_ID;
089 }
090
091 @Override
092 public boolean hasPermission(
093 PermissionChecker permissionChecker, String entryClassName,
094 long entryClassPK, String actionId)
095 throws Exception {
096
097 return MBMessagePermission.contains(
098 permissionChecker, entryClassPK, ActionKeys.VIEW);
099 }
100
101 @Override
102 public void postProcessContextQuery(
103 BooleanQuery contextQuery, SearchContext searchContext)
104 throws Exception {
105
106 int status = GetterUtil.getInteger(
107 searchContext.getAttribute(Field.STATUS),
108 WorkflowConstants.STATUS_APPROVED);
109
110 if (status != WorkflowConstants.STATUS_ANY) {
111 contextQuery.addRequiredTerm(Field.STATUS, status);
112 }
113
114 boolean discussion = GetterUtil.getBoolean(
115 searchContext.getAttribute("discussion"), false);
116
117 contextQuery.addRequiredTerm("discussion", discussion);
118
119 long threadId = GetterUtil.getLong(
120 (String)searchContext.getAttribute("threadId"));
121
122 if (threadId > 0) {
123 contextQuery.addRequiredTerm("threadId", threadId);
124 }
125
126 long[] categoryIds = searchContext.getCategoryIds();
127
128 if ((categoryIds != null) && (categoryIds.length > 0)) {
129 if (categoryIds[0] ==
130 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
131
132 return;
133 }
134
135 BooleanQuery categoriesQuery = BooleanQueryFactoryUtil.create(
136 searchContext);
137
138 for (long categoryId : categoryIds) {
139 try {
140 MBCategoryServiceUtil.getCategory(categoryId);
141 }
142 catch (Exception e) {
143 continue;
144 }
145
146 categoriesQuery.addTerm(Field.CATEGORY_ID, categoryId);
147 }
148
149 contextQuery.add(categoriesQuery, BooleanClauseOccur.MUST);
150 }
151 }
152
153 @Override
154 protected void doDelete(Object obj) throws Exception {
155 SearchContext searchContext = new SearchContext();
156
157 searchContext.setSearchEngineId(getSearchEngineId());
158
159 if (obj instanceof MBCategory) {
160 MBCategory category = (MBCategory)obj;
161
162 BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create(
163 searchContext);
164
165 booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
166
167 booleanQuery.addRequiredTerm(
168 "categoryId", category.getCategoryId());
169
170 Hits hits = SearchEngineUtil.search(
171 getSearchEngineId(), category.getCompanyId(), booleanQuery,
172 QueryUtil.ALL_POS, QueryUtil.ALL_POS);
173
174 for (int i = 0; i < hits.getLength(); i++) {
175 Document document = hits.doc(i);
176
177 SearchEngineUtil.deleteDocument(
178 getSearchEngineId(), category.getCompanyId(),
179 document.get(Field.UID));
180 }
181 }
182 else if (obj instanceof MBMessage) {
183 MBMessage message = (MBMessage)obj;
184
185 Document document = new DocumentImpl();
186
187 document.addUID(PORTLET_ID, message.getMessageId());
188
189 SearchEngineUtil.deleteDocument(
190 getSearchEngineId(), message.getCompanyId(),
191 document.get(Field.UID));
192 }
193 else if (obj instanceof MBThread) {
194 MBThread thread = (MBThread)obj;
195
196 MBMessage message = MBMessageLocalServiceUtil.getMessage(
197 thread.getRootMessageId());
198
199 BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create(
200 searchContext);
201
202 booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
203
204 booleanQuery.addRequiredTerm("threadId", thread.getThreadId());
205
206 Hits hits = SearchEngineUtil.search(
207 getSearchEngineId(), message.getCompanyId(), booleanQuery,
208 QueryUtil.ALL_POS, QueryUtil.ALL_POS);
209
210 for (int i = 0; i < hits.getLength(); i++) {
211 Document document = hits.doc(i);
212
213 SearchEngineUtil.deleteDocument(
214 getSearchEngineId(), message.getCompanyId(),
215 document.get(Field.UID));
216 }
217 }
218 }
219
220 @Override
221 protected Document doGetDocument(Object obj) throws Exception {
222 MBMessage message = (MBMessage)obj;
223
224 Document document = getBaseModelDocument(PORTLET_ID, message);
225
226 document.addKeyword(Field.CATEGORY_ID, message.getCategoryId());
227 document.addText(Field.CONTENT, processContent(message));
228 document.addKeyword(
229 Field.ROOT_ENTRY_CLASS_PK, message.getRootMessageId());
230 document.addText(Field.TITLE, message.getSubject());
231
232 if (message.isAnonymous()) {
233 document.remove(Field.USER_NAME);
234 }
235
236 try {
237 MBDiscussionLocalServiceUtil.getThreadDiscussion(
238 message.getThreadId());
239
240 document.addKeyword("discussion", true);
241 }
242 catch (NoSuchDiscussionException nsde) {
243 document.addKeyword("discussion", false);
244 }
245
246 document.addKeyword("threadId", message.getThreadId());
247
248 if (!message.isInTrash() && message.isInTrashThread()) {
249 addTrashFields(
250 document, MBThread.class.getName(), message.getThreadId(), null,
251 null, MBMessageAssetRendererFactory.TYPE);
252
253 String className = MBThread.class.getName();
254 long classPK = message.getThreadId();
255
256 MBThread thread = message.getThread();
257
258 if (thread.isInTrashContainer()) {
259 MBCategory category = thread.getTrashContainer();
260
261 className = MBCategory.class.getName();
262 classPK = category.getCategoryId();
263 }
264
265 document.addKeyword(Field.ROOT_ENTRY_CLASS_NAME, className);
266 document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, classPK);
267
268 document.addKeyword(
269 Field.STATUS, WorkflowConstants.STATUS_IN_TRASH);
270 }
271
272 return document;
273 }
274
275 @Override
276 protected Summary doGetSummary(
277 Document document, Locale locale, String snippet,
278 PortletURL portletURL) {
279
280 String messageId = document.get(Field.ENTRY_CLASS_PK);
281
282 portletURL.setParameter(
283 "struts_action", "/message_boards/view_message");
284 portletURL.setParameter("messageId", messageId);
285
286 Summary summary = createSummary(document, Field.TITLE, Field.CONTENT);
287
288 summary.setMaxContentLength(200);
289 summary.setPortletURL(portletURL);
290
291 return summary;
292 }
293
294 @Override
295 protected void doReindex(Object obj) throws Exception {
296 MBMessage message = (MBMessage)obj;
297
298 if (message.isDiscussion() ||
299 (message.getStatus() != WorkflowConstants.STATUS_APPROVED)) {
300
301 return;
302 }
303
304 Document document = getDocument(message);
305
306 SearchEngineUtil.updateDocument(
307 getSearchEngineId(), message.getCompanyId(), document);
308 }
309
310 @Override
311 protected void doReindex(String className, long classPK) throws Exception {
312 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
313
314 doReindex(message);
315
316 if (message.isRoot()) {
317 List<MBMessage> messages =
318 MBMessageLocalServiceUtil.getThreadMessages(
319 message.getThreadId(), WorkflowConstants.STATUS_APPROVED);
320
321 for (MBMessage curMessage : messages) {
322 reindex(curMessage);
323 }
324 }
325 else {
326 reindex(message);
327 }
328 }
329
330 @Override
331 protected void doReindex(String[] ids) throws Exception {
332 long companyId = GetterUtil.getLong(ids[0]);
333
334 reindexCategories(companyId);
335 reindexRoot(companyId);
336 }
337
338 @Override
339 protected String getPortletId(SearchContext searchContext) {
340 return PORTLET_ID;
341 }
342
343 protected String processContent(MBMessage message) {
344 String content = message.getBody();
345
346 try {
347 if (message.isFormatBBCode()) {
348 content = BBCodeTranslatorUtil.getHTML(content);
349 }
350 }
351 catch (Exception e) {
352 _log.error(
353 "Could not parse message " + message.getMessageId() + ": " +
354 e.getMessage());
355 }
356
357 content = HtmlUtil.extractText(content);
358
359 return content;
360 }
361
362 protected void reindexCategories(final long companyId)
363 throws PortalException, SystemException {
364
365 ActionableDynamicQuery actionableDynamicQuery =
366 new MBCategoryActionableDynamicQuery() {
367
368 @Override
369 protected void performAction(Object object)
370 throws PortalException, SystemException {
371
372 MBCategory category = (MBCategory)object;
373
374 reindexMessages(
375 companyId, category.getGroupId(), category.getCategoryId());
376 }
377
378 };
379
380 actionableDynamicQuery.setCompanyId(companyId);
381
382 actionableDynamicQuery.performActions();
383 }
384
385 protected void reindexMessages(
386 long companyId, long groupId, final long categoryId)
387 throws PortalException, SystemException {
388
389 final Collection<Document> documents = new ArrayList<Document>();
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 dynamicQuery.add(
404 statusProperty.eq(WorkflowConstants.STATUS_APPROVED));
405 }
406
407 @Override
408 protected void performAction(Object object) throws PortalException {
409 MBMessage message = (MBMessage)object;
410
411 Document document = getDocument(message);
412
413 documents.add(document);
414 }
415
416 };
417
418 actionableDynamicQuery.setGroupId(groupId);
419
420 actionableDynamicQuery.performActions();
421
422 SearchEngineUtil.updateDocuments(
423 getSearchEngineId(), companyId, documents);
424 }
425
426 protected void reindexRoot(final long companyId)
427 throws PortalException, SystemException {
428
429 ActionableDynamicQuery actionableDynamicQuery =
430 new GroupActionableDynamicQuery() {
431
432 @Override
433 protected void performAction(Object object)
434 throws PortalException, SystemException {
435
436 Group group = (Group)object;
437
438 reindexMessages(
439 companyId, group.getGroupId(),
440 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID);
441 }
442
443 };
444
445 actionableDynamicQuery.setCompanyId(companyId);
446
447 actionableDynamicQuery.performActions();
448 }
449
450 private static Log _log = LogFactoryUtil.getLog(MBMessageIndexer.class);
451
452 }