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.journal.util;
16  
17  import com.liferay.portal.kernel.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  import com.liferay.portal.kernel.search.Document;
20  import com.liferay.portal.kernel.search.DocumentImpl;
21  import com.liferay.portal.kernel.search.Field;
22  import com.liferay.portal.kernel.search.Indexer;
23  import com.liferay.portal.kernel.search.SearchContext;
24  import com.liferay.portal.kernel.search.SearchEngineUtil;
25  import com.liferay.portal.kernel.search.Summary;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.HtmlUtil;
28  import com.liferay.portal.kernel.util.StringBundler;
29  import com.liferay.portal.kernel.util.StringPool;
30  import com.liferay.portal.kernel.util.StringUtil;
31  import com.liferay.portal.kernel.util.Validator;
32  import com.liferay.portal.kernel.workflow.StatusConstants;
33  import com.liferay.portal.kernel.xml.Element;
34  import com.liferay.portal.kernel.xml.SAXReaderUtil;
35  import com.liferay.portal.search.BaseIndexer;
36  import com.liferay.portal.util.PortletKeys;
37  import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
38  import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
39  import com.liferay.portlet.expando.model.ExpandoBridge;
40  import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
41  import com.liferay.portlet.journal.model.JournalArticle;
42  import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
43  
44  import java.util.Date;
45  import java.util.LinkedList;
46  import java.util.List;
47  
48  import javax.portlet.PortletURL;
49  
50  /**
51   * <a href="JournalIndexer.java.html"><b><i>View Source</i></b></a>
52   *
53   * @author Brian Wing Shun Chan
54   * @author Harry Mark
55   * @author Bruno Farache
56   * @author Raymond Augé
57   */
58  public class JournalIndexer extends BaseIndexer {
59  
60      public static final String[] CLASS_NAMES = {JournalArticle.class.getName()};
61  
62      public static final String PORTLET_ID = PortletKeys.JOURNAL;
63  
64      public String[] getClassNames() {
65          return CLASS_NAMES;
66      }
67  
68      public Summary getSummary(
69          Document document, String snippet, PortletURL portletURL) {
70  
71          String title = document.get(Field.TITLE);
72  
73          String content = snippet;
74  
75          if (Validator.isNull(snippet)) {
76              content = StringUtil.shorten(document.get(Field.CONTENT), 200);
77          }
78  
79          String groupId = document.get("groupId");
80          String articleId = document.get(Field.ENTRY_CLASS_PK);
81          String version = document.get("version");
82  
83          portletURL.setParameter("struts_action", "/journal/edit_article");
84          portletURL.setParameter("groupId", groupId);
85          portletURL.setParameter("articleId", articleId);
86          portletURL.setParameter("version", version);
87  
88          return new Summary(title, content, portletURL);
89      }
90  
91      protected void doDelete(Object obj) throws Exception {
92          JournalArticle article = (JournalArticle)obj;
93  
94          Document document = new DocumentImpl();
95  
96          document.addUID(
97              PORTLET_ID, article.getGroupId(), article.getArticleId());
98  
99          SearchEngineUtil.deleteDocument(
100             article.getCompanyId(), document.get(Field.UID));
101     }
102 
103     protected Document doGetDocument(Object obj) throws Exception {
104         JournalArticle article = (JournalArticle)obj;
105 
106         long companyId = article.getCompanyId();
107         long groupId = getParentGroupId(article.getGroupId());
108         long scopeGroupId = article.getGroupId();
109         long resourcePrimKey = article.getResourcePrimKey();
110         String articleId = article.getArticleId();
111         double version = article.getVersion();
112         String title = article.getTitle();
113         String description = article.getDescription();
114         String content = article.getContent();
115         String type = article.getType();
116         Date displayDate = article.getDisplayDate();
117 
118         long[] assetCategoryIds = AssetCategoryLocalServiceUtil.getCategoryIds(
119             JournalArticle.class.getName(), resourcePrimKey);
120         String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(
121             JournalArticle.class.getName(), resourcePrimKey);
122 
123         ExpandoBridge expandoBridge = article.getExpandoBridge();
124 
125         Document document = new DocumentImpl();
126 
127         document.addUID(PORTLET_ID, groupId, articleId);
128 
129         document.addModifiedDate(displayDate);
130 
131         document.addKeyword(Field.COMPANY_ID, companyId);
132         document.addKeyword(Field.PORTLET_ID, PORTLET_ID);
133         document.addKeyword(Field.GROUP_ID, groupId);
134         document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);
135 
136         document.addText(Field.TITLE, title);
137         document.addText(Field.CONTENT, processContent(document, content));
138         document.addText(Field.DESCRIPTION, description);
139         document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
140         document.addKeyword(Field.ASSET_TAG_NAMES, assetTagNames);
141 
142         document.addKeyword(
143             Field.ENTRY_CLASS_NAME, JournalArticle.class.getName());
144         document.addKeyword(Field.ENTRY_CLASS_PK, articleId);
145         document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);
146         document.addKeyword(Field.VERSION, version);
147         document.addKeyword(Field.TYPE, type);
148 
149         ExpandoBridgeIndexerUtil.addAttributes(document, expandoBridge);
150 
151         return document;
152     }
153 
154     protected void doReindex(Object obj) throws Exception {
155         JournalArticle article = (JournalArticle)obj;
156 
157         if (!article.isApproved() || !article.isIndexable()) {
158             return;
159         }
160 
161         Document document = getDocument(article);
162 
163         SearchEngineUtil.updateDocument(
164             article.getCompanyId(), document.get(Field.UID), document);
165     }
166 
167     protected void doReindex(String className, long classPK) throws Exception {
168         JournalArticle article =
169             JournalArticleLocalServiceUtil.getLatestArticle(
170                 classPK, StatusConstants.APPROVED);
171 
172         doReindex(article);
173     }
174 
175     protected void doReindex(String[] ids) throws Exception {
176         long companyId = GetterUtil.getLong(ids[0]);
177 
178         reindexArticles(companyId);
179     }
180 
181     protected String getIndexableContent(Document document, Element rootElement)
182         throws Exception {
183 
184         StringBundler sb = new StringBundler();
185 
186         LinkedList<Element> queue = new LinkedList<Element>(
187             rootElement.elements());
188 
189         Element element = null;
190 
191         while ((element = queue.poll()) != null) {
192             String elType = element.attributeValue("type", StringPool.BLANK);
193             String elIndexType = element.attributeValue(
194                 "index-type", StringPool.BLANK);
195 
196             indexField(document, element, elType, elIndexType);
197 
198             if (elType.equals("text") || elType.equals("text_box") ||
199                 elType.equals("text_area")) {
200 
201                 for (Element dynamicContentElement :
202                         element.elements("dynamic-content")) {
203 
204                     String text = dynamicContentElement.getText();
205 
206                     sb.append(text);
207                     sb.append(StringPool.SPACE);
208                 }
209             }
210             else if (element.getName().equals("static-content")) {
211                 String text = element.getText();
212 
213                 sb.append(text);
214                 sb.append(StringPool.SPACE);
215             }
216 
217             queue.addAll(element.elements());
218         }
219 
220         return sb.toString();
221     }
222 
223     protected String getIndexableContent(Document document, String content) {
224         try {
225             com.liferay.portal.kernel.xml.Document contentDocument =
226                 SAXReaderUtil.read(content);
227 
228             Element rootElement = contentDocument.getRootElement();
229 
230             return getIndexableContent(document, rootElement);
231         }
232         catch (Exception e) {
233             _log.error(e, e);
234 
235             return content;
236         }
237     }
238 
239     protected String getPortletId(SearchContext searchContext) {
240         return PORTLET_ID;
241     }
242 
243     protected void indexField(
244         Document document, Element element, String elType, String elIndexType) {
245 
246         if (Validator.isNull(elIndexType)) {
247             return;
248         }
249 
250         Element dynamicContentElement = element.element("dynamic-content");
251 
252         String name = element.attributeValue("name", StringPool.BLANK);
253         String[] value = new String[] {dynamicContentElement.getText()};
254 
255         if (elType.equals("multi-list")) {
256             List<Element> optionElements = dynamicContentElement.elements();
257 
258             value = new String[optionElements.size()];
259 
260             for (int i = 0; i < optionElements.size(); i++) {
261                 value[i] = optionElements.get(i).getText();
262             }
263         }
264 
265         if (elIndexType.equals("keyword")) {
266             document.addKeyword(name, value);
267         }
268         else if (elIndexType.equals("text")) {
269             document.addText(name, StringUtil.merge(value, StringPool.SPACE));
270         }
271     }
272 
273     protected String processContent(Document document, String content) {
274         if ((content != null) &&
275             ((content.indexOf("<dynamic-content") != -1) ||
276              (content.indexOf("<static-content") != -1))) {
277 
278             content = getIndexableContent(document, content);
279 
280             content = StringUtil.replace(
281                 content, "<![CDATA[", StringPool.BLANK);
282             content = StringUtil.replace(content, "]]>", StringPool.BLANK);
283         }
284 
285         content = StringUtil.replace(content, "&amp;", "&");
286         content = StringUtil.replace(content, "&lt;", "<");
287         content = StringUtil.replace(content, "&gt;", ">");
288 
289         content = HtmlUtil.extractText(content);
290 
291         return content;
292     }
293 
294     protected void reindexArticles(long companyId) throws Exception {
295         int count = JournalArticleLocalServiceUtil.getCompanyArticlesCount(
296             companyId, StatusConstants.APPROVED);
297 
298         int pages = count / Indexer.DEFAULT_INTERVAL;
299 
300         for (int i = 0; i <= pages; i++) {
301             int start = (i * Indexer.DEFAULT_INTERVAL);
302             int end = start + Indexer.DEFAULT_INTERVAL;
303 
304             reindexArticles(companyId, start, end);
305         }
306     }
307 
308     protected void reindexArticles(long companyId, int start, int end)
309         throws Exception {
310 
311         List<JournalArticle> articles =
312             JournalArticleLocalServiceUtil.getCompanyArticles(
313                 companyId, StatusConstants.APPROVED, start, end);
314 
315         for (JournalArticle article : articles) {
316             reindex(article);
317         }
318     }
319 
320     private static Log _log = LogFactoryUtil.getLog(JournalIndexer.class);
321 
322 }