1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.messageboards.util;
16  
17  import com.liferay.portal.kernel.dao.orm.QueryUtil;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.search.BooleanQuery;
21  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
22  import com.liferay.portal.kernel.search.Document;
23  import com.liferay.portal.kernel.search.DocumentImpl;
24  import com.liferay.portal.kernel.search.Field;
25  import com.liferay.portal.kernel.search.Hits;
26  import com.liferay.portal.kernel.search.Indexer;
27  import com.liferay.portal.kernel.search.SearchContext;
28  import com.liferay.portal.kernel.search.SearchEngineUtil;
29  import com.liferay.portal.kernel.search.Summary;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.HtmlUtil;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.kernel.workflow.StatusConstants;
35  import com.liferay.portal.model.Group;
36  import com.liferay.portal.search.BaseIndexer;
37  import com.liferay.portal.service.GroupLocalServiceUtil;
38  import com.liferay.portal.util.PortalUtil;
39  import com.liferay.portal.util.PortletKeys;
40  import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
41  import com.liferay.portlet.expando.model.ExpandoBridge;
42  import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
43  import com.liferay.portlet.messageboards.model.MBCategory;
44  import com.liferay.portlet.messageboards.model.MBCategoryConstants;
45  import com.liferay.portlet.messageboards.model.MBMessage;
46  import com.liferay.portlet.messageboards.model.MBThread;
47  import com.liferay.portlet.messageboards.service.MBCategoryLocalServiceUtil;
48  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
49  import com.liferay.portlet.messageboards.service.MBThreadLocalServiceUtil;
50  
51  import java.util.Date;
52  import java.util.List;
53  
54  import javax.portlet.PortletURL;
55  
56  /**
57   * <a href="MBIndexer.java.html"><b><i>View Source</i></b></a>
58   *
59   * @author Brian Wing Shun Chan
60   * @author Harry Mark
61   * @author Bruno Farache
62   * @author Raymond Augé
63   */
64  public class MBIndexer extends BaseIndexer {
65  
66      public static final String[] CLASS_NAMES = {MBMessage.class.getName()};
67  
68      public static final String PORTLET_ID = PortletKeys.MESSAGE_BOARDS;
69  
70      public String[] getClassNames() {
71          return CLASS_NAMES;
72      }
73  
74      public Summary getSummary(
75          Document document, String snippet, PortletURL portletURL) {
76  
77          String title = document.get(Field.TITLE);
78  
79          String content = snippet;
80  
81          if (Validator.isNull(snippet)) {
82              content = StringUtil.shorten(document.get(Field.CONTENT), 200);
83          }
84  
85          String messageId = document.get(Field.ENTRY_CLASS_PK);
86  
87          portletURL.setParameter(
88              "struts_action", "/message_boards/view_message");
89          portletURL.setParameter("messageId", messageId);
90  
91          return new Summary(title, content, portletURL);
92      }
93  
94      protected void doDelete(Object obj) throws Exception {
95          if (obj instanceof MBCategory) {
96              MBCategory category = (MBCategory)obj;
97  
98              BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create();
99  
100             booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
101 
102             booleanQuery.addRequiredTerm(
103                 "categoryId", category.getCategoryId());
104 
105             Hits hits = SearchEngineUtil.search(
106                 category.getCompanyId(), booleanQuery, QueryUtil.ALL_POS,
107                 QueryUtil.ALL_POS);
108 
109             for (int i = 0; i < hits.getLength(); i++) {
110                 Document document = hits.doc(i);
111 
112                 SearchEngineUtil.deleteDocument(
113                     category.getCompanyId(), document.get(Field.UID));
114             }
115         }
116         else if (obj instanceof MBMessage) {
117             MBMessage message = (MBMessage)obj;
118 
119             Document document = new DocumentImpl();
120 
121             document.addUID(PORTLET_ID, message.getMessageId());
122 
123             SearchEngineUtil.deleteDocument(
124                 message.getCompanyId(), document.get(Field.UID));
125         }
126         else if (obj instanceof MBThread) {
127             MBThread thread = (MBThread)obj;
128 
129             MBCategory category = MBCategoryLocalServiceUtil.getCategory(
130                 thread.getCategoryId());
131 
132             BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create();
133 
134             booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
135 
136             booleanQuery.addRequiredTerm("threadId", thread.getThreadId());
137 
138             Hits hits = SearchEngineUtil.search(
139                 category.getCompanyId(), booleanQuery, QueryUtil.ALL_POS,
140                 QueryUtil.ALL_POS);
141 
142             for (int i = 0; i < hits.getLength(); i++) {
143                 Document document = hits.doc(i);
144 
145                 SearchEngineUtil.deleteDocument(
146                     category.getCompanyId(), document.get(Field.UID));
147             }
148         }
149     }
150 
151     protected Document doGetDocument(Object obj) throws Exception {
152         MBMessage message = (MBMessage)obj;
153 
154         long companyId = message.getCompanyId();
155         long groupId = getParentGroupId(message.getGroupId());
156         long scopeGroupId = message.getGroupId();
157         long userId = message.getUserId();
158         String userName = PortalUtil.getUserName(userId, message.getUserName());
159         long categoryId = message.getCategoryId();
160         long threadId = message.getThreadId();
161         long messageId = message.getMessageId();
162         String title = message.getSubject();
163         String content = processContent(messageId, message.getBody());
164         boolean anonymous = message.isAnonymous();
165         Date modifiedDate = message.getModifiedDate();
166 
167         String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(
168             MBMessage.class.getName(), messageId);
169 
170         ExpandoBridge expandoBridge = message.getExpandoBridge();
171 
172         Document document = new DocumentImpl();
173 
174         document.addUID(PORTLET_ID, messageId);
175 
176         document.addModifiedDate(modifiedDate);
177 
178         document.addKeyword(Field.COMPANY_ID, companyId);
179         document.addKeyword(Field.PORTLET_ID, PORTLET_ID);
180         document.addKeyword(Field.GROUP_ID, groupId);
181         document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);
182         document.addKeyword(Field.USER_ID, userId);
183 
184         if (!anonymous) {
185             document.addText(Field.USER_NAME, userName);
186         }
187 
188         document.addText(Field.TITLE, title);
189         document.addText(Field.CONTENT, content);
190         document.addKeyword(Field.ASSET_TAG_NAMES, assetTagNames);
191 
192         document.addKeyword(Field.CATEGORY_ID, categoryId);
193         document.addKeyword("threadId", threadId);
194         document.addKeyword(Field.ENTRY_CLASS_NAME, MBMessage.class.getName());
195         document.addKeyword(Field.ENTRY_CLASS_PK, messageId);
196 
197         try {
198             MBThread thread = MBThreadLocalServiceUtil.getMBThread(threadId);
199 
200             document.addKeyword(
201                 Field.ROOT_ENTRY_CLASS_PK, thread.getRootMessageId());
202         }
203         catch (Exception e) {
204         }
205 
206         ExpandoBridgeIndexerUtil.addAttributes(document, expandoBridge);
207 
208         return document;
209     }
210     protected void doReindex(Object obj) throws Exception {
211         MBMessage message = (MBMessage)obj;
212 
213         if (message.isDiscussion() ||
214             (message.getStatus() != StatusConstants.APPROVED)) {
215 
216             return;
217         }
218 
219         Document document = getDocument(message);
220 
221         SearchEngineUtil.updateDocument(
222             message.getCompanyId(), document.get(Field.UID), document);
223     }
224 
225     protected void doReindex(String className, long classPK) throws Exception {
226         MBMessage message = MBMessageLocalServiceUtil.getMessage(classPK);
227 
228         doReindex(message);
229 
230         if (message.isRoot()) {
231             List<MBMessage> messages =
232                 MBMessageLocalServiceUtil.getThreadMessages(
233                     message.getThreadId(), StatusConstants.APPROVED);
234 
235             for (MBMessage curMessage : messages) {
236                 reindex(curMessage);
237             }
238         }
239         else {
240             reindex(message);
241         }
242     }
243 
244     protected void doReindex(String[] ids) throws Exception {
245         long companyId = GetterUtil.getLong(ids[0]);
246 
247         reindexCategories(companyId);
248         reindexRoot(companyId);
249     }
250 
251     protected String getPortletId(SearchContext searchContext) {
252         return PORTLET_ID;
253     }
254 
255     protected void postProcessContextQuery(
256             BooleanQuery contextQuery, SearchContext searchContext)
257         throws Exception {
258 
259         Long threadId = (Long)searchContext.getAttribute("threadId");
260 
261         if ((threadId != null) && (threadId.longValue() > 0)) {
262             contextQuery.addTerm("threadId", threadId.longValue());
263         }
264     }
265 
266     protected String processContent(long messageId, String content) {
267         try {
268             content = BBCodeUtil.getHTML(content);
269         }
270         catch (Exception e) {
271             _log.error(
272                 "Could not parse message " + messageId + ": " + e.getMessage());
273         }
274 
275         content = HtmlUtil.extractText(content);
276 
277         return content;
278     }
279 
280     protected void reindexCategories(long companyId) throws Exception {
281         int categoryCount =
282             MBCategoryLocalServiceUtil.getCompanyCategoriesCount(companyId);
283 
284         int categoryPages = categoryCount / Indexer.DEFAULT_INTERVAL;
285 
286         for (int i = 0; i <= categoryPages; i++) {
287             int categoryStart = (i * Indexer.DEFAULT_INTERVAL);
288             int categoryEnd = categoryStart + Indexer.DEFAULT_INTERVAL;
289 
290             reindexCategories(companyId, categoryStart, categoryEnd);
291         }
292     }
293 
294     protected void reindexCategories(
295             long companyId, int categoryStart, int categoryEnd)
296         throws Exception {
297 
298         List<MBCategory> categories =
299             MBCategoryLocalServiceUtil.getCompanyCategories(
300                 companyId, categoryStart, categoryEnd);
301 
302         for (MBCategory category : categories) {
303             long groupId = category.getGroupId();
304             long categoryId = category.getCategoryId();
305 
306             int messageCount =
307                 MBMessageLocalServiceUtil.getCategoryMessagesCount(
308                     groupId, categoryId, StatusConstants.APPROVED);
309 
310             int messagePages = messageCount / Indexer.DEFAULT_INTERVAL;
311 
312             for (int i = 0; i <= messagePages; i++) {
313                 int messageStart = (i * Indexer.DEFAULT_INTERVAL);
314                 int messageEnd = messageStart + Indexer.DEFAULT_INTERVAL;
315 
316                 reindexMessages(groupId, categoryId, messageStart, messageEnd);
317             }
318         }
319     }
320 
321     protected void reindexMessages(
322             long groupId, long categoryId, int messageStart, int messageEnd)
323         throws Exception {
324 
325         List<MBMessage> messages =
326             MBMessageLocalServiceUtil.getCategoryMessages(
327                 groupId, categoryId, StatusConstants.APPROVED, messageStart,
328                 messageEnd);
329 
330         for (MBMessage message : messages) {
331             reindex(message);
332         }
333     }
334 
335     protected void reindexRoot(long companyId) throws Exception {
336         int groupCount = GroupLocalServiceUtil.getCompanyGroupsCount(companyId);
337 
338         int groupPages = groupCount / Indexer.DEFAULT_INTERVAL;
339 
340         for (int i = 0; i <= groupPages; i++) {
341             int groupStart = (i * Indexer.DEFAULT_INTERVAL);
342             int groupEnd = groupStart + Indexer.DEFAULT_INTERVAL;
343 
344             reindexRoot(companyId, groupStart, groupEnd);
345         }
346     }
347 
348     protected void reindexRoot(long companyId, int groupStart, int groupEnd)
349         throws Exception {
350 
351         List<Group> groups = GroupLocalServiceUtil.getCompanyGroups(
352             companyId, groupStart, groupEnd);
353 
354         for (Group group : groups) {
355             long groupId = group.getGroupId();
356             long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
357 
358             int entryCount = MBMessageLocalServiceUtil.getCategoryMessagesCount(
359                 groupId, categoryId, StatusConstants.APPROVED);
360 
361             int entryPages = entryCount / Indexer.DEFAULT_INTERVAL;
362 
363             for (int i = 0; i <= entryPages; i++) {
364                 int entryStart = (i * Indexer.DEFAULT_INTERVAL);
365                 int entryEnd = entryStart + Indexer.DEFAULT_INTERVAL;
366 
367                 reindexMessages(groupId, categoryId, entryStart, entryEnd);
368             }
369         }
370     }
371 
372     private static Log _log = LogFactoryUtil.getLog(MBIndexer.class);
373 
374 }