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