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 void postProcessContextQuery(
098 BooleanQuery contextQuery, SearchContext searchContext)
099 throws Exception {
100
101 int status = GetterUtil.getInteger(
102 searchContext.getAttribute(Field.STATUS),
103 WorkflowConstants.STATUS_ANY);
104
105 if (status != WorkflowConstants.STATUS_ANY) {
106 contextQuery.addRequiredTerm(Field.STATUS, status);
107 }
108
109 boolean discussion = GetterUtil.getBoolean(
110 searchContext.getAttribute("discussion"), false);
111
112 contextQuery.addRequiredTerm("discussion", discussion);
113
114 long threadId = GetterUtil.getLong(
115 (String)searchContext.getAttribute("threadId"));
116
117 if (threadId > 0) {
118 contextQuery.addRequiredTerm("threadId", threadId);
119 }
120
121 long[] categoryIds = searchContext.getCategoryIds();
122
123 if ((categoryIds != null) && (categoryIds.length > 0)) {
124 if (categoryIds[0] ==
125 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
126
127 return;
128 }
129
130 BooleanQuery categoriesQuery = BooleanQueryFactoryUtil.create(
131 searchContext);
132
133 for (long categoryId : categoryIds) {
134 try {
135 MBCategoryServiceUtil.getCategory(categoryId);
136 }
137 catch (Exception e) {
138 continue;
139 }
140
141 categoriesQuery.addTerm(Field.CATEGORY_ID, categoryId);
142 }
143
144 contextQuery.add(categoriesQuery, BooleanClauseOccur.MUST);
145 }
146 }
147
148 @Override
149 protected void doDelete(Object obj) throws Exception {
150 SearchContext searchContext = new SearchContext();
151
152 searchContext.setSearchEngineId(SearchEngineUtil.SYSTEM_ENGINE_ID);
153
154 if (obj instanceof MBCategory) {
155 MBCategory category = (MBCategory)obj;
156
157 BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create(
158 searchContext);
159
160 booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
161
162 booleanQuery.addRequiredTerm(
163 "categoryId", category.getCategoryId());
164
165 Hits hits = SearchEngineUtil.search(
166 category.getCompanyId(), booleanQuery, QueryUtil.ALL_POS,
167 QueryUtil.ALL_POS);
168
169 for (int i = 0; i < hits.getLength(); i++) {
170 Document document = hits.doc(i);
171
172 SearchEngineUtil.deleteDocument(
173 category.getCompanyId(), document.get(Field.UID));
174 }
175 }
176 else if (obj instanceof MBMessage) {
177 MBMessage message = (MBMessage)obj;
178
179 Document document = new DocumentImpl();
180
181 document.addUID(PORTLET_ID, message.getMessageId());
182
183 SearchEngineUtil.deleteDocument(
184 message.getCompanyId(), document.get(Field.UID));
185 }
186 else if (obj instanceof MBThread) {
187 MBThread thread = (MBThread)obj;
188
189 MBMessage message = MBMessageLocalServiceUtil.getMessage(
190 thread.getRootMessageId());
191
192 BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create(
193 searchContext);
194
195 booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
196
197 booleanQuery.addRequiredTerm("threadId", thread.getThreadId());
198
199 Hits hits = SearchEngineUtil.search(
200 message.getCompanyId(), booleanQuery, QueryUtil.ALL_POS,
201 QueryUtil.ALL_POS);
202
203 for (int i = 0; i < hits.getLength(); i++) {
204 Document document = hits.doc(i);
205
206 SearchEngineUtil.deleteDocument(
207 message.getCompanyId(), document.get(Field.UID));
208 }
209 }
210 }
211
212 @Override
213 protected Document doGetDocument(Object obj) throws Exception {
214 MBMessage message = (MBMessage)obj;
215
216 Document document = getBaseModelDocument(PORTLET_ID, message);
217
218 document.addKeyword(Field.CATEGORY_ID, message.getCategoryId());
219 document.addText(Field.CONTENT, processContent(message));
220 document.addKeyword(
221 Field.ROOT_ENTRY_CLASS_PK, message.getRootMessageId());
222 document.addText(Field.TITLE, message.getSubject());
223
224 if (message.isAnonymous()) {
225 document.remove(Field.USER_NAME);
226 }
227
228 try {
229 MBDiscussionLocalServiceUtil.getThreadDiscussion(
230 message.getThreadId());
231
232 document.addKeyword("discussion", true);
233 }
234 catch (NoSuchDiscussionException nsde) {
235 document.addKeyword("discussion", false);
236 }
237
238 document.addKeyword("threadId", message.getThreadId());
239
240 return document;
241 }
242
243 @Override
244 protected Summary doGetSummary(
245 Document document, Locale locale, String snippet,
246 PortletURL portletURL) {
247
248 String title = document.get(Field.TITLE);
249
250 String content = snippet;
251
252 if (Validator.isNull(snippet)) {
253 content = StringUtil.shorten(document.get(Field.CONTENT), 200);
254 }
255
256 String messageId = document.get(Field.ENTRY_CLASS_PK);
257
258 portletURL.setParameter(
259 "struts_action", "/message_boards/view_message");
260 portletURL.setParameter("messageId", messageId);
261
262 return new Summary(title, content, portletURL);
263 }
264
265 @Override
266 protected void doReindex(Object obj) throws Exception {
267 MBMessage message = (MBMessage)obj;
268
269 if (message.isDiscussion() ||
270 (message.getStatus() != WorkflowConstants.STATUS_APPROVED)) {
271
272 return;
273 }
274
275 Document document = getDocument(message);
276
277 SearchEngineUtil.updateDocument(message.getCompanyId(), document);
278 }
279
280 @Override
281 protected void doReindex(String className, long classPK) throws Exception {
282 MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
283
284 doReindex(message);
285
286 if (message.isRoot()) {
287 List<MBMessage> messages =
288 MBMessageLocalServiceUtil.getThreadMessages(
289 message.getThreadId(), WorkflowConstants.STATUS_APPROVED);
290
291 for (MBMessage curMessage : messages) {
292 reindex(curMessage);
293 }
294 }
295 else {
296 reindex(message);
297 }
298 }
299
300 @Override
301 protected void doReindex(String[] ids) throws Exception {
302 long companyId = GetterUtil.getLong(ids[0]);
303
304 reindexCategories(companyId);
305 reindexRoot(companyId);
306 }
307
308 @Override
309 protected String getPortletId(SearchContext searchContext) {
310 return PORTLET_ID;
311 }
312
313 protected String processContent(MBMessage message) {
314 String content = message.getBody();
315
316 try {
317 content = BBCodeTranslatorUtil.getHTML(content);
318 }
319 catch (Exception e) {
320 _log.error(
321 "Could not parse message " + message.getMessageId() + ": " +
322 e.getMessage());
323 }
324
325 content = HtmlUtil.extractText(content);
326
327 return content;
328 }
329
330 protected void reindexCategories(long companyId) throws Exception {
331 int categoryCount =
332 MBCategoryLocalServiceUtil.getCompanyCategoriesCount(companyId);
333
334 int categoryPages = categoryCount / Indexer.DEFAULT_INTERVAL;
335
336 for (int i = 0; i <= categoryPages; i++) {
337 int categoryStart = (i * Indexer.DEFAULT_INTERVAL);
338 int categoryEnd = categoryStart + Indexer.DEFAULT_INTERVAL;
339
340 reindexCategories(companyId, categoryStart, categoryEnd);
341 }
342 }
343
344 protected void reindexCategories(
345 long companyId, int categoryStart, int categoryEnd)
346 throws Exception {
347
348 List<MBCategory> categories =
349 MBCategoryLocalServiceUtil.getCompanyCategories(
350 companyId, categoryStart, categoryEnd);
351
352 for (MBCategory category : categories) {
353 long groupId = category.getGroupId();
354 long categoryId = category.getCategoryId();
355
356 int messageCount =
357 MBMessageLocalServiceUtil.getCategoryMessagesCount(
358 groupId, categoryId, WorkflowConstants.STATUS_APPROVED);
359
360 int messagePages = messageCount / Indexer.DEFAULT_INTERVAL;
361
362 for (int i = 0; i <= messagePages; i++) {
363 int messageStart = (i * Indexer.DEFAULT_INTERVAL);
364 int messageEnd = messageStart + Indexer.DEFAULT_INTERVAL;
365
366 reindexMessages(
367 companyId, groupId, categoryId, messageStart, messageEnd);
368 }
369 }
370 }
371
372 protected void reindexMessages(
373 long companyId, long groupId, long categoryId, int messageStart,
374 int messageEnd)
375 throws Exception {
376
377 List<MBMessage> messages =
378 MBMessageLocalServiceUtil.getCategoryMessages(
379 groupId, categoryId, WorkflowConstants.STATUS_APPROVED,
380 messageStart, messageEnd);
381
382 if (messages.isEmpty()) {
383 return;
384 }
385
386 Collection<Document> documents = new ArrayList<Document>();
387
388 for (MBMessage message : messages) {
389 Document document = getDocument(message);
390
391 documents.add(document);
392 }
393
394 SearchEngineUtil.updateDocuments(companyId, documents);
395 }
396
397 protected void reindexRoot(long companyId) throws Exception {
398 int groupCount = GroupLocalServiceUtil.getCompanyGroupsCount(companyId);
399
400 int groupPages = groupCount / Indexer.DEFAULT_INTERVAL;
401
402 for (int i = 0; i <= groupPages; i++) {
403 int groupStart = (i * Indexer.DEFAULT_INTERVAL);
404 int groupEnd = groupStart + Indexer.DEFAULT_INTERVAL;
405
406 reindexRoot(companyId, groupStart, groupEnd);
407 }
408 }
409
410 protected void reindexRoot(long companyId, int groupStart, int groupEnd)
411 throws Exception {
412
413 List<Group> groups = GroupLocalServiceUtil.getCompanyGroups(
414 companyId, groupStart, groupEnd);
415
416 for (Group group : groups) {
417 long groupId = group.getGroupId();
418 long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
419
420 int entryCount = MBMessageLocalServiceUtil.getCategoryMessagesCount(
421 groupId, categoryId, WorkflowConstants.STATUS_APPROVED);
422
423 int entryPages = entryCount / Indexer.DEFAULT_INTERVAL;
424
425 for (int i = 0; i <= entryPages; i++) {
426 int entryStart = (i * Indexer.DEFAULT_INTERVAL);
427 int entryEnd = entryStart + Indexer.DEFAULT_INTERVAL;
428
429 reindexMessages(
430 companyId, groupId, categoryId, entryStart, entryEnd);
431 }
432 }
433 }
434
435 private static final boolean _FILTER_SEARCH = true;
436
437 private static Log _log = LogFactoryUtil.getLog(MBIndexer.class);
438
439 }