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