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