001
014
015 package com.liferay.portlet.journal.util;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.search.BaseIndexer;
020 import com.liferay.portal.kernel.search.BooleanQuery;
021 import com.liferay.portal.kernel.search.Document;
022 import com.liferay.portal.kernel.search.Field;
023 import com.liferay.portal.kernel.search.Indexer;
024 import com.liferay.portal.kernel.search.SearchContext;
025 import com.liferay.portal.kernel.search.SearchEngineUtil;
026 import com.liferay.portal.kernel.search.Summary;
027 import com.liferay.portal.kernel.util.GetterUtil;
028 import com.liferay.portal.kernel.util.HtmlUtil;
029 import com.liferay.portal.kernel.util.LocaleUtil;
030 import com.liferay.portal.kernel.util.LocalizationUtil;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.kernel.util.StringUtil;
033 import com.liferay.portal.kernel.util.Validator;
034 import com.liferay.portal.kernel.workflow.WorkflowConstants;
035 import com.liferay.portal.kernel.xml.Element;
036 import com.liferay.portal.kernel.xml.Node;
037 import com.liferay.portal.kernel.xml.SAXReaderUtil;
038 import com.liferay.portal.model.Group;
039 import com.liferay.portal.service.GroupLocalServiceUtil;
040 import com.liferay.portal.util.PortletKeys;
041 import com.liferay.portlet.journal.NoSuchStructureException;
042 import com.liferay.portlet.journal.model.JournalArticle;
043 import com.liferay.portlet.journal.model.JournalArticleConstants;
044 import com.liferay.portlet.journal.model.JournalStructure;
045 import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
046 import com.liferay.portlet.journal.service.JournalStructureLocalServiceUtil;
047
048 import java.util.ArrayList;
049 import java.util.Collection;
050 import java.util.LinkedHashMap;
051 import java.util.LinkedList;
052 import java.util.List;
053 import java.util.Locale;
054
055 import javax.portlet.PortletURL;
056
057
064 public class JournalIndexer extends BaseIndexer {
065
066 public static final String[] CLASS_NAMES = {JournalArticle.class.getName()};
067
068 public static final String PORTLET_ID = PortletKeys.JOURNAL;
069
070 public String[] getClassNames() {
071 return CLASS_NAMES;
072 }
073
074 public String getPortletId() {
075 return PORTLET_ID;
076 }
077
078 @Override
079 public boolean isPermissionAware() {
080 return _PERMISSION_AWARE;
081 }
082
083 @Override
084 public void postProcessContextQuery(
085 BooleanQuery contextQuery, SearchContext searchContext)
086 throws Exception {
087
088 Long classNameId = (Long)searchContext.getAttribute(
089 Field.CLASS_NAME_ID);
090
091 if (classNameId != null) {
092 contextQuery.addRequiredTerm("classNameId", classNameId.toString());
093 }
094
095 int status = GetterUtil.getInteger(
096 searchContext.getAttribute(Field.STATUS),
097 WorkflowConstants.STATUS_APPROVED);
098
099 if (status != WorkflowConstants.STATUS_ANY) {
100 contextQuery.addRequiredTerm(Field.STATUS, status);
101 }
102
103 String articleType = (String)searchContext.getAttribute("articleType");
104
105 if (Validator.isNotNull(articleType)) {
106 contextQuery.addRequiredTerm(Field.TYPE, articleType);
107 }
108
109 String structureId = (String)searchContext.getAttribute("structureId");
110
111 if (Validator.isNotNull(structureId)) {
112 contextQuery.addRequiredTerm("structureId", structureId);
113 }
114
115 String templateId = (String)searchContext.getAttribute("templateId");
116
117 if (Validator.isNotNull(templateId)) {
118 contextQuery.addRequiredTerm("templateId", templateId);
119 }
120 }
121
122 @Override
123 public void postProcessSearchQuery(
124 BooleanQuery searchQuery, SearchContext searchContext)
125 throws Exception {
126
127 addSearchTerm(searchQuery, searchContext, Field.CLASS_PK, false);
128 addSearchLocalizedTerm(
129 searchQuery, searchContext, Field.CONTENT, false);
130 addSearchLocalizedTerm(
131 searchQuery, searchContext, Field.DESCRIPTION, false);
132 addSearchTerm(searchQuery, searchContext, Field.ENTRY_CLASS_PK, false);
133 addSearchLocalizedTerm(searchQuery, searchContext, Field.TITLE, false);
134 addSearchTerm(searchQuery, searchContext, Field.TYPE, false);
135 addSearchTerm(searchQuery, searchContext, Field.USER_NAME, false);
136
137 LinkedHashMap<String, Object> params =
138 (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
139
140 if (params != null) {
141 String expandoAttributes = (String)params.get("expandoAttributes");
142
143 if (Validator.isNotNull(expandoAttributes)) {
144 addSearchExpando(searchQuery, searchContext, expandoAttributes);
145 }
146 }
147 }
148
149 @Override
150 protected void doDelete(Object obj) throws Exception {
151 JournalArticle article = (JournalArticle)obj;
152
153 deleteDocument(
154 article.getCompanyId(), article.getGroupId(),
155 article.getArticleId());
156 }
157
158 @Override
159 protected Document doGetDocument(Object obj) throws Exception {
160 JournalArticle article = (JournalArticle)obj;
161
162 Document document = getBaseModelDocument(PORTLET_ID, article);
163
164 document.addUID(
165 PORTLET_ID, article.getGroupId(), article.getArticleId());
166
167 Locale defaultLocale = LocaleUtil.getDefault();
168
169 String defaultLangaugeId = LocaleUtil.toLanguageId(defaultLocale);
170
171 String[] languageIds = getLanguageIds(
172 defaultLangaugeId, article.getContent());
173
174 for (String languageId : languageIds) {
175 String content = extractContent(
176 article.getContentByLocale(languageId));
177
178 if (languageId.equals(defaultLangaugeId)) {
179 document.addText(Field.CONTENT, content);
180 }
181
182 document.addText(
183 Field.CONTENT.concat(StringPool.UNDERLINE).concat(languageId),
184 content);
185 }
186
187 document.addLocalizedText(
188 Field.DESCRIPTION, article.getDescriptionMap());
189 document.addLocalizedText(Field.TITLE, article.getTitleMap());
190 document.addKeyword(Field.TYPE, article.getType());
191 document.addKeyword(Field.VERSION, article.getVersion());
192
193 document.addKeyword("articleId", article.getArticleId());
194 document.addDate("displayDate", article.getDisplayDate());
195 document.addKeyword("layoutUuid", article.getLayoutUuid());
196 document.addKeyword("structureId", article.getStructureId());
197 document.addKeyword("templateId", article.getTemplateId());
198
199 JournalStructure structure = null;
200
201 if (Validator.isNotNull(article.getStructureId())) {
202 try {
203 structure = JournalStructureLocalServiceUtil.getStructure(
204 article.getGroupId(), article.getStructureId());
205 }
206 catch (NoSuchStructureException nsse1) {
207 Group group = GroupLocalServiceUtil.getCompanyGroup(
208 article.getCompanyId());
209
210 try {
211 structure = JournalStructureLocalServiceUtil.getStructure(
212 group.getGroupId(), article.getStructureId());
213 }
214 catch (NoSuchStructureException nsse2) {
215 }
216 }
217 }
218
219 processStructure(structure, document, article.getContent());
220
221 return document;
222 }
223
224 @Override
225 protected String doGetSortField(String orderByCol) {
226 if (orderByCol.equals("display-date")) {
227 return "displayDate";
228 }
229 else if (orderByCol.equals("id")) {
230 return Field.ENTRY_CLASS_PK;
231 }
232 else if (orderByCol.equals("modified-date")) {
233 return Field.MODIFIED_DATE;
234 }
235 else if (orderByCol.equals("title")) {
236 return Field.TITLE;
237 }
238 else {
239 return orderByCol;
240 }
241 }
242
243 @Override
244 protected Summary doGetSummary(
245 Document document, Locale locale, String snippet,
246 PortletURL portletURL) {
247
248 String title = document.get(locale, Field.TITLE);
249
250 String content = snippet;
251
252 if (Validator.isNull(snippet)) {
253 content = StringUtil.shorten(
254 document.get(locale, Field.CONTENT), 200);
255 }
256
257 String groupId = document.get(Field.GROUP_ID);
258 String articleId = document.get("articleId");
259 String version = document.get(Field.VERSION);
260
261 portletURL.setParameter("struts_action", "/journal/edit_article");
262 portletURL.setParameter("groupId", groupId);
263 portletURL.setParameter("articleId", articleId);
264 portletURL.setParameter("version", version);
265
266 return new Summary(title, content, portletURL);
267 }
268
269 @Override
270 protected void doReindex(Object obj) throws Exception {
271 JournalArticle article = (JournalArticle)obj;
272
273 Document document = getDocument(article);
274
275 if (!article.isIndexable() ||
276 (!article.isApproved() &&
277 (article.getVersion() !=
278 JournalArticleConstants.VERSION_DEFAULT))) {
279
280 SearchEngineUtil.deleteDocument(
281 article.getCompanyId(), document.get(Field.UID));
282
283 return;
284 }
285
286 SearchEngineUtil.updateDocument(article.getCompanyId(), document);
287 }
288
289 @Override
290 protected void doReindex(String className, long classPK) throws Exception {
291 JournalArticle article =
292 JournalArticleLocalServiceUtil.getLatestArticle(
293 classPK, WorkflowConstants.STATUS_APPROVED);
294
295 doReindex(article);
296 }
297
298 @Override
299 protected void doReindex(String[] ids) throws Exception {
300 long companyId = GetterUtil.getLong(ids[0]);
301
302 reindexArticles(companyId);
303 }
304
305 protected String encodeFieldName(String name) {
306 return _FIELD_NAMESPACE.concat(StringPool.FORWARD_SLASH).concat(name);
307 }
308
309 protected String extractContent(String content) {
310 content = StringUtil.replace(content, "<![CDATA[", StringPool.BLANK);
311 content = StringUtil.replace(content, "]]>", StringPool.BLANK);
312 content = StringUtil.replace(content, "&", "&");
313 content = StringUtil.replace(content, "<", "<");
314 content = StringUtil.replace(content, ">", ">");
315
316 content = HtmlUtil.extractText(content);
317
318 return content;
319 }
320
321 protected String[] getLanguageIds(
322 String defaultLangaugeId, String content) {
323
324 String[] languageIds = LocalizationUtil.getAvailableLocales(content);
325
326 if (languageIds.length == 0) {
327 languageIds = new String[] {defaultLangaugeId};
328 }
329
330 return languageIds;
331 }
332
333 @Override
334 protected String getPortletId(SearchContext searchContext) {
335 return PORTLET_ID;
336 }
337
338 protected void indexField(
339 Document document, Element element, String elType, String elIndexType) {
340
341 if (Validator.isNull(elIndexType)) {
342 return;
343 }
344
345 com.liferay.portal.kernel.xml.Document structureDocument =
346 element.getDocument();
347
348 Element rootElement = structureDocument.getRootElement();
349
350 String defaultLocale = GetterUtil.getString(
351 rootElement.attributeValue("default-locale"));
352
353 String name = encodeFieldName(element.attributeValue("name"));
354
355 List<Element> dynamicContentElements = element.elements(
356 "dynamic-content");
357
358 for (Element dynamicContentElement : dynamicContentElements) {
359 String contentLocale = GetterUtil.getString(
360 dynamicContentElement.attributeValue("language-id"));
361
362 String[] value = new String[] {dynamicContentElement.getText()};
363
364 if (elType.equals("multi-list")) {
365 List<Element> optionElements = dynamicContentElement.elements(
366 "option");
367
368 value = new String[optionElements.size()];
369
370 for (int i = 0; i < optionElements.size(); i++) {
371 value[i] = optionElements.get(i).getText();
372 }
373 }
374
375 if (elIndexType.equals("keyword")) {
376 if (Validator.isNull(contentLocale)) {
377 document.addKeyword(name, value);
378 }
379 else {
380 if (defaultLocale.equals(contentLocale)) {
381 document.addKeyword(name, value);
382 }
383
384 document.addKeyword(
385 name.concat(StringPool.UNDERLINE).concat(contentLocale),
386 value);
387 }
388 }
389 else if (elIndexType.equals("text")) {
390 if (Validator.isNull(contentLocale)) {
391 document.addText(
392 name, StringUtil.merge(value, StringPool.SPACE));
393 }
394 else {
395 if (defaultLocale.equals(contentLocale)) {
396 document.addText(
397 name, StringUtil.merge(value, StringPool.SPACE));
398 }
399
400 document.addText(
401 name.concat(StringPool.UNDERLINE).concat(contentLocale),
402 StringUtil.merge(value, StringPool.SPACE));
403 }
404 }
405 }
406 }
407
408 protected void processStructure(
409 com.liferay.portal.kernel.xml.Document structureDocument,
410 Document document, Element rootElement)
411 throws Exception {
412
413 LinkedList<Element> queue = new LinkedList<Element>(
414 rootElement.elements());
415
416 Element element = null;
417
418 while ((element = queue.poll()) != null) {
419 String elName = element.attributeValue("name", StringPool.BLANK);
420 String elType = element.attributeValue("type", StringPool.BLANK);
421 String elIndexType = element.attributeValue(
422 "index-type", StringPool.BLANK);
423
424 if (structureDocument != null) {
425 String path = element.getPath().concat(
426 "[@name='").concat(elName).concat("']");
427
428 Node structureNode = structureDocument.selectSingleNode(path);
429
430 if (structureNode != null) {
431 Element structureElement = (Element)structureNode;
432
433 elType = structureElement.attributeValue(
434 "type", StringPool.BLANK);
435 elIndexType = structureElement.attributeValue(
436 "index-type", StringPool.BLANK);
437 }
438 }
439
440 if (Validator.isNotNull(elType)) {
441 indexField(document, element, elType, elIndexType);
442 }
443
444 queue.addAll(element.elements());
445 }
446 }
447
448 protected void processStructure(
449 JournalStructure structure, Document document, String content) {
450
451 try {
452 com.liferay.portal.kernel.xml.Document structureDocument = null;
453
454 if (structure != null) {
455 structureDocument = SAXReaderUtil.read(structure.getXsd());
456 }
457
458 com.liferay.portal.kernel.xml.Document contentDocument =
459 SAXReaderUtil.read(content);
460
461 Element rootElement = contentDocument.getRootElement();
462
463 processStructure(structureDocument, document, rootElement);
464 }
465 catch (Exception e) {
466 _log.error(e, e);
467 }
468 }
469
470 protected void reindexArticles(long companyId) throws Exception {
471 int count = JournalArticleLocalServiceUtil.getCompanyArticlesCount(
472 companyId, WorkflowConstants.STATUS_APPROVED);
473
474 int pages = count / Indexer.DEFAULT_INTERVAL;
475
476 for (int i = 0; i <= pages; i++) {
477 int start = (i * Indexer.DEFAULT_INTERVAL);
478 int end = start + Indexer.DEFAULT_INTERVAL;
479
480 reindexArticles(companyId, start, end);
481 }
482 }
483
484 protected void reindexArticles(long companyId, int start, int end)
485 throws Exception {
486
487 List<JournalArticle> articles = new ArrayList<JournalArticle>();
488
489 List<JournalArticle> approvedArticles =
490 JournalArticleLocalServiceUtil.getCompanyArticles(
491 companyId, WorkflowConstants.STATUS_APPROVED, start, end);
492
493 articles.addAll(approvedArticles);
494
495 List<JournalArticle> draftArticles =
496 JournalArticleLocalServiceUtil.getCompanyArticles(
497 companyId, JournalArticleConstants.VERSION_DEFAULT,
498 WorkflowConstants.STATUS_DRAFT, start, end);
499
500 articles.addAll(draftArticles);
501
502 if (articles.isEmpty()) {
503 return;
504 }
505
506 Collection<Document> documents = new ArrayList<Document>();
507
508 for (JournalArticle article : articles) {
509 if (!article.isIndexable()) {
510 continue;
511 }
512
513 if (article.isApproved()) {
514 JournalArticle latestArticle =
515 JournalArticleLocalServiceUtil.getLatestArticle(
516 article.getResourcePrimKey(),
517 WorkflowConstants.STATUS_APPROVED);
518
519 if (!latestArticle.isIndexable()) {
520 continue;
521 }
522 }
523
524 Document document = getDocument(article);
525
526 documents.add(document);
527 }
528
529 SearchEngineUtil.updateDocuments(companyId, documents);
530 }
531
532 private static final String _FIELD_NAMESPACE = "web_content";
533
534 private static final boolean _PERMISSION_AWARE = true;
535
536 private static Log _log = LogFactoryUtil.getLog(JournalIndexer.class);
537
538 }