001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.journal.util;
016    
017    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.search.BaseIndexer;
023    import com.liferay.portal.kernel.search.BooleanClauseOccur;
024    import com.liferay.portal.kernel.search.BooleanQuery;
025    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
026    import com.liferay.portal.kernel.search.Document;
027    import com.liferay.portal.kernel.search.DocumentImpl;
028    import com.liferay.portal.kernel.search.Field;
029    import com.liferay.portal.kernel.search.SearchContext;
030    import com.liferay.portal.kernel.search.SearchEngineUtil;
031    import com.liferay.portal.kernel.search.Summary;
032    import com.liferay.portal.kernel.util.CharPool;
033    import com.liferay.portal.kernel.util.Constants;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.HtmlUtil;
036    import com.liferay.portal.kernel.util.LocaleUtil;
037    import com.liferay.portal.kernel.util.LocalizationUtil;
038    import com.liferay.portal.kernel.util.StringPool;
039    import com.liferay.portal.kernel.util.StringUtil;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.kernel.workflow.WorkflowConstants;
042    import com.liferay.portal.security.permission.ActionKeys;
043    import com.liferay.portal.security.permission.PermissionChecker;
044    import com.liferay.portal.util.PortalUtil;
045    import com.liferay.portal.util.PortletKeys;
046    import com.liferay.portal.util.PropsUtil;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.portlet.dynamicdatamapping.StructureFieldException;
049    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
050    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
051    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
052    import com.liferay.portlet.dynamicdatamapping.util.DDMIndexer;
053    import com.liferay.portlet.dynamicdatamapping.util.DDMIndexerUtil;
054    import com.liferay.portlet.dynamicdatamapping.util.DDMUtil;
055    import com.liferay.portlet.journal.model.JournalArticle;
056    import com.liferay.portlet.journal.model.JournalArticleDisplay;
057    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
058    import com.liferay.portlet.journal.service.permission.JournalArticlePermission;
059    import com.liferay.portlet.journal.service.persistence.JournalArticleActionableDynamicQuery;
060    import com.liferay.portlet.trash.util.TrashUtil;
061    
062    import java.io.Serializable;
063    
064    import java.util.ArrayList;
065    import java.util.Collection;
066    import java.util.LinkedHashMap;
067    import java.util.List;
068    import java.util.Locale;
069    
070    import javax.portlet.PortletURL;
071    
072    /**
073     * @author Brian Wing Shun Chan
074     * @author Harry Mark
075     * @author Bruno Farache
076     * @author Raymond Aug??
077     * @author Hugo Huijser
078     * @author Tibor Lipusz
079     */
080    public class JournalArticleIndexer extends BaseIndexer {
081    
082            public static final String[] CLASS_NAMES = {JournalArticle.class.getName()};
083    
084            public static boolean JOURNAL_ARTICLE_INDEX_ALL_VERSIONS =
085                    GetterUtil.getBoolean(
086                            PropsUtil.get("journal.articles.index.all.versions"));
087    
088            public static final String PORTLET_ID = PortletKeys.JOURNAL;
089    
090            public JournalArticleIndexer() {
091                    setFilterSearch(true);
092                    setPermissionAware(true);
093            }
094    
095            @Override
096            public String[] getClassNames() {
097                    return CLASS_NAMES;
098            }
099    
100            @Override
101            public String getPortletId() {
102                    return PORTLET_ID;
103            }
104    
105            @Override
106            public boolean hasPermission(
107                            PermissionChecker permissionChecker, String entryClassName,
108                            long entryClassPK, String actionId)
109                    throws Exception {
110    
111                    return JournalArticlePermission.contains(
112                            permissionChecker, entryClassPK, ActionKeys.VIEW);
113            }
114    
115            @Override
116            public boolean isVisible(long classPK, int status) throws Exception {
117                    List<JournalArticle> articles =
118                            JournalArticleLocalServiceUtil.getArticlesByResourcePrimKey(
119                                    classPK);
120    
121                    for (JournalArticle article : articles) {
122                            if (isVisible(article.getStatus(), status)) {
123                                    return true;
124                            }
125                    }
126    
127                    return false;
128            }
129    
130            @Override
131            public void postProcessContextQuery(
132                            BooleanQuery contextQuery, SearchContext searchContext)
133                    throws Exception {
134    
135                    Long classNameId = (Long)searchContext.getAttribute(
136                            Field.CLASS_NAME_ID);
137    
138                    if ((classNameId != null) && (classNameId.longValue() != 0)) {
139                            contextQuery.addRequiredTerm("classNameId", classNameId.toString());
140                    }
141    
142                    addStatus(contextQuery, searchContext);
143    
144                    addSearchClassTypeIds(contextQuery, searchContext);
145    
146                    String ddmStructureFieldName = (String)searchContext.getAttribute(
147                            "ddmStructureFieldName");
148                    Serializable ddmStructureFieldValue = searchContext.getAttribute(
149                            "ddmStructureFieldValue");
150    
151                    if (Validator.isNotNull(ddmStructureFieldName) &&
152                            Validator.isNotNull(ddmStructureFieldValue)) {
153    
154                            String[] ddmStructureFieldNameParts = StringUtil.split(
155                                    ddmStructureFieldName, DDMIndexer.DDM_FIELD_SEPARATOR);
156    
157                            DDMStructure structure = DDMStructureLocalServiceUtil.getStructure(
158                                    GetterUtil.getLong(ddmStructureFieldNameParts[1]));
159    
160                            String fieldName = StringUtil.replaceLast(
161                                    ddmStructureFieldNameParts[2],
162                                    StringPool.UNDERLINE.concat(
163                                            LocaleUtil.toLanguageId(searchContext.getLocale())),
164                                    StringPool.BLANK);
165    
166                            try {
167                                    ddmStructureFieldValue = DDMUtil.getIndexedFieldValue(
168                                            ddmStructureFieldValue, structure.getFieldType(fieldName));
169                            }
170                            catch (StructureFieldException sfe) {
171                            }
172    
173                            contextQuery.addRequiredTerm(
174                                    ddmStructureFieldName,
175                                    StringPool.QUOTE + ddmStructureFieldValue + StringPool.QUOTE);
176                    }
177    
178                    String articleType = (String)searchContext.getAttribute("articleType");
179    
180                    if (Validator.isNotNull(articleType)) {
181                            contextQuery.addRequiredTerm(Field.TYPE, articleType);
182                    }
183    
184                    String ddmStructureKey = (String)searchContext.getAttribute(
185                            "ddmStructureKey");
186    
187                    if (Validator.isNotNull(ddmStructureKey)) {
188                            contextQuery.addRequiredTerm("ddmStructureKey", ddmStructureKey);
189                    }
190    
191                    String ddmTemplateKey = (String)searchContext.getAttribute(
192                            "ddmTemplateKey");
193    
194                    if (Validator.isNotNull(ddmTemplateKey)) {
195                            contextQuery.addRequiredTerm("ddmTemplateKey", ddmTemplateKey);
196                    }
197            }
198    
199            @Override
200            public void postProcessSearchQuery(
201                            BooleanQuery searchQuery, SearchContext searchContext)
202                    throws Exception {
203    
204                    addSearchTerm(searchQuery, searchContext, Field.CLASS_PK, false);
205                    addSearchLocalizedTerm(
206                            searchQuery, searchContext, Field.CONTENT, false);
207                    addSearchLocalizedTerm(
208                            searchQuery, searchContext, Field.DESCRIPTION, false);
209                    addSearchTerm(searchQuery, searchContext, Field.ENTRY_CLASS_PK, false);
210                    addSearchLocalizedTerm(searchQuery, searchContext, Field.TITLE, false);
211                    addSearchTerm(searchQuery, searchContext, Field.TYPE, false);
212                    addSearchTerm(searchQuery, searchContext, Field.USER_NAME, false);
213    
214                    addSearchTerm(searchQuery, searchContext, "articleId", false);
215    
216                    LinkedHashMap<String, Object> params =
217                            (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
218    
219                    if (params != null) {
220                            String expandoAttributes = (String)params.get("expandoAttributes");
221    
222                            if (Validator.isNotNull(expandoAttributes)) {
223                                    addSearchExpando(searchQuery, searchContext, expandoAttributes);
224                            }
225                    }
226            }
227    
228            protected void addDDMStructureAttributes(
229                            Document document, JournalArticle article)
230                    throws Exception {
231    
232                    if (Validator.isNull(article.getStructureId())) {
233                            return;
234                    }
235    
236                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.fetchStructure(
237                            article.getGroupId(),
238                            PortalUtil.getClassNameId(JournalArticle.class),
239                            article.getStructureId(), true);
240    
241                    if (ddmStructure == null) {
242                            return;
243                    }
244    
245                    document.addKeyword(Field.CLASS_TYPE_ID, ddmStructure.getStructureId());
246    
247                    Fields fields = null;
248    
249                    try {
250                            fields = JournalConverterUtil.getDDMFields(
251                                    ddmStructure, article.getContent());
252                    }
253                    catch (Exception e) {
254                            return;
255                    }
256    
257                    if (fields != null) {
258                            DDMIndexerUtil.addAttributes(document, ddmStructure, fields);
259                    }
260            }
261    
262            @Override
263            protected void addSearchLocalizedTerm(
264                            BooleanQuery searchQuery, SearchContext searchContext, String field,
265                            boolean like)
266                    throws Exception {
267    
268                    if (Validator.isNull(field)) {
269                            return;
270                    }
271    
272                    String value = String.valueOf(searchContext.getAttribute(field));
273    
274                    if (Validator.isNull(value)) {
275                            value = searchContext.getKeywords();
276                    }
277    
278                    if (Validator.isNull(value)) {
279                            return;
280                    }
281    
282                    String localizedField = DocumentImpl.getLocalizedName(
283                            searchContext.getLocale(), field);
284    
285                    if (Validator.isNull(searchContext.getKeywords())) {
286                            BooleanQuery localizedQuery = BooleanQueryFactoryUtil.create(
287                                    searchContext);
288    
289                            localizedQuery.addTerm(field, value, like);
290                            localizedQuery.addTerm(localizedField, value, like);
291    
292                            BooleanClauseOccur booleanClauseOccur = BooleanClauseOccur.SHOULD;
293    
294                            if (searchContext.isAndSearch()) {
295                                    booleanClauseOccur = BooleanClauseOccur.MUST;
296                            }
297    
298                            searchQuery.add(localizedQuery, booleanClauseOccur);
299                    }
300                    else {
301                            searchQuery.addTerm(localizedField, value, like);
302                    }
303            }
304    
305            @Override
306            protected void addStatus(
307                            BooleanQuery contextQuery, SearchContext searchContext)
308                    throws Exception {
309    
310                    LinkedHashMap<String, Object> params =
311                            (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
312    
313                    boolean showNonindexable = false;
314    
315                    if (params != null) {
316                            showNonindexable = GetterUtil.getBoolean(
317                                    params.get("showNonindexable"));
318                    }
319    
320                    super.addStatus(contextQuery, searchContext);
321    
322                    boolean head = GetterUtil.getBoolean(
323                            searchContext.getAttribute("head"), Boolean.TRUE);
324                    boolean relatedClassName = GetterUtil.getBoolean(
325                            searchContext.getAttribute("relatedClassName"));
326    
327                    if (head && !relatedClassName && !showNonindexable) {
328                            contextQuery.addRequiredTerm("head", Boolean.TRUE);
329                    }
330    
331                    if (!relatedClassName && showNonindexable) {
332                            contextQuery.addRequiredTerm("headListable", Boolean.TRUE);
333                    }
334            }
335    
336            @Override
337            protected void doDelete(Object obj) throws Exception {
338                    JournalArticle article = (JournalArticle)obj;
339    
340                    long classPK = article.getId();
341    
342                    if (!PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
343                            if (JournalArticleLocalServiceUtil.getArticlesCount(
344                                            article.getGroupId(), article.getArticleId()) > 0) {
345    
346                                    doReindex(obj);
347    
348                                    return;
349                            }
350                            else {
351                                    classPK = article.getResourcePrimKey();
352                            }
353                    }
354    
355                    deleteDocument(article.getCompanyId(), classPK);
356    
357                    if (!article.isApproved()) {
358                            return;
359                    }
360    
361                    JournalArticle latestIndexableArticle =
362                            JournalArticleLocalServiceUtil.fetchLatestIndexableArticle(
363                                    article.getResourcePrimKey());
364    
365                    if ((latestIndexableArticle == null) ||
366                            (PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS &&
367                            (latestIndexableArticle.getVersion() > article.getVersion()))) {
368    
369                            return;
370                    }
371    
372                    SearchEngineUtil.updateDocument(
373                            getSearchEngineId(), article.getCompanyId(),
374                            getDocument(latestIndexableArticle), isCommitImmediately());
375            }
376    
377            @Override
378            protected Document doGetDocument(Object obj) throws Exception {
379                    JournalArticle article = (JournalArticle)obj;
380    
381                    Document document = getBaseModelDocument(PORTLET_ID, article);
382    
383                    long classPK = article.getId();
384    
385                    if (!PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
386                            classPK = article.getResourcePrimKey();
387                    }
388    
389                    document.addUID(PORTLET_ID, classPK);
390    
391                    String articleDefaultLanguageId = LocalizationUtil.getDefaultLanguageId(
392                            article.getContent());
393    
394                    Locale defaultLocale = LocaleUtil.getSiteDefault();
395    
396                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
397    
398                    String[] languageIds = getLanguageIds(
399                            defaultLanguageId, article.getContent());
400    
401                    for (String languageId : languageIds) {
402                            String content = extractContent(article, languageId);
403    
404                            String description = article.getDescription(languageId);
405    
406                            String title = article.getTitle(languageId);
407    
408                            if (languageId.equals(articleDefaultLanguageId)) {
409                                    document.addText(Field.CONTENT, content);
410                                    document.addText(Field.DESCRIPTION, description);
411                                    document.addText(Field.TITLE, title);
412                                    document.addText("defaultLanguageId", languageId);
413                            }
414    
415                            document.addText(
416                                    Field.CONTENT.concat(StringPool.UNDERLINE).concat(languageId),
417                                    content);
418                            document.addText(
419                                    Field.DESCRIPTION.concat(StringPool.UNDERLINE).concat(
420                                            languageId), description);
421                            document.addText(
422                                    Field.TITLE.concat(StringPool.UNDERLINE).concat(languageId),
423                                    title);
424                    }
425    
426                    document.addKeyword(Field.FOLDER_ID, article.getFolderId());
427                    document.addKeyword(Field.LAYOUT_UUID, article.getLayoutUuid());
428                    document.addKeyword(
429                            Field.TREE_PATH,
430                            StringUtil.split(article.getTreePath(), CharPool.SLASH));
431                    document.addKeyword(Field.TYPE, article.getType());
432                    document.addKeyword(Field.VERSION, article.getVersion());
433    
434                    String articleId = article.getArticleId();
435    
436                    if (article.isInTrash()) {
437                            articleId = TrashUtil.getOriginalTitle(articleId);
438                    }
439    
440                    document.addKeyword("articleId", articleId);
441                    document.addKeyword("ddmStructureKey", article.getStructureId());
442                    document.addKeyword("ddmTemplateKey", article.getTemplateId());
443                    document.addDate("displayDate", article.getDisplayDate());
444    
445                    addDDMStructureAttributes(document, article);
446    
447                    boolean head = isHead(article);
448                    boolean headListable = isHeadListable(article);
449    
450                    document.addKeyword("head", head);
451                    document.addKeyword("headListable", headListable);
452    
453                    return document;
454            }
455    
456            @Override
457            protected String doGetSortField(String orderByCol) {
458                    if (orderByCol.equals("display-date")) {
459                            return "displayDate";
460                    }
461                    else if (orderByCol.equals("id")) {
462                            return Field.ENTRY_CLASS_PK;
463                    }
464                    else if (orderByCol.equals("modified-date")) {
465                            return Field.MODIFIED_DATE;
466                    }
467                    else if (orderByCol.equals("title")) {
468                            return Field.TITLE;
469                    }
470                    else {
471                            return orderByCol;
472                    }
473            }
474    
475            @Override
476            protected Summary doGetSummary(
477                    Document document, Locale locale, String snippet,
478                    PortletURL portletURL) {
479    
480                    Locale snippetLocale = getSnippetLocale(document, locale);
481    
482                    String localizedTitleName = DocumentImpl.getLocalizedName(
483                            locale, Field.TITLE);
484    
485                    if ((snippetLocale == null) ||
486                            (document.getField(localizedTitleName) == null)) {
487    
488                            snippetLocale = LocaleUtil.fromLanguageId(
489                                    document.get("defaultLanguageId"));
490                    }
491    
492                    String title = document.get(
493                            snippetLocale, Field.SNIPPET + StringPool.UNDERLINE + Field.TITLE,
494                            Field.TITLE);
495    
496                    String content = StringPool.BLANK;
497    
498                    String ddmStructureKey = document.get("ddmStructureKey");
499    
500                    if (Validator.isNotNull(ddmStructureKey)) {
501                            content = getDDMContentSummary(document, snippetLocale);
502                    }
503                    else {
504                            content = getBasicContentSummary(document, snippetLocale);
505                    }
506    
507                    String groupId = document.get(Field.GROUP_ID);
508                    String articleId = document.get("articleId");
509                    String version = document.get(Field.VERSION);
510    
511                    portletURL.setParameter("struts_action", "/journal/edit_article");
512                    portletURL.setParameter("groupId", groupId);
513                    portletURL.setParameter("articleId", articleId);
514                    portletURL.setParameter("version", version);
515    
516                    return new Summary(snippetLocale, title, content, portletURL);
517            }
518    
519            public void doReindex(JournalArticle article, boolean allVersions)
520                    throws Exception {
521    
522                    if (PortalUtil.getClassNameId(DDMStructure.class) ==
523                                    article.getClassNameId()) {
524    
525                            Document document = getDocument(article);
526    
527                            SearchEngineUtil.deleteDocument(
528                                    getSearchEngineId(), article.getCompanyId(),
529                                    document.get(Field.UID), isCommitImmediately());
530    
531                            return;
532                    }
533    
534                    if (allVersions || !PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
535                            reindexArticleVersions(article);
536                    }
537                    else {
538                            SearchEngineUtil.updateDocument(
539                                    getSearchEngineId(), article.getCompanyId(),
540                                    getDocument(article), isCommitImmediately());
541                    }
542            }
543    
544            @Override
545            protected void doReindex(Object obj) throws Exception {
546                    JournalArticle article = (JournalArticle)obj;
547    
548                    doReindex(article, true);
549            }
550    
551            @Override
552            protected void doReindex(String className, long classPK) throws Exception {
553                    JournalArticle article =
554                            JournalArticleLocalServiceUtil.fetchJournalArticle(classPK);
555    
556                    if (article == null) {
557                            article = JournalArticleLocalServiceUtil.fetchLatestArticle(
558                                    classPK);
559                    }
560    
561                    if (article != null) {
562                            doReindex(article);
563                    }
564            }
565    
566            @Override
567            protected void doReindex(String[] ids) throws Exception {
568                    long companyId = GetterUtil.getLong(ids[0]);
569    
570                    reindexArticles(companyId);
571            }
572    
573            @Override
574            protected void doReindexDDMStructures(List<Long> ddmStructureIds)
575                    throws Exception {
576    
577                    String[] ddmStructureKeys = new String[ddmStructureIds.size()];
578    
579                    for (int i = 0; i < ddmStructureIds.size(); i++) {
580                            long structureId = ddmStructureIds.get(i);
581    
582                            DDMStructure ddmStructure =
583                                    DDMStructureLocalServiceUtil.getDDMStructure(structureId);
584    
585                            ddmStructureKeys[i] = ddmStructure.getStructureKey();
586                    }
587    
588                    List<JournalArticle> articles =
589                            JournalArticleLocalServiceUtil.
590                                    getIndexableArticlesByDDMStructureKey(ddmStructureKeys);
591    
592                    for (JournalArticle article : articles) {
593                            doReindex(article, false);
594                    }
595            }
596    
597            protected String extractBasicContent(
598                    JournalArticle article, String languageId) {
599    
600                    String content = article.getContentByLocale(languageId);
601    
602                    content = StringUtil.replace(content, "<![CDATA[", StringPool.BLANK);
603                    content = StringUtil.replace(content, "]]>", StringPool.BLANK);
604                    content = StringUtil.replace(content, "&amp;", "&");
605                    content = StringUtil.replace(content, "&lt;", "<");
606                    content = StringUtil.replace(content, "&gt;", ">");
607    
608                    content = HtmlUtil.extractText(content);
609    
610                    return content;
611            }
612    
613            protected String extractContent(JournalArticle article, String languageId)
614                    throws Exception {
615    
616                    if (Validator.isNotNull(article.getStructureId())) {
617                            return extractDDMContent(article, languageId);
618                    }
619    
620                    return extractBasicContent(article, languageId);
621            }
622    
623            protected String extractDDMContent(
624                            JournalArticle article, String languageId)
625                    throws Exception {
626    
627                    if (Validator.isNull(article.getStructureId())) {
628                            return StringPool.BLANK;
629                    }
630    
631                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.fetchStructure(
632                            article.getGroupId(),
633                            PortalUtil.getClassNameId(JournalArticle.class),
634                            article.getStructureId(), true);
635    
636                    if (ddmStructure == null) {
637                            return StringPool.BLANK;
638                    }
639    
640                    Fields fields = null;
641    
642                    try {
643                            fields = JournalConverterUtil.getDDMFields(
644                                    ddmStructure, article.getContent());
645                    }
646                    catch (Exception e) {
647                            return StringPool.BLANK;
648                    }
649    
650                    if (fields == null) {
651                            return StringPool.BLANK;
652                    }
653    
654                    return DDMIndexerUtil.extractAttributes(
655                            ddmStructure, fields, LocaleUtil.fromLanguageId(languageId));
656            }
657    
658            protected JournalArticle fetchLatestIndexableArticleVersion(
659                            long resourcePrimKey)
660                    throws SystemException {
661    
662                    JournalArticle latestIndexableArticle =
663                            JournalArticleLocalServiceUtil.fetchLatestArticle(
664                                    resourcePrimKey,
665                                    new int[] {
666                                            WorkflowConstants.STATUS_APPROVED,
667                                            WorkflowConstants.STATUS_IN_TRASH
668                                    });
669    
670                    if (latestIndexableArticle == null) {
671                            latestIndexableArticle =
672                                    JournalArticleLocalServiceUtil.fetchLatestArticle(
673                                            resourcePrimKey);
674                    }
675    
676                    return latestIndexableArticle;
677            }
678    
679            protected Collection<Document> getArticleVersions(JournalArticle article)
680                    throws PortalException, SystemException {
681    
682                    Collection<Document> documents = new ArrayList<Document>();
683    
684                    List<JournalArticle> articles = null;
685    
686                    if (PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
687                            articles =
688                                    JournalArticleLocalServiceUtil.getArticlesByResourcePrimKey(
689                                            article.getResourcePrimKey());
690                    }
691                    else {
692                            articles = new ArrayList<JournalArticle>();
693    
694                            JournalArticle latestIndexableArticle =
695                                    fetchLatestIndexableArticleVersion(
696                                            article.getResourcePrimKey());
697    
698                            if (latestIndexableArticle != null) {
699                                    articles.add(latestIndexableArticle);
700                            }
701                    }
702    
703                    for (JournalArticle curArticle : articles) {
704                            Document document = getDocument(curArticle);
705    
706                            documents.add(document);
707                    }
708    
709                    return documents;
710            }
711    
712            protected String getBasicContentSummary(
713                    Document document, Locale snippetLocale) {
714    
715                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
716    
717                    String content = document.get(
718                            snippetLocale, prefix + Field.DESCRIPTION, prefix + Field.CONTENT);
719    
720                    if (Validator.isBlank(content)) {
721                            content = document.get(
722                                    snippetLocale, Field.DESCRIPTION, Field.CONTENT);
723                    }
724    
725                    if (content.length() > 200) {
726                            content = StringUtil.shorten(content, 200);
727                    }
728    
729                    return content;
730            }
731    
732            protected String getDDMContentSummary(
733                    Document document, Locale snippetLocale) {
734    
735                    String content = StringPool.BLANK;
736    
737                    try {
738                            long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID));
739                            String articleId = document.get("articleId");
740                            double version = GetterUtil.getDouble(document.get(Field.VERSION));
741    
742                            JournalArticle article =
743                                    JournalArticleLocalServiceUtil.fetchArticle(
744                                            groupId, articleId, version);
745    
746                            if (article == null) {
747                                    return content;
748                            }
749    
750                            JournalArticleDisplay articleDisplay =
751                                    JournalArticleLocalServiceUtil.getArticleDisplay(
752                                            article, null, Constants.VIEW,
753                                            LocaleUtil.toLanguageId(snippetLocale), 1, null, null);
754    
755                            content = HtmlUtil.escape(articleDisplay.getDescription());
756                            content = HtmlUtil.replaceNewLine(content);
757    
758                            if (Validator.isNull(content)) {
759                                    content = HtmlUtil.extractText(articleDisplay.getContent());
760                            }
761                    }
762                    catch (Exception e) {
763                            if (_log.isDebugEnabled()) {
764                                    _log.debug(e, e);
765                            }
766                    }
767    
768                    return content;
769            }
770    
771            protected String[] getLanguageIds(
772                    String defaultLanguageId, String content) {
773    
774                    String[] languageIds = LocalizationUtil.getAvailableLanguageIds(
775                            content);
776    
777                    if (languageIds.length == 0) {
778                            languageIds = new String[] {defaultLanguageId};
779                    }
780    
781                    return languageIds;
782            }
783    
784            @Override
785            protected String getPortletId(SearchContext searchContext) {
786                    return PORTLET_ID;
787            }
788    
789            protected boolean isHead(JournalArticle article) throws SystemException {
790                    JournalArticle latestArticle =
791                            JournalArticleLocalServiceUtil.fetchLatestArticle(
792                                    article.getResourcePrimKey(),
793                                    new int[] {
794                                            WorkflowConstants.STATUS_APPROVED,
795                                            WorkflowConstants.STATUS_IN_TRASH
796                                    });
797    
798                    if ((latestArticle != null) && !latestArticle.isIndexable()) {
799                            return false;
800                    }
801                    else if ((latestArticle != null) &&
802                                     (article.getId() == latestArticle.getId())) {
803    
804                            return true;
805                    }
806    
807                    return false;
808            }
809    
810            protected boolean isHeadListable(JournalArticle article)
811                    throws SystemException {
812    
813                    JournalArticle latestArticle =
814                            JournalArticleLocalServiceUtil.fetchLatestArticle(
815                                    article.getResourcePrimKey(),
816                                    new int[] {
817                                            WorkflowConstants.STATUS_APPROVED,
818                                            WorkflowConstants.STATUS_IN_TRASH,
819                                            WorkflowConstants.STATUS_SCHEDULED
820                                    });
821    
822                    if ((latestArticle != null) &&
823                            (article.getId() == latestArticle.getId())) {
824    
825                            return true;
826                    }
827    
828                    return false;
829            }
830    
831            protected void reindexArticles(long companyId)
832                    throws PortalException, SystemException {
833    
834                    ActionableDynamicQuery actionableDynamicQuery =
835                            new JournalArticleActionableDynamicQuery() {
836    
837                            @Override
838                            protected void performAction(Object object)
839                                    throws PortalException, SystemException {
840    
841                                    JournalArticle article = (JournalArticle)object;
842    
843                                    if (!PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
844                                            JournalArticle latestIndexableArticle =
845                                                    fetchLatestIndexableArticleVersion(
846                                                            article.getResourcePrimKey());
847    
848                                            if (latestIndexableArticle == null) {
849                                                    return;
850                                            }
851    
852                                            article = latestIndexableArticle;
853                                    }
854    
855                                    Document document = getDocument(article);
856    
857                                    addDocument(document);
858                            }
859    
860                    };
861    
862                    actionableDynamicQuery.setCompanyId(companyId);
863                    actionableDynamicQuery.setSearchEngineId(getSearchEngineId());
864    
865                    actionableDynamicQuery.performActions();
866            }
867    
868            protected void reindexArticleVersions(JournalArticle article)
869                    throws PortalException, SystemException {
870    
871                    SearchEngineUtil.updateDocuments(
872                            getSearchEngineId(), article.getCompanyId(),
873                            getArticleVersions(article), isCommitImmediately());
874            }
875    
876            private static Log _log = LogFactoryUtil.getLog(
877                    JournalArticleIndexer.class);
878    
879    }