001
014
015 package com.liferay.portlet.messageboards.util;
016
017 import com.liferay.portal.kernel.dao.orm.QueryUtil;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslatorUtil;
021 import com.liferay.portal.kernel.search.BaseIndexer;
022 import com.liferay.portal.kernel.search.BooleanClauseOccur;
023 import com.liferay.portal.kernel.search.BooleanQuery;
024 import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
025 import com.liferay.portal.kernel.search.Document;
026 import com.liferay.portal.kernel.search.DocumentImpl;
027 import com.liferay.portal.kernel.search.Field;
028 import com.liferay.portal.kernel.search.Hits;
029 import com.liferay.portal.kernel.search.Indexer;
030 import com.liferay.portal.kernel.search.SearchContext;
031 import com.liferay.portal.kernel.search.SearchEngineUtil;
032 import com.liferay.portal.kernel.search.Summary;
033 import com.liferay.portal.kernel.util.GetterUtil;
034 import com.liferay.portal.kernel.util.HtmlUtil;
035 import com.liferay.portal.kernel.util.StringUtil;
036 import com.liferay.portal.kernel.util.Validator;
037 import com.liferay.portal.kernel.workflow.WorkflowConstants;
038 import com.liferay.portal.model.Group;
039 import com.liferay.portal.security.permission.ActionKeys;
040 import com.liferay.portal.security.permission.PermissionChecker;
041 import com.liferay.portal.service.GroupLocalServiceUtil;
042 import com.liferay.portal.util.PortletKeys;
043 import com.liferay.portlet.messageboards.NoSuchDiscussionException;
044 import com.liferay.portlet.messageboards.model.MBCategory;
045 import com.liferay.portlet.messageboards.model.MBCategoryConstants;
046 import com.liferay.portlet.messageboards.model.MBMessage;
047 import com.liferay.portlet.messageboards.model.MBThread;
048 import com.liferay.portlet.messageboards.service.MBCategoryLocalServiceUtil;
049 import com.liferay.portlet.messageboards.service.MBCategoryServiceUtil;
050 import com.liferay.portlet.messageboards.service.MBDiscussionLocalServiceUtil;
051 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
052 import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
053
054 import java.util.ArrayList;
055 import java.util.Collection;
056 import java.util.List;
057 import java.util.Locale;
058
059 import javax.portlet.PortletURL;
060
061
067 public class MBIndexer extends BaseIndexer {
068
069 public static final String[] CLASS_NAMES = {MBMessage.class.getName()};
070
071 public static final String PORTLET_ID = PortletKeys.MESSAGE_BOARDS;
072
073 public String[] getClassNames() {
074 return CLASS_NAMES;
075 }
076
077 public String getPortletId() {
078 return PORTLET_ID;
079 }
080
081 @Override
082 public boolean hasPermission(
083 PermissionChecker permissionChecker, long entryClassPK,
084 String actionId)
085 throws Exception {
086
087 return MBMessagePermission.contains(
088 permissionChecker, entryClassPK, ActionKeys.VIEW);
089 }
090
091 @Override
092 public boolean isFilterSearch() {
093 return _FILTER_SEARCH;
094 }
095
096 @Override
097 public boolean isPermissionAware() {
098 return _PERMISSION_AWARE;
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_ANY);
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(SearchEngineUtil.SYSTEM_ENGINE_ID);
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 category.getCompanyId(), booleanQuery, QueryUtil.ALL_POS,
172 QueryUtil.ALL_POS);
173
174 for (int i = 0; i < hits.getLength(); i++) {
175 Document document = hits.doc(i);
176
177 SearchEngineUtil.deleteDocument(
178 category.getCompanyId(), document.get(Field.UID));
179 }
180 }
181 else if (obj instanceof MBMessage) {
182 MBMessage message = (MBMessage)obj;
183
184 Document document = new DocumentImpl();
185
186 document.addUID(PORTLET_ID, message.getMessageId());
187
188 SearchEngineUtil.deleteDocument(
189 message.getCompanyId(), document.get(Field.UID));
190 }
191 else if (obj instanceof MBThread) {
192 MBThread thread = (MBThread)obj;
193
194 MBMessage message = MBMessageLocalServiceUtil.getMessage(
195 thread.getRootMessageId());
196
197 BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create(
198 searchContext);
199
200 booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
201
202 booleanQuery.addRequiredTerm("threadId", thread.getThreadId());
203
204 Hits hits = SearchEngineUtil.search(
205 message.getCompanyId(), booleanQuery, QueryUtil.ALL_POS,
206 QueryUtil.ALL_POS);
207
208 for (int i = 0; i < hits.getLength(); i++) {
209 Document document = hits.doc(i);
210
211 SearchEngineUtil.deleteDocument(
212 message.getCompanyId(), document.get(Field.UID));
213 }
214 }
215 }
216
217 @Override
218 protected Document doGetDocument(Object obj) throws Exception {
219 MBMessage message = (MBMessage)obj;
220
221 Document document = getBaseModelDocument(PORTLET_ID, message);
222
223 document.addKeyword(Field.CATEGORY_ID, message.getCategoryId());
224 document.addText(Field.CONTENT, processContent(message));
225 document.addKeyword(
226 Field.ROOT_ENTRY_CLASS_PK, message.getRootMessageId());
227 document.addText(Field.TITLE, message.getSubject());
228
229 if (message.isAnonymous()) {
230 document.remove(Field.USER_NAME);
231 }
232
233 try {
234 MBDiscussionLocalServiceUtil.getThreadDiscussion(
235 message.getThreadId());
236
237 document.addKeyword("discussion", true);
238 }
239 catch (NoSuchDiscussionException nsde) {
240 document.addKeyword("discussion", false);
241 }
242
243 document.addKeyword("threadId", message.getThreadId());
244
245 return document;
246 }
247
248 @Override
249 protected Summary doGetSummary(
250 Document document, Locale locale, String snippet,
251 PortletURL portletURL) {
252
253 String title = document.get(Field.TITLE);
254
255 String content = snippet;
256
257 if (Validator.isNull(snippet)) {
258 content = StringUtil.shorten(document.get(Field.CONTENT), 200);
259 }
260
261 String messageId = document.get(Field.ENTRY_CLASS_PK);
262
263 portletURL.setParameter(
264 "struts_action", "/message_boards/view_message");
265 portletURL.setParameter("messageId", messageId);
266
267 return new Summary(title, content, portletURL);
268 }
269
270 @Override
271 protected void doReindex(Object obj) throws Exception {
272 MBMessage message = (MBMessage)obj;
273
274 if (message.isDiscussion() ||
275 (message.getStatus() != WorkflowConstants.STATUS_APPROVED)) {
276
277 return;
278 }
279
280 Document document = getDocument(message);
281
282 SearchEngineUtil.updateDocument(message.getCompanyId(), document);
283 }
284
285 @Override
286 protected void doReindex(String className, long classPK) throws Exception {
287 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
288
289 doReindex(message);
290
291 if (message.isRoot()) {
292 List<MBMessage> messages =
293 MBMessageLocalServiceUtil.getThreadMessages(
294 message.getThreadId(), WorkflowConstants.STATUS_APPROVED);
295
296 for (MBMessage curMessage : messages) {
297 reindex(curMessage);
298 }
299 }
300 else {
301 reindex(message);
302 }
303 }
304
305 @Override
306 protected void doReindex(String[] ids) throws Exception {
307 long companyId = GetterUtil.getLong(ids[0]);
308
309 reindexCategories(companyId);
310 reindexRoot(companyId);
311 }
312
313 @Override
314 protected String getPortletId(SearchContext searchContext) {
315 return PORTLET_ID;
316 }
317
318 protected String processContent(MBMessage message) {
319 String content = message.getBody();
320
321 try {
322 content = BBCodeTranslatorUtil.getHTML(content);
323 }
324 catch (Exception e) {
325 _log.error(
326 "Could not parse message " + message.getMessageId() + ": " +
327 e.getMessage());
328 }
329
330 content = HtmlUtil.extractText(content);
331
332 return content;
333 }
334
335 protected void reindexCategories(long companyId) throws Exception {
336 int categoryCount =
337 MBCategoryLocalServiceUtil.getCompanyCategoriesCount(companyId);
338
339 int categoryPages = categoryCount / Indexer.DEFAULT_INTERVAL;
340
341 for (int i = 0; i <= categoryPages; i++) {
342 int categoryStart = (i * Indexer.DEFAULT_INTERVAL);
343 int categoryEnd = categoryStart + Indexer.DEFAULT_INTERVAL;
344
345 reindexCategories(companyId, categoryStart, categoryEnd);
346 }
347 }
348
349 protected void reindexCategories(
350 long companyId, int categoryStart, int categoryEnd)
351 throws Exception {
352
353 List<MBCategory> categories =
354 MBCategoryLocalServiceUtil.getCompanyCategories(
355 companyId, categoryStart, categoryEnd);
356
357 for (MBCategory category : categories) {
358 long groupId = category.getGroupId();
359 long categoryId = category.getCategoryId();
360
361 int messageCount =
362 MBMessageLocalServiceUtil.getCategoryMessagesCount(
363 groupId, categoryId, WorkflowConstants.STATUS_APPROVED);
364
365 int messagePages = messageCount / Indexer.DEFAULT_INTERVAL;
366
367 for (int i = 0; i <= messagePages; i++) {
368 int messageStart = (i * Indexer.DEFAULT_INTERVAL);
369 int messageEnd = messageStart + Indexer.DEFAULT_INTERVAL;
370
371 reindexMessages(
372 companyId, groupId, categoryId, messageStart, messageEnd);
373 }
374 }
375 }
376
377 protected void reindexMessages(
378 long companyId, long groupId, long categoryId, int messageStart,
379 int messageEnd)
380 throws Exception {
381
382 List<MBMessage> messages =
383 MBMessageLocalServiceUtil.getCategoryMessages(
384 groupId, categoryId, WorkflowConstants.STATUS_APPROVED,
385 messageStart, messageEnd);
386
387 if (messages.isEmpty()) {
388 return;
389 }
390
391 Collection<Document> documents = new ArrayList<Document>();
392
393 for (MBMessage message : messages) {
394 Document document = getDocument(message);
395
396 documents.add(document);
397 }
398
399 SearchEngineUtil.updateDocuments(companyId, documents);
400 }
401
402 protected void reindexRoot(long companyId) throws Exception {
403 int groupCount = GroupLocalServiceUtil.getCompanyGroupsCount(companyId);
404
405 int groupPages = groupCount / Indexer.DEFAULT_INTERVAL;
406
407 for (int i = 0; i <= groupPages; i++) {
408 int groupStart = (i * Indexer.DEFAULT_INTERVAL);
409 int groupEnd = groupStart + Indexer.DEFAULT_INTERVAL;
410
411 reindexRoot(companyId, groupStart, groupEnd);
412 }
413 }
414
415 protected void reindexRoot(long companyId, int groupStart, int groupEnd)
416 throws Exception {
417
418 List<Group> groups = GroupLocalServiceUtil.getCompanyGroups(
419 companyId, groupStart, groupEnd);
420
421 for (Group group : groups) {
422 long groupId = group.getGroupId();
423 long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
424
425 int entryCount = MBMessageLocalServiceUtil.getCategoryMessagesCount(
426 groupId, categoryId, WorkflowConstants.STATUS_APPROVED);
427
428 int entryPages = entryCount / Indexer.DEFAULT_INTERVAL;
429
430 for (int i = 0; i <= entryPages; i++) {
431 int entryStart = (i * Indexer.DEFAULT_INTERVAL);
432 int entryEnd = entryStart + Indexer.DEFAULT_INTERVAL;
433
434 reindexMessages(
435 companyId, groupId, categoryId, entryStart, entryEnd);
436 }
437 }
438 }
439
440 private static final boolean _FILTER_SEARCH = true;
441
442 private static final boolean _PERMISSION_AWARE = true;
443
444 private static Log _log = LogFactoryUtil.getLog(MBIndexer.class);
445
446 }