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.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 includeScheduledArticles = false;
314    
315                    if (params != null) {
316                            includeScheduledArticles = GetterUtil.getBoolean(
317                                    params.get("includeScheduledArticles"));
318                    }
319    
320                    if (includeScheduledArticles) {
321                            BooleanQuery statusQuery = BooleanQueryFactoryUtil.create(
322                                    searchContext);
323    
324                            BooleanQuery statusHeadQuery = BooleanQueryFactoryUtil.create(
325                                    searchContext);
326    
327                            statusHeadQuery.addRequiredTerm("head", Boolean.TRUE);
328                            statusHeadQuery.addRequiredTerm(
329                                    Field.STATUS, WorkflowConstants.STATUS_APPROVED);
330    
331                            statusQuery.add(statusHeadQuery, BooleanClauseOccur.SHOULD);
332    
333                            BooleanQuery statusScheduledHeadQuery =
334                                    BooleanQueryFactoryUtil.create(searchContext);
335    
336                            statusScheduledHeadQuery.addRequiredTerm(
337                                    "scheduledHead", Boolean.TRUE);
338                            statusScheduledHeadQuery.addRequiredTerm(
339                                    Field.STATUS, WorkflowConstants.STATUS_SCHEDULED);
340    
341                            statusQuery.add(
342                                    statusScheduledHeadQuery, BooleanClauseOccur.SHOULD);
343    
344                            contextQuery.add(statusQuery, BooleanClauseOccur.MUST);
345                    }
346                    else {
347                            super.addStatus(contextQuery, searchContext);
348    
349                            boolean head = GetterUtil.getBoolean(
350                                    searchContext.getAttribute("head"), Boolean.TRUE);
351                            boolean relatedClassName = GetterUtil.getBoolean(
352                                    searchContext.getAttribute("relatedClassName"));
353    
354                            if (head && !relatedClassName) {
355                                    contextQuery.addRequiredTerm("head", Boolean.TRUE);
356                            }
357                    }
358            }
359    
360            protected void addStatusHeads(Document document, JournalArticle article)
361                    throws SystemException {
362    
363                    boolean head = false;
364                    boolean scheduledHead = false;
365    
366                    int[] statuses = new int[] {
367                            WorkflowConstants.STATUS_APPROVED, WorkflowConstants.STATUS_IN_TRASH
368                    };
369    
370                    JournalArticle latestArticle =
371                            JournalArticleLocalServiceUtil.fetchLatestArticle(
372                                    article.getResourcePrimKey(), statuses);
373    
374                    if (latestArticle == null) {
375                            statuses = new int[] {WorkflowConstants.STATUS_SCHEDULED};
376    
377                            latestArticle = JournalArticleLocalServiceUtil.fetchLatestArticle(
378                                    article.getResourcePrimKey(), statuses);
379                    }
380    
381                    if ((latestArticle != null) && latestArticle.isIndexable() &&
382                            (article.getId() == latestArticle.getId())) {
383    
384                            if (latestArticle.getStatus() ==
385                                            WorkflowConstants.STATUS_SCHEDULED) {
386    
387                                    scheduledHead = true;
388                            }
389                            else {
390                                    head = true;
391                            }
392                    }
393    
394                    document.addKeyword("head", head);
395                    document.addKeyword("scheduledHead", scheduledHead);
396            }
397    
398            @Override
399            protected void doDelete(Object obj) throws Exception {
400                    JournalArticle article = (JournalArticle)obj;
401    
402                    long classPK = article.getId();
403    
404                    if (!PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
405                            if (JournalArticleLocalServiceUtil.getArticlesCount(
406                                            article.getGroupId(), article.getArticleId()) > 0) {
407    
408                                    doReindex(obj);
409    
410                                    return;
411                            }
412                            else {
413                                    classPK = article.getResourcePrimKey();
414                            }
415                    }
416    
417                    deleteDocument(article.getCompanyId(), classPK);
418    
419                    if (!article.isApproved()) {
420                            return;
421                    }
422    
423                    JournalArticle latestIndexableArticle =
424                            JournalArticleLocalServiceUtil.fetchLatestIndexableArticle(
425                                    article.getResourcePrimKey());
426    
427                    if ((latestIndexableArticle == null) ||
428                            (PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS &&
429                            (latestIndexableArticle.getVersion() > article.getVersion()))) {
430    
431                            return;
432                    }
433    
434                    SearchEngineUtil.updateDocument(
435                            getSearchEngineId(), article.getCompanyId(),
436                            getDocument(latestIndexableArticle), isCommitImmediately());
437            }
438    
439            @Override
440            protected Document doGetDocument(Object obj) throws Exception {
441                    JournalArticle article = (JournalArticle)obj;
442    
443                    Document document = getBaseModelDocument(PORTLET_ID, article);
444    
445                    long classPK = article.getId();
446    
447                    if (!PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
448                            classPK = article.getResourcePrimKey();
449                    }
450    
451                    document.addUID(PORTLET_ID, classPK);
452    
453                    String articleDefaultLanguageId = LocalizationUtil.getDefaultLanguageId(
454                            article.getContent());
455    
456                    Locale defaultLocale = LocaleUtil.getSiteDefault();
457    
458                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
459    
460                    String[] languageIds = getLanguageIds(
461                            defaultLanguageId, article.getContent());
462    
463                    for (String languageId : languageIds) {
464                            String content = extractContent(article, languageId);
465    
466                            String description = article.getDescription(languageId);
467    
468                            String title = article.getTitle(languageId);
469    
470                            if (languageId.equals(articleDefaultLanguageId)) {
471                                    document.addText(Field.CONTENT, content);
472                                    document.addText(Field.DESCRIPTION, description);
473                                    document.addText(Field.TITLE, title);
474                                    document.addText("defaultLanguageId", languageId);
475                            }
476    
477                            document.addText(
478                                    Field.CONTENT.concat(StringPool.UNDERLINE).concat(languageId),
479                                    content);
480                            document.addText(
481                                    Field.DESCRIPTION.concat(StringPool.UNDERLINE).concat(
482                                            languageId), description);
483                            document.addText(
484                                    Field.TITLE.concat(StringPool.UNDERLINE).concat(languageId),
485                                    title);
486                    }
487    
488                    document.addKeyword(Field.FOLDER_ID, article.getFolderId());
489                    document.addKeyword(Field.LAYOUT_UUID, article.getLayoutUuid());
490                    document.addKeyword(
491                            Field.TREE_PATH,
492                            StringUtil.split(article.getTreePath(), CharPool.SLASH));
493                    document.addKeyword(Field.TYPE, article.getType());
494                    document.addKeyword(Field.VERSION, article.getVersion());
495    
496                    String articleId = article.getArticleId();
497    
498                    if (article.isInTrash()) {
499                            articleId = TrashUtil.getOriginalTitle(articleId);
500                    }
501    
502                    document.addKeyword("articleId", articleId);
503                    document.addKeyword("ddmStructureKey", article.getStructureId());
504                    document.addKeyword("ddmTemplateKey", article.getTemplateId());
505                    document.addDate("displayDate", article.getDisplayDate());
506    
507                    addDDMStructureAttributes(document, article);
508    
509                    addStatusHeads(document, article);
510    
511                    return document;
512            }
513    
514            @Override
515            protected String doGetSortField(String orderByCol) {
516                    if (orderByCol.equals("display-date")) {
517                            return "displayDate";
518                    }
519                    else if (orderByCol.equals("id")) {
520                            return Field.ENTRY_CLASS_PK;
521                    }
522                    else if (orderByCol.equals("modified-date")) {
523                            return Field.MODIFIED_DATE;
524                    }
525                    else if (orderByCol.equals("title")) {
526                            return Field.TITLE;
527                    }
528                    else {
529                            return orderByCol;
530                    }
531            }
532    
533            @Override
534            protected Summary doGetSummary(
535                    Document document, Locale locale, String snippet,
536                    PortletURL portletURL) {
537    
538                    Locale snippetLocale = getSnippetLocale(document, locale);
539    
540                    String localizedTitleName = DocumentImpl.getLocalizedName(
541                            locale, Field.TITLE);
542    
543                    if ((snippetLocale == null) ||
544                            (document.getField(localizedTitleName) == null)) {
545    
546                            snippetLocale = LocaleUtil.fromLanguageId(
547                                    document.get("defaultLanguageId"));
548                    }
549    
550                    String title = document.get(
551                            snippetLocale, Field.SNIPPET + StringPool.UNDERLINE + Field.TITLE,
552                            Field.TITLE);
553    
554                    String content = StringPool.BLANK;
555    
556                    String ddmStructureKey = document.get("ddmStructureKey");
557    
558                    if (Validator.isNotNull(ddmStructureKey)) {
559                            content = getDDMContentSummary(document, snippetLocale);
560                    }
561                    else {
562                            content = getBasicContentSummary(document, snippetLocale);
563                    }
564    
565                    String groupId = document.get(Field.GROUP_ID);
566                    String articleId = document.get("articleId");
567                    String version = document.get(Field.VERSION);
568    
569                    portletURL.setParameter("struts_action", "/journal/edit_article");
570                    portletURL.setParameter("groupId", groupId);
571                    portletURL.setParameter("articleId", articleId);
572                    portletURL.setParameter("version", version);
573    
574                    return new Summary(snippetLocale, title, content, portletURL);
575            }
576    
577            public void doReindex(JournalArticle article, boolean allVersions)
578                    throws Exception {
579    
580                    if (PortalUtil.getClassNameId(DDMStructure.class) ==
581                                    article.getClassNameId()) {
582    
583                            Document document = getDocument(article);
584    
585                            SearchEngineUtil.deleteDocument(
586                                    getSearchEngineId(), article.getCompanyId(),
587                                    document.get(Field.UID), isCommitImmediately());
588    
589                            return;
590                    }
591    
592                    if (allVersions || !PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
593                            reindexArticleVersions(article);
594                    }
595                    else {
596                            SearchEngineUtil.updateDocument(
597                                    getSearchEngineId(), article.getCompanyId(),
598                                    getDocument(article), isCommitImmediately());
599                    }
600            }
601    
602            @Override
603            protected void doReindex(Object obj) throws Exception {
604                    JournalArticle article = (JournalArticle)obj;
605    
606                    doReindex(article, true);
607            }
608    
609            @Override
610            protected void doReindex(String className, long classPK) throws Exception {
611                    JournalArticle article =
612                            JournalArticleLocalServiceUtil.fetchJournalArticle(classPK);
613    
614                    if (article == null) {
615                            article = JournalArticleLocalServiceUtil.fetchLatestArticle(
616                                    classPK);
617                    }
618    
619                    if (article != null) {
620                            doReindex(article);
621                    }
622            }
623    
624            @Override
625            protected void doReindex(String[] ids) throws Exception {
626                    long companyId = GetterUtil.getLong(ids[0]);
627    
628                    reindexArticles(companyId);
629            }
630    
631            @Override
632            protected void doReindexDDMStructures(List<Long> ddmStructureIds)
633                    throws Exception {
634    
635                    String[] ddmStructureKeys = new String[ddmStructureIds.size()];
636    
637                    for (int i = 0; i < ddmStructureIds.size(); i++) {
638                            long structureId = ddmStructureIds.get(i);
639    
640                            DDMStructure ddmStructure =
641                                    DDMStructureLocalServiceUtil.getDDMStructure(structureId);
642    
643                            ddmStructureKeys[i] = ddmStructure.getStructureKey();
644                    }
645    
646                    List<JournalArticle> articles =
647                            JournalArticleLocalServiceUtil.
648                                    getIndexableArticlesByDDMStructureKey(ddmStructureKeys);
649    
650                    for (JournalArticle article : articles) {
651                            doReindex(article, false);
652                    }
653            }
654    
655            protected String extractBasicContent(
656                    JournalArticle article, String languageId) {
657    
658                    String content = article.getContentByLocale(languageId);
659    
660                    content = StringUtil.replace(content, "<![CDATA[", StringPool.BLANK);
661                    content = StringUtil.replace(content, "]]>", StringPool.BLANK);
662                    content = StringUtil.replace(content, "&amp;", "&");
663                    content = StringUtil.replace(content, "&lt;", "<");
664                    content = StringUtil.replace(content, "&gt;", ">");
665    
666                    content = HtmlUtil.extractText(content);
667    
668                    return content;
669            }
670    
671            protected String extractContent(JournalArticle article, String languageId)
672                    throws Exception {
673    
674                    if (Validator.isNotNull(article.getStructureId())) {
675                            return extractDDMContent(article, languageId);
676                    }
677    
678                    return extractBasicContent(article, languageId);
679            }
680    
681            protected String extractDDMContent(
682                            JournalArticle article, String languageId)
683                    throws Exception {
684    
685                    if (Validator.isNull(article.getStructureId())) {
686                            return StringPool.BLANK;
687                    }
688    
689                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.fetchStructure(
690                            article.getGroupId(),
691                            PortalUtil.getClassNameId(JournalArticle.class),
692                            article.getStructureId(), true);
693    
694                    if (ddmStructure == null) {
695                            return StringPool.BLANK;
696                    }
697    
698                    Fields fields = null;
699    
700                    try {
701                            fields = JournalConverterUtil.getDDMFields(
702                                    ddmStructure, article.getContent());
703                    }
704                    catch (Exception e) {
705                            return StringPool.BLANK;
706                    }
707    
708                    if (fields == null) {
709                            return StringPool.BLANK;
710                    }
711    
712                    return DDMIndexerUtil.extractAttributes(
713                            ddmStructure, fields, LocaleUtil.fromLanguageId(languageId));
714            }
715    
716            protected JournalArticle fetchLatestIndexableArticleVersion(
717                            long resourcePrimKey)
718                    throws SystemException {
719    
720                    JournalArticle latestIndexableArticle =
721                            JournalArticleLocalServiceUtil.fetchLatestArticle(
722                                    resourcePrimKey,
723                                    new int[] {
724                                            WorkflowConstants.STATUS_APPROVED,
725                                            WorkflowConstants.STATUS_IN_TRASH
726                                    });
727    
728                    if (latestIndexableArticle == null) {
729                            latestIndexableArticle =
730                                    JournalArticleLocalServiceUtil.fetchLatestArticle(
731                                            resourcePrimKey);
732                    }
733    
734                    return latestIndexableArticle;
735            }
736    
737            protected Collection<Document> getArticleVersions(JournalArticle article)
738                    throws PortalException, SystemException {
739    
740                    Collection<Document> documents = new ArrayList<Document>();
741    
742                    List<JournalArticle> articles = null;
743    
744                    if (PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
745                            articles =
746                                    JournalArticleLocalServiceUtil.
747                                            getIndexableArticlesByResourcePrimKey(
748                                                    article.getResourcePrimKey());
749                    }
750                    else {
751                            articles = new ArrayList<JournalArticle>();
752    
753                            JournalArticle latestIndexableArticle =
754                                    fetchLatestIndexableArticleVersion(
755                                            article.getResourcePrimKey());
756    
757                            if (latestIndexableArticle != null) {
758                                    articles.add(latestIndexableArticle);
759                            }
760                    }
761    
762                    for (JournalArticle curArticle : articles) {
763                            Document document = getDocument(curArticle);
764    
765                            documents.add(document);
766                    }
767    
768                    return documents;
769            }
770    
771            protected String getBasicContentSummary(
772                    Document document, Locale snippetLocale) {
773    
774                    String prefix = Field.SNIPPET + StringPool.UNDERLINE;
775    
776                    String content = document.get(
777                            snippetLocale, prefix + Field.DESCRIPTION, prefix + Field.CONTENT);
778    
779                    if (Validator.isBlank(content)) {
780                            content = document.get(
781                                    snippetLocale, Field.DESCRIPTION, Field.CONTENT);
782                    }
783    
784                    if (content.length() > 200) {
785                            content = StringUtil.shorten(content, 200);
786                    }
787    
788                    return content;
789            }
790    
791            protected String getDDMContentSummary(
792                    Document document, Locale snippetLocale) {
793    
794                    String content = StringPool.BLANK;
795    
796                    try {
797                            long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID));
798                            String articleId = document.get("articleId");
799                            double version = GetterUtil.getDouble(document.get(Field.VERSION));
800    
801                            JournalArticle article =
802                                    JournalArticleLocalServiceUtil.fetchArticle(
803                                            groupId, articleId, version);
804    
805                            if (article == null) {
806                                    return content;
807                            }
808    
809                            JournalArticleDisplay articleDisplay =
810                                    JournalArticleLocalServiceUtil.getArticleDisplay(
811                                            article, null, Constants.VIEW,
812                                            LocaleUtil.toLanguageId(snippetLocale), 1, null, null);
813    
814                            content = HtmlUtil.escape(articleDisplay.getDescription());
815                            content = HtmlUtil.replaceNewLine(content);
816    
817                            if (Validator.isNull(content)) {
818                                    content = HtmlUtil.extractText(articleDisplay.getContent());
819                            }
820                    }
821                    catch (Exception e) {
822                            if (_log.isDebugEnabled()) {
823                                    _log.debug(e, e);
824                            }
825                    }
826    
827                    return content;
828            }
829    
830            protected String[] getLanguageIds(
831                    String defaultLanguageId, String content) {
832    
833                    String[] languageIds = LocalizationUtil.getAvailableLanguageIds(
834                            content);
835    
836                    if (languageIds.length == 0) {
837                            languageIds = new String[] {defaultLanguageId};
838                    }
839    
840                    return languageIds;
841            }
842    
843            @Override
844            protected String getPortletId(SearchContext searchContext) {
845                    return PORTLET_ID;
846            }
847    
848            protected void reindexArticles(long companyId)
849                    throws PortalException, SystemException {
850    
851                    ActionableDynamicQuery actionableDynamicQuery =
852                            new JournalArticleActionableDynamicQuery() {
853    
854                            @Override
855                            protected void performAction(Object object)
856                                    throws PortalException, SystemException {
857    
858                                    JournalArticle article = (JournalArticle)object;
859    
860                                    if (!PropsValues.JOURNAL_ARTICLE_INDEX_ALL_VERSIONS) {
861                                            JournalArticle latestIndexableArticle =
862                                                    fetchLatestIndexableArticleVersion(
863                                                            article.getResourcePrimKey());
864    
865                                            if (latestIndexableArticle == null) {
866                                                    return;
867                                            }
868    
869                                            article = latestIndexableArticle;
870                                    }
871    
872                                    Document document = getDocument(article);
873    
874                                    addDocument(document);
875                            }
876    
877                    };
878    
879                    actionableDynamicQuery.setCompanyId(companyId);
880                    actionableDynamicQuery.setSearchEngineId(getSearchEngineId());
881    
882                    actionableDynamicQuery.performActions();
883            }
884    
885            protected void reindexArticleVersions(JournalArticle article)
886                    throws PortalException, SystemException {
887    
888                    SearchEngineUtil.updateDocuments(
889                            getSearchEngineId(), article.getCompanyId(),
890                            getArticleVersions(article), isCommitImmediately());
891            }
892    
893            private static Log _log = LogFactoryUtil.getLog(
894                    JournalArticleIndexer.class);
895    
896    }