001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.journal.util;
016    
017    import com.liferay.portal.LocaleException;
018    import com.liferay.portal.kernel.configuration.Filter;
019    import com.liferay.portal.kernel.dao.orm.QueryUtil;
020    import com.liferay.portal.kernel.diff.CompareVersionsException;
021    import com.liferay.portal.kernel.diff.DiffHtmlUtil;
022    import com.liferay.portal.kernel.diff.DiffVersion;
023    import com.liferay.portal.kernel.diff.DiffVersionsInfo;
024    import com.liferay.portal.kernel.exception.PortalException;
025    import com.liferay.portal.kernel.exception.SystemException;
026    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
027    import com.liferay.portal.kernel.language.LanguageUtil;
028    import com.liferay.portal.kernel.log.Log;
029    import com.liferay.portal.kernel.log.LogFactoryUtil;
030    import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
031    import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
032    import com.liferay.portal.kernel.portlet.LiferayWindowState;
033    import com.liferay.portal.kernel.portlet.PortletRequestModel;
034    import com.liferay.portal.kernel.portlet.ThemeDisplayModel;
035    import com.liferay.portal.kernel.search.Field;
036    import com.liferay.portal.kernel.search.Hits;
037    import com.liferay.portal.kernel.search.Indexer;
038    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
039    import com.liferay.portal.kernel.templateparser.TransformerListener;
040    import com.liferay.portal.kernel.util.ArrayUtil;
041    import com.liferay.portal.kernel.util.CharPool;
042    import com.liferay.portal.kernel.util.Constants;
043    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
044    import com.liferay.portal.kernel.util.GetterUtil;
045    import com.liferay.portal.kernel.util.HtmlUtil;
046    import com.liferay.portal.kernel.util.HttpUtil;
047    import com.liferay.portal.kernel.util.InstanceFactory;
048    import com.liferay.portal.kernel.util.LocaleUtil;
049    import com.liferay.portal.kernel.util.LocalizationUtil;
050    import com.liferay.portal.kernel.util.OrderByComparator;
051    import com.liferay.portal.kernel.util.ParamUtil;
052    import com.liferay.portal.kernel.util.PropsKeys;
053    import com.liferay.portal.kernel.util.StringBundler;
054    import com.liferay.portal.kernel.util.StringPool;
055    import com.liferay.portal.kernel.util.StringUtil;
056    import com.liferay.portal.kernel.util.Time;
057    import com.liferay.portal.kernel.util.Validator;
058    import com.liferay.portal.kernel.workflow.WorkflowConstants;
059    import com.liferay.portal.kernel.xml.Attribute;
060    import com.liferay.portal.kernel.xml.Document;
061    import com.liferay.portal.kernel.xml.Element;
062    import com.liferay.portal.kernel.xml.Node;
063    import com.liferay.portal.kernel.xml.SAXReaderUtil;
064    import com.liferay.portal.kernel.xml.XPath;
065    import com.liferay.portal.model.Company;
066    import com.liferay.portal.model.Group;
067    import com.liferay.portal.model.Layout;
068    import com.liferay.portal.model.LayoutConstants;
069    import com.liferay.portal.model.LayoutSet;
070    import com.liferay.portal.model.ModelHintsUtil;
071    import com.liferay.portal.model.User;
072    import com.liferay.portal.service.ImageLocalServiceUtil;
073    import com.liferay.portal.service.LayoutLocalServiceUtil;
074    import com.liferay.portal.service.SubscriptionLocalServiceUtil;
075    import com.liferay.portal.service.UserLocalServiceUtil;
076    import com.liferay.portal.templateparser.Transformer;
077    import com.liferay.portal.theme.ThemeDisplay;
078    import com.liferay.portal.util.PortalUtil;
079    import com.liferay.portal.util.PortletKeys;
080    import com.liferay.portal.util.PropsUtil;
081    import com.liferay.portal.util.PropsValues;
082    import com.liferay.portal.util.WebKeys;
083    import com.liferay.portal.webserver.WebServerServletTokenUtil;
084    import com.liferay.portlet.PortalPreferences;
085    import com.liferay.portlet.PortletPreferencesFactoryUtil;
086    import com.liferay.portlet.PortletURLFactoryUtil;
087    import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
088    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
089    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
090    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
091    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
092    import com.liferay.portlet.journal.model.JournalArticle;
093    import com.liferay.portlet.journal.model.JournalArticleDisplay;
094    import com.liferay.portlet.journal.model.JournalFolder;
095    import com.liferay.portlet.journal.model.JournalFolderConstants;
096    import com.liferay.portlet.journal.model.JournalStructureConstants;
097    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
098    import com.liferay.portlet.journal.service.JournalArticleServiceUtil;
099    import com.liferay.portlet.journal.service.JournalFolderLocalServiceUtil;
100    import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
101    import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
102    import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
103    import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
104    import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
105    import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
106    import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
107    import com.liferay.util.FiniteUniqueStack;
108    
109    import java.util.ArrayList;
110    import java.util.Collections;
111    import java.util.Date;
112    import java.util.HashMap;
113    import java.util.Iterator;
114    import java.util.LinkedHashMap;
115    import java.util.List;
116    import java.util.Locale;
117    import java.util.Map;
118    import java.util.Stack;
119    import java.util.regex.Pattern;
120    
121    import javax.portlet.PortletPreferences;
122    import javax.portlet.PortletRequest;
123    import javax.portlet.PortletSession;
124    import javax.portlet.PortletURL;
125    import javax.portlet.RenderResponse;
126    
127    import javax.servlet.http.HttpServletRequest;
128    
129    /**
130     * @author Brian Wing Shun Chan
131     * @author Raymond Aug??
132     * @author Wesley Gong
133     * @author Angelo Jefferson
134     * @author Hugo Huijser
135     */
136    public class JournalUtil {
137    
138            public static final int MAX_STACK_SIZE = 20;
139    
140            public static final String[] SELECTED_FIELD_NAMES =
141                    {Field.ARTICLE_ID, Field.COMPANY_ID, Field.GROUP_ID, Field.UID};
142    
143            public static void addAllReservedEls(
144                    Element rootElement, Map<String, String> tokens, JournalArticle article,
145                    String languageId, ThemeDisplay themeDisplay) {
146    
147                    addReservedEl(
148                            rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_ID,
149                            article.getArticleId());
150    
151                    addReservedEl(
152                            rootElement, tokens,
153                            JournalStructureConstants.RESERVED_ARTICLE_VERSION,
154                            article.getVersion());
155    
156                    addReservedEl(
157                            rootElement, tokens,
158                            JournalStructureConstants.RESERVED_ARTICLE_TITLE,
159                            article.getTitle(languageId));
160    
161                    addReservedEl(
162                            rootElement, tokens,
163                            JournalStructureConstants.RESERVED_ARTICLE_URL_TITLE,
164                            article.getUrlTitle());
165    
166                    addReservedEl(
167                            rootElement, tokens,
168                            JournalStructureConstants.RESERVED_ARTICLE_DESCRIPTION,
169                            article.getDescription(languageId));
170    
171                    addReservedEl(
172                            rootElement, tokens,
173                            JournalStructureConstants.RESERVED_ARTICLE_TYPE, article.getType());
174    
175                    addReservedEl(
176                            rootElement, tokens,
177                            JournalStructureConstants.RESERVED_ARTICLE_CREATE_DATE,
178                            article.getCreateDate());
179    
180                    addReservedEl(
181                            rootElement, tokens,
182                            JournalStructureConstants.RESERVED_ARTICLE_MODIFIED_DATE,
183                            article.getModifiedDate());
184    
185                    if (article.getDisplayDate() != null) {
186                            addReservedEl(
187                                    rootElement, tokens,
188                                    JournalStructureConstants.RESERVED_ARTICLE_DISPLAY_DATE,
189                                    article.getDisplayDate());
190                    }
191    
192                    String smallImageURL = StringPool.BLANK;
193    
194                    if (Validator.isNotNull(article.getSmallImageURL())) {
195                            smallImageURL = article.getSmallImageURL();
196                    }
197                    else if ((themeDisplay != null) && article.isSmallImage()) {
198                            StringBundler sb = new StringBundler(5);
199    
200                            sb.append(themeDisplay.getPathImage());
201                            sb.append("/journal/article?img_id=");
202                            sb.append(article.getSmallImageId());
203                            sb.append("&t=");
204                            sb.append(
205                                    WebServerServletTokenUtil.getToken(article.getSmallImageId()));
206    
207                            smallImageURL = sb.toString();
208                    }
209    
210                    addReservedEl(
211                            rootElement, tokens,
212                            JournalStructureConstants.RESERVED_ARTICLE_SMALL_IMAGE_URL,
213                            smallImageURL);
214    
215                    String[] assetTagNames = new String[0];
216    
217                    try {
218                            assetTagNames = AssetTagLocalServiceUtil.getTagNames(
219                                    JournalArticle.class.getName(), article.getResourcePrimKey());
220                    }
221                    catch (SystemException se) {
222                    }
223    
224                    addReservedEl(
225                            rootElement, tokens,
226                            JournalStructureConstants.RESERVED_ARTICLE_ASSET_TAG_NAMES,
227                            StringUtil.merge(assetTagNames));
228    
229                    addReservedEl(
230                            rootElement, tokens,
231                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_ID,
232                            String.valueOf(article.getUserId()));
233    
234                    String userName = StringPool.BLANK;
235                    String userEmailAddress = StringPool.BLANK;
236                    String userComments = StringPool.BLANK;
237                    String userJobTitle = StringPool.BLANK;
238    
239                    try {
240                            User user = UserLocalServiceUtil.fetchUserById(article.getUserId());
241    
242                            if (user != null) {
243                                    userName = user.getFullName();
244                                    userEmailAddress = user.getEmailAddress();
245                                    userComments = user.getComments();
246                                    userJobTitle = user.getJobTitle();
247                            }
248                    }
249                    catch (SystemException se) {
250                    }
251    
252                    addReservedEl(
253                            rootElement, tokens,
254                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_NAME, userName);
255    
256                    addReservedEl(
257                            rootElement, tokens,
258                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_EMAIL_ADDRESS,
259                            userEmailAddress);
260    
261                    addReservedEl(
262                            rootElement, tokens,
263                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_COMMENTS,
264                            userComments);
265    
266                    addReservedEl(
267                            rootElement, tokens,
268                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_JOB_TITLE,
269                            userJobTitle);
270            }
271    
272            public static void addPortletBreadcrumbEntries(
273                            JournalArticle article, HttpServletRequest request,
274                            RenderResponse renderResponse)
275                    throws Exception {
276    
277                    JournalFolder folder = article.getFolder();
278    
279                    if (folder.getFolderId() !=
280                                    JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
281    
282                            addPortletBreadcrumbEntries(folder, request, renderResponse);
283                    }
284    
285                    JournalArticle unescapedArticle = article.toUnescapedModel();
286    
287                    PortletURL portletURL = renderResponse.createRenderURL();
288    
289                    portletURL.setParameter("struts_action", "/article/view_article");
290                    portletURL.setParameter(
291                            "groupId", String.valueOf(article.getGroupId()));
292                    portletURL.setParameter(
293                            "articleId", String.valueOf(article.getArticleId()));
294    
295                    PortalUtil.addPortletBreadcrumbEntry(
296                            request, unescapedArticle.getTitle(), portletURL.toString());
297            }
298    
299            public static void addPortletBreadcrumbEntries(
300                            JournalFolder folder, HttpServletRequest request,
301                            LiferayPortletResponse liferayPortletResponse)
302                    throws Exception {
303    
304                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
305                            com.liferay.portal.kernel.util.WebKeys.THEME_DISPLAY);
306    
307                    String strutsAction = ParamUtil.getString(request, "struts_action");
308    
309                    PortletURL portletURL = liferayPortletResponse.createRenderURL();
310    
311                    if (strutsAction.equals("/journal/select_folder")) {
312                            portletURL.setParameter("struts_action", "/journal/select_folder");
313                            portletURL.setWindowState(LiferayWindowState.POP_UP);
314    
315                            PortalUtil.addPortletBreadcrumbEntry(
316                                    request, themeDisplay.translate("home"), portletURL.toString());
317                    }
318                    else {
319                            portletURL.setParameter("struts_action", "/journal/view");
320    
321                            Map<String, Object> data = new HashMap<String, Object>();
322    
323                            data.put("direction-right", Boolean.TRUE.toString());
324                            data.put(
325                                    "folder-id", JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID);
326    
327                            PortalUtil.addPortletBreadcrumbEntry(
328                                    request, themeDisplay.translate("home"), portletURL.toString(),
329                                    data);
330                    }
331    
332                    if (folder == null) {
333                            return;
334                    }
335    
336                    List<JournalFolder> ancestorFolders = folder.getAncestors();
337    
338                    Collections.reverse(ancestorFolders);
339    
340                    for (JournalFolder ancestorFolder : ancestorFolders) {
341                            portletURL.setParameter(
342                                    "folderId", String.valueOf(ancestorFolder.getFolderId()));
343    
344                            Map<String, Object> data = new HashMap<String, Object>();
345    
346                            data.put("direction-right", Boolean.TRUE.toString());
347                            data.put("folder-id", ancestorFolder.getFolderId());
348    
349                            PortalUtil.addPortletBreadcrumbEntry(
350                                    request, ancestorFolder.getName(), portletURL.toString(), data);
351                    }
352    
353                    portletURL.setParameter(
354                            "folderId", String.valueOf(folder.getFolderId()));
355    
356                    if (folder.getFolderId() !=
357                                    JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
358    
359                            JournalFolder unescapedFolder = folder.toUnescapedModel();
360    
361                            Map<String, Object> data = new HashMap<String, Object>();
362    
363                            data.put("direction-right", Boolean.TRUE.toString());
364                            data.put("folder-id", folder.getFolderId());
365    
366                            PortalUtil.addPortletBreadcrumbEntry(
367                                    request, unescapedFolder.getName(), portletURL.toString(),
368                                    data);
369                    }
370            }
371    
372            public static void addPortletBreadcrumbEntries(
373                            JournalFolder folder, HttpServletRequest request,
374                            RenderResponse renderResponse)
375                    throws Exception {
376    
377                    LiferayPortletResponse liferayPortletResponse =
378                            (LiferayPortletResponse)renderResponse;
379    
380                    addPortletBreadcrumbEntries(folder, request, liferayPortletResponse);
381            }
382    
383            public static void addPortletBreadcrumbEntries(
384                            long folderId, HttpServletRequest request,
385                            RenderResponse renderResponse)
386                    throws Exception {
387    
388                    if (folderId == JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
389                            return;
390                    }
391    
392                    JournalFolder folder = JournalFolderLocalServiceUtil.getFolder(
393                            folderId);
394    
395                    addPortletBreadcrumbEntries(folder, request, renderResponse);
396            }
397    
398            public static void addRecentArticle(
399                    PortletRequest portletRequest, JournalArticle article) {
400    
401                    if (article != null) {
402                            Stack<JournalArticle> stack = getRecentArticles(portletRequest);
403    
404                            stack.push(article);
405                    }
406            }
407    
408            public static void addRecentDDMStructure(
409                    PortletRequest portletRequest, DDMStructure ddmStructure) {
410    
411                    if (ddmStructure != null) {
412                            Stack<DDMStructure> stack = getRecentDDMStructures(portletRequest);
413    
414                            stack.push(ddmStructure);
415                    }
416            }
417    
418            public static void addRecentDDMTemplate(
419                    PortletRequest portletRequest, DDMTemplate ddmTemplate) {
420    
421                    if (ddmTemplate != null) {
422                            Stack<DDMTemplate> stack = getRecentDDMTemplates(portletRequest);
423    
424                            stack.push(ddmTemplate);
425                    }
426            }
427    
428            public static void addReservedEl(
429                    Element rootElement, Map<String, String> tokens, String name,
430                    Date value) {
431    
432                    addReservedEl(rootElement, tokens, name, Time.getRFC822(value));
433            }
434    
435            public static void addReservedEl(
436                    Element rootElement, Map<String, String> tokens, String name,
437                    double value) {
438    
439                    addReservedEl(rootElement, tokens, name, String.valueOf(value));
440            }
441    
442            public static void addReservedEl(
443                    Element rootElement, Map<String, String> tokens, String name,
444                    String value) {
445    
446                    // XML
447    
448                    if (rootElement != null) {
449                            Element dynamicElementElement = rootElement.addElement(
450                                    "dynamic-element");
451    
452                            dynamicElementElement.addAttribute("name", name);
453    
454                            dynamicElementElement.addAttribute("type", "text");
455    
456                            Element dynamicContentElement = dynamicElementElement.addElement(
457                                    "dynamic-content");
458    
459                            //dynamicContentElement.setText("<![CDATA[" + value + "]]>");
460                            dynamicContentElement.setText(value);
461                    }
462    
463                    // Tokens
464    
465                    tokens.put(
466                            StringUtil.replace(name, CharPool.DASH, CharPool.UNDERLINE), value);
467            }
468    
469            public static String diffHtml(
470                            long groupId, String articleId, double sourceVersion,
471                            double targetVersion, String languageId,
472                            PortletRequestModel portletRequestModel, ThemeDisplay themeDisplay)
473                    throws Exception {
474    
475                    JournalArticle sourceArticle =
476                            JournalArticleLocalServiceUtil.getArticle(
477                                    groupId, articleId, sourceVersion);
478    
479                    if (!JournalArticleLocalServiceUtil.isRenderable(
480                                    sourceArticle, portletRequestModel, themeDisplay)) {
481    
482                            throw new CompareVersionsException(sourceVersion);
483                    }
484    
485                    JournalArticleDisplay sourceArticleDisplay =
486                            JournalArticleLocalServiceUtil.getArticleDisplay(
487                                    sourceArticle, null, Constants.VIEW, languageId, 1,
488                                    portletRequestModel, themeDisplay);
489    
490                    JournalArticle targetArticle =
491                            JournalArticleLocalServiceUtil.getArticle(
492                                    groupId, articleId, targetVersion);
493    
494                    if (!JournalArticleLocalServiceUtil.isRenderable(
495                                    targetArticle, portletRequestModel, themeDisplay)) {
496    
497                            throw new CompareVersionsException(targetVersion);
498                    }
499    
500                    JournalArticleDisplay targetArticleDisplay =
501                            JournalArticleLocalServiceUtil.getArticleDisplay(
502                                    targetArticle, null, Constants.VIEW, languageId, 1,
503                                    portletRequestModel, themeDisplay);
504    
505                    return DiffHtmlUtil.diff(
506                            new UnsyncStringReader(sourceArticleDisplay.getContent()),
507                            new UnsyncStringReader(targetArticleDisplay.getContent()));
508            }
509    
510            public static String doTransform(
511                            ThemeDisplay themeDisplay, Map<String, String> tokens,
512                            String viewMode, String languageId, Document document,
513                            PortletRequestModel portletRequestModel, String script,
514                            String langType)
515                    throws Exception {
516    
517                    return _transformer.doTransform(
518                            themeDisplay, tokens, viewMode, languageId, document,
519                            portletRequestModel, script, langType);
520            }
521    
522            public static String formatVM(String vm) {
523                    return vm;
524            }
525    
526            public static String getAbsolutePath(
527                            PortletRequest portletRequest, long folderId)
528                    throws PortalException {
529    
530                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
531                            WebKeys.THEME_DISPLAY);
532    
533                    if (folderId == JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
534                            return themeDisplay.translate("home");
535                    }
536    
537                    JournalFolder folder = JournalFolderLocalServiceUtil.getFolder(
538                            folderId);
539    
540                    List<JournalFolder> folders = folder.getAncestors();
541    
542                    Collections.reverse(folders);
543    
544                    StringBundler sb = new StringBundler((folders.size() * 3) + 5);
545    
546                    sb.append(themeDisplay.translate("home"));
547                    sb.append(StringPool.SPACE);
548    
549                    for (JournalFolder curFolder : folders) {
550                            sb.append(StringPool.RAQUO_CHAR);
551                            sb.append(StringPool.SPACE);
552                            sb.append(curFolder.getName());
553                    }
554    
555                    sb.append(StringPool.RAQUO_CHAR);
556                    sb.append(StringPool.SPACE);
557                    sb.append(folder.getName());
558    
559                    return sb.toString();
560            }
561    
562            public static Layout getArticleLayout(String layoutUuid, long groupId) {
563                    if (Validator.isNull(layoutUuid)) {
564                            return null;
565                    }
566    
567                    // The target page and the article must belong to the same group
568    
569                    Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
570                            layoutUuid, groupId, false);
571    
572                    if (layout == null) {
573                            layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
574                                    layoutUuid, groupId, true);
575                    }
576    
577                    return layout;
578            }
579    
580            public static OrderByComparator<JournalArticle> getArticleOrderByComparator(
581                    String orderByCol, String orderByType) {
582    
583                    boolean orderByAsc = false;
584    
585                    if (orderByType.equals("asc")) {
586                            orderByAsc = true;
587                    }
588    
589                    OrderByComparator<JournalArticle> orderByComparator = null;
590    
591                    if (orderByCol.equals("create-date")) {
592                            orderByComparator = new ArticleCreateDateComparator(orderByAsc);
593                    }
594                    else if (orderByCol.equals("display-date")) {
595                            orderByComparator = new ArticleDisplayDateComparator(orderByAsc);
596                    }
597                    else if (orderByCol.equals("id")) {
598                            orderByComparator = new ArticleIDComparator(orderByAsc);
599                    }
600                    else if (orderByCol.equals("modified-date")) {
601                            orderByComparator = new ArticleModifiedDateComparator(orderByAsc);
602                    }
603                    else if (orderByCol.equals("review-date")) {
604                            orderByComparator = new ArticleReviewDateComparator(orderByAsc);
605                    }
606                    else if (orderByCol.equals("title")) {
607                            orderByComparator = new ArticleTitleComparator(orderByAsc);
608                    }
609                    else if (orderByCol.equals("version")) {
610                            orderByComparator = new ArticleVersionComparator(orderByAsc);
611                    }
612    
613                    return orderByComparator;
614            }
615    
616            public static List<JournalArticle> getArticles(Hits hits)
617                    throws PortalException {
618    
619                    List<com.liferay.portal.kernel.search.Document> documents =
620                            hits.toList();
621    
622                    List<JournalArticle> articles = new ArrayList<JournalArticle>(
623                            documents.size());
624    
625                    for (com.liferay.portal.kernel.search.Document document : documents) {
626                            String articleId = document.get(Field.ARTICLE_ID);
627                            long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID));
628    
629                            JournalArticle article =
630                                    JournalArticleLocalServiceUtil.fetchLatestArticle(
631                                            groupId, articleId, WorkflowConstants.STATUS_APPROVED);
632    
633                            if (article == null) {
634                                    articles = null;
635    
636                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
637                                            JournalArticle.class);
638    
639                                    long companyId = GetterUtil.getLong(
640                                            document.get(Field.COMPANY_ID));
641    
642                                    indexer.delete(companyId, document.getUID());
643                            }
644                            else if (articles != null) {
645                                    articles.add(article);
646                            }
647                    }
648    
649                    return articles;
650            }
651    
652            public static DiffVersionsInfo getDiffVersionsInfo(
653                    long groupId, String articleId, double sourceVersion,
654                    double targetVersion) {
655    
656                    double previousVersion = 0;
657                    double nextVersion = 0;
658    
659                    List<JournalArticle> articles =
660                            JournalArticleServiceUtil.getArticlesByArticleId(
661                                    groupId, articleId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
662                                    new ArticleVersionComparator(true));
663    
664                    for (JournalArticle article : articles) {
665                            if ((article.getVersion() < sourceVersion) &&
666                                    (article.getVersion() > previousVersion)) {
667    
668                                    previousVersion = article.getVersion();
669                            }
670    
671                            if ((article.getVersion() > targetVersion) &&
672                                    ((article.getVersion() < nextVersion) || (nextVersion == 0))) {
673    
674                                    nextVersion = article.getVersion();
675                            }
676                    }
677    
678                    List<DiffVersion> diffVersions = new ArrayList<DiffVersion>();
679    
680                    for (JournalArticle article : articles) {
681                            DiffVersion diffVersion = new DiffVersion(
682                                    article.getUserId(), article.getVersion(),
683                                    article.getModifiedDate());
684    
685                            diffVersions.add(diffVersion);
686                    }
687    
688                    return new DiffVersionsInfo(diffVersions, nextVersion, previousVersion);
689            }
690    
691            public static String getDisplayStyle(
692                    LiferayPortletRequest liferayPortletRequest, String[] displayViews) {
693    
694                    PortalPreferences portalPreferences =
695                            PortletPreferencesFactoryUtil.getPortalPreferences(
696                                    liferayPortletRequest);
697    
698                    String displayStyle = ParamUtil.getString(
699                            liferayPortletRequest, "displayStyle");
700    
701                    if (Validator.isNull(displayStyle)) {
702                            displayStyle = portalPreferences.getValue(
703                                    PortletKeys.JOURNAL, "display-style",
704                                    PropsValues.JOURNAL_DEFAULT_DISPLAY_VIEW);
705                    }
706                    else {
707                            if (ArrayUtil.contains(displayViews, displayStyle)) {
708                                    portalPreferences.setValue(
709                                            PortletKeys.JOURNAL, "display-style", displayStyle);
710                            }
711                    }
712    
713                    if (!ArrayUtil.contains(displayViews, displayStyle)) {
714                            displayStyle = displayViews[0];
715                    }
716    
717                    return displayStyle;
718            }
719    
720            public static Map<Locale, String> getEmailArticleAddedBodyMap(
721                    PortletPreferences preferences) {
722    
723                    return LocalizationUtil.getLocalizationMap(
724                            preferences, "emailArticleAddedBody",
725                            PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_BODY);
726            }
727    
728            public static boolean getEmailArticleAddedEnabled(
729                    PortletPreferences preferences) {
730    
731                    String emailArticleAddedEnabled = preferences.getValue(
732                            "emailArticleAddedEnabled", StringPool.BLANK);
733    
734                    if (Validator.isNotNull(emailArticleAddedEnabled)) {
735                            return GetterUtil.getBoolean(emailArticleAddedEnabled);
736                    }
737                    else {
738                            return GetterUtil.getBoolean(
739                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_ENABLED));
740                    }
741            }
742    
743            public static Map<Locale, String> getEmailArticleAddedSubjectMap(
744                    PortletPreferences preferences) {
745    
746                    return LocalizationUtil.getLocalizationMap(
747                            preferences, "emailArticleAddedSubject",
748                            PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_SUBJECT);
749            }
750    
751            public static boolean getEmailArticleAnyEventEnabled(
752                    PortletPreferences preferences) {
753    
754                    if (getEmailArticleAddedEnabled(preferences) ||
755                            getEmailArticleApprovalDeniedEnabled(preferences) ||
756                            getEmailArticleApprovalGrantedEnabled(preferences) ||
757                            getEmailArticleApprovalRequestedEnabled(preferences) ||
758                            getEmailArticleReviewEnabled(preferences) ||
759                            getEmailArticleUpdatedEnabled(preferences)) {
760    
761                            return true;
762                    }
763    
764                    return false;
765            }
766    
767            public static Map<Locale, String> getEmailArticleApprovalDeniedBodyMap(
768                    PortletPreferences preferences) {
769    
770                    return LocalizationUtil.getLocalizationMap(
771                            preferences, "emailArticleApprovalDeniedBody",
772                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_BODY);
773            }
774    
775            public static boolean getEmailArticleApprovalDeniedEnabled(
776                    PortletPreferences preferences) {
777    
778                    String emailArticleApprovalDeniedEnabled = preferences.getValue(
779                            "emailArticleApprovalDeniedEnabled", StringPool.BLANK);
780    
781                    if (Validator.isNotNull(emailArticleApprovalDeniedEnabled)) {
782                            return GetterUtil.getBoolean(emailArticleApprovalDeniedEnabled);
783                    }
784                    else {
785                            return GetterUtil.getBoolean(
786                                    PropsUtil.get(
787                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_ENABLED));
788                    }
789            }
790    
791            public static Map<Locale, String> getEmailArticleApprovalDeniedSubjectMap(
792                    PortletPreferences preferences) {
793    
794                    return LocalizationUtil.getLocalizationMap(
795                            preferences, "emailArticleApprovalDeniedSubject",
796                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_SUBJECT);
797            }
798    
799            public static Map<Locale, String> getEmailArticleApprovalGrantedBodyMap(
800                    PortletPreferences preferences) {
801    
802                    return LocalizationUtil.getLocalizationMap(
803                            preferences, "emailArticleApprovalGrantedBody",
804                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_BODY);
805            }
806    
807            public static boolean getEmailArticleApprovalGrantedEnabled(
808                    PortletPreferences preferences) {
809    
810                    String emailArticleApprovalGrantedEnabled = preferences.getValue(
811                            "emailArticleApprovalGrantedEnabled", StringPool.BLANK);
812    
813                    if (Validator.isNotNull(emailArticleApprovalGrantedEnabled)) {
814                            return GetterUtil.getBoolean(emailArticleApprovalGrantedEnabled);
815                    }
816                    else {
817                            return GetterUtil.getBoolean(
818                                    PropsUtil.get(
819                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_ENABLED));
820                    }
821            }
822    
823            public static Map<Locale, String> getEmailArticleApprovalGrantedSubjectMap(
824                    PortletPreferences preferences) {
825    
826                    return LocalizationUtil.getLocalizationMap(
827                            preferences, "emailArticleApprovalGrantedSubject",
828                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_SUBJECT);
829            }
830    
831            public static Map<Locale, String> getEmailArticleApprovalRequestedBodyMap(
832                    PortletPreferences preferences) {
833    
834                    return LocalizationUtil.getLocalizationMap(
835                            preferences, "emailArticleApprovalRequestedBody",
836                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_BODY);
837            }
838    
839            public static boolean getEmailArticleApprovalRequestedEnabled(
840                    PortletPreferences preferences) {
841    
842                    String emailArticleApprovalRequestedEnabled = preferences.getValue(
843                            "emailArticleApprovalRequestedEnabled", StringPool.BLANK);
844    
845                    if (Validator.isNotNull(emailArticleApprovalRequestedEnabled)) {
846                            return GetterUtil.getBoolean(emailArticleApprovalRequestedEnabled);
847                    }
848                    else {
849                            return GetterUtil.getBoolean(
850                                    PropsUtil.get(
851                                            PropsKeys.
852                                                    JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_ENABLED));
853                    }
854            }
855    
856            public static Map<Locale, String>
857                    getEmailArticleApprovalRequestedSubjectMap(
858                            PortletPreferences preferences) {
859    
860                    return LocalizationUtil.getLocalizationMap(
861                            preferences, "emailArticleApprovalRequestedSubject",
862                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_SUBJECT);
863            }
864    
865            public static Map<Locale, String> getEmailArticleReviewBodyMap(
866                    PortletPreferences preferences) {
867    
868                    return LocalizationUtil.getLocalizationMap(
869                            preferences, "emailArticleReviewBody",
870                            PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_BODY);
871            }
872    
873            public static boolean getEmailArticleReviewEnabled(
874                    PortletPreferences preferences) {
875    
876                    String emailArticleReviewEnabled = preferences.getValue(
877                            "emailArticleReviewEnabled", StringPool.BLANK);
878    
879                    if (Validator.isNotNull(emailArticleReviewEnabled)) {
880                            return GetterUtil.getBoolean(emailArticleReviewEnabled);
881                    }
882                    else {
883                            return GetterUtil.getBoolean(
884                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_ENABLED));
885                    }
886            }
887    
888            public static Map<Locale, String> getEmailArticleReviewSubjectMap(
889                    PortletPreferences preferences) {
890    
891                    return LocalizationUtil.getLocalizationMap(
892                            preferences, "emailArticleReviewSubject",
893                            PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_SUBJECT);
894            }
895    
896            public static Map<Locale, String> getEmailArticleUpdatedBodyMap(
897                    PortletPreferences preferences) {
898    
899                    return LocalizationUtil.getLocalizationMap(
900                            preferences, "emailArticleUpdatedBody",
901                            PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_BODY);
902            }
903    
904            public static boolean getEmailArticleUpdatedEnabled(
905                    PortletPreferences preferences) {
906    
907                    String emailArticleUpdatedEnabled = preferences.getValue(
908                            "emailArticleUpdatedEnabled", StringPool.BLANK);
909    
910                    if (Validator.isNotNull(emailArticleUpdatedEnabled)) {
911                            return GetterUtil.getBoolean(emailArticleUpdatedEnabled);
912                    }
913                    else {
914                            return GetterUtil.getBoolean(
915                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_ENABLED));
916                    }
917            }
918    
919            public static Map<Locale, String> getEmailArticleUpdatedSubjectMap(
920                    PortletPreferences preferences) {
921    
922                    return LocalizationUtil.getLocalizationMap(
923                            preferences, "emailArticleUpdatedSubject",
924                            PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_SUBJECT);
925            }
926    
927            public static Map<String, String> getEmailDefinitionTerms(
928                    PortletRequest portletRequest, String emailFromAddress,
929                    String emailFromName) {
930    
931                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
932                            WebKeys.THEME_DISPLAY);
933    
934                    Map<String, String> definitionTerms =
935                            new LinkedHashMap<String, String>();
936    
937                    definitionTerms.put(
938                            "[$ARTICLE_CONTENT]",
939                            LanguageUtil.get(themeDisplay.getLocale(), "the-web-content"));
940                    definitionTerms.put(
941                            "[$ARTICLE_DIFFS$]",
942                            LanguageUtil.get(
943                                    themeDisplay.getLocale(),
944                                    "the-web-content-compared-with-the-previous-version-web-" +
945                                            "content"));
946                    definitionTerms.put(
947                            "[$ARTICLE_ID$]",
948                            LanguageUtil.get(themeDisplay.getLocale(), "the-web-content-id"));
949                    definitionTerms.put(
950                            "[$ARTICLE_TITLE$]",
951                            LanguageUtil.get(
952                                    themeDisplay.getLocale(), "the-web-content-title"));
953                    definitionTerms.put(
954                            "[$ARTICLE_URL$]",
955                            LanguageUtil.get(themeDisplay.getLocale(), "the-web-content-url"));
956                    definitionTerms.put(
957                            "[$ARTICLE_VERSION$]",
958                            LanguageUtil.get(
959                                    themeDisplay.getLocale(), "the-web-content-version"));
960                    definitionTerms.put(
961                            "[$FROM_ADDRESS$]", HtmlUtil.escape(emailFromAddress));
962                    definitionTerms.put("[$FROM_NAME$]", HtmlUtil.escape(emailFromName));
963    
964                    Company company = themeDisplay.getCompany();
965    
966                    definitionTerms.put("[$PORTAL_URL$]", company.getVirtualHostname());
967    
968                    definitionTerms.put(
969                            "[$PORTLET_NAME$]", PortalUtil.getPortletTitle(portletRequest));
970                    definitionTerms.put(
971                            "[$TO_ADDRESS$]",
972                            LanguageUtil.get(
973                                    themeDisplay.getLocale(),
974                                    "the-address-of-the-email-recipient"));
975                    definitionTerms.put(
976                            "[$TO_NAME$]",
977                            LanguageUtil.get(
978                                    themeDisplay.getLocale(), "the-name-of-the-email-recipient"));
979    
980                    return definitionTerms;
981            }
982    
983            public static String getEmailFromAddress(
984                    PortletPreferences preferences, long companyId) {
985    
986                    return PortalUtil.getEmailFromAddress(
987                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_ADDRESS);
988            }
989    
990            public static String getEmailFromName(
991                    PortletPreferences preferences, long companyId) {
992    
993                    return PortalUtil.getEmailFromName(
994                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_NAME);
995            }
996    
997            public static String getJournalControlPanelLink(
998                            PortletRequest portletRequest, long folderId)
999                    throws PortalException {
1000    
1001                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
1002                            WebKeys.THEME_DISPLAY);
1003    
1004                    PortletURL portletURL = PortletURLFactoryUtil.create(
1005                            portletRequest, PortletKeys.JOURNAL,
1006                            PortalUtil.getControlPanelPlid(themeDisplay.getCompanyId()),
1007                            PortletRequest.RENDER_PHASE);
1008    
1009                    portletURL.setParameter("struts_action", "/journal/view");
1010                    portletURL.setParameter("folderId", String.valueOf(folderId));
1011    
1012                    return portletURL.toString();
1013            }
1014    
1015            public static long getPreviewPlid(
1016                            JournalArticle article, ThemeDisplay themeDisplay)
1017                    throws Exception {
1018    
1019                    if (article != null) {
1020                            Layout layout = article.getLayout();
1021    
1022                            if (layout != null) {
1023                                    return layout.getPlid();
1024                            }
1025                    }
1026    
1027                    Layout layout = LayoutLocalServiceUtil.fetchFirstLayout(
1028                            themeDisplay.getScopeGroupId(), false,
1029                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
1030    
1031                    if (layout == null) {
1032                            layout = LayoutLocalServiceUtil.fetchFirstLayout(
1033                                    themeDisplay.getScopeGroupId(), true,
1034                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
1035                    }
1036    
1037                    if (layout != null) {
1038                            return layout.getPlid();
1039                    }
1040    
1041                    return themeDisplay.getPlid();
1042            }
1043    
1044            public static Stack<JournalArticle> getRecentArticles(
1045                    PortletRequest portletRequest) {
1046    
1047                    PortletSession portletSession = portletRequest.getPortletSession();
1048    
1049                    Stack<JournalArticle> recentArticles =
1050                            (Stack<JournalArticle>)portletSession.getAttribute(
1051                                    WebKeys.JOURNAL_RECENT_ARTICLES);
1052    
1053                    if (recentArticles == null) {
1054                            recentArticles = new FiniteUniqueStack<JournalArticle>(
1055                                    MAX_STACK_SIZE);
1056    
1057                            portletSession.setAttribute(
1058                                    WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
1059                    }
1060    
1061                    return recentArticles;
1062            }
1063    
1064            public static Stack<DDMStructure> getRecentDDMStructures(
1065                    PortletRequest portletRequest) {
1066    
1067                    PortletSession portletSession = portletRequest.getPortletSession();
1068    
1069                    Stack<DDMStructure> recentDDMStructures =
1070                            (Stack<DDMStructure>)portletSession.getAttribute(
1071                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_STRUCTURES);
1072    
1073                    if (recentDDMStructures == null) {
1074                            recentDDMStructures = new FiniteUniqueStack<DDMStructure>(
1075                                    MAX_STACK_SIZE);
1076    
1077                            portletSession.setAttribute(
1078                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_STRUCTURES,
1079                                    recentDDMStructures);
1080                    }
1081    
1082                    return recentDDMStructures;
1083            }
1084    
1085            public static Stack<DDMTemplate> getRecentDDMTemplates(
1086                    PortletRequest portletRequest) {
1087    
1088                    PortletSession portletSession = portletRequest.getPortletSession();
1089    
1090                    Stack<DDMTemplate> recentDDMTemplates =
1091                            (Stack<DDMTemplate>)portletSession.getAttribute(
1092                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_TEMPLATES);
1093    
1094                    if (recentDDMTemplates == null) {
1095                            recentDDMTemplates = new FiniteUniqueStack<DDMTemplate>(
1096                                    MAX_STACK_SIZE);
1097    
1098                            portletSession.setAttribute(
1099                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_TEMPLATES,
1100                                    recentDDMTemplates);
1101                    }
1102    
1103                    return recentDDMTemplates;
1104            }
1105    
1106            public static int getRestrictionType(long folderId) {
1107                    int restrictionType = JournalFolderConstants.RESTRICTION_TYPE_INHERIT;
1108    
1109                    JournalFolder folder = JournalFolderLocalServiceUtil.fetchFolder(
1110                            folderId);
1111    
1112                    if (folder != null) {
1113                            restrictionType = folder.getRestrictionType();
1114                    }
1115    
1116                    return restrictionType;
1117            }
1118    
1119            public static String getTemplateScript(
1120                    DDMTemplate ddmTemplate, Map<String, String> tokens, String languageId,
1121                    boolean transform) {
1122    
1123                    String script = ddmTemplate.getScript();
1124    
1125                    if (!transform) {
1126                            return script;
1127                    }
1128    
1129                    String[] transformerListenerClassNames = PropsUtil.getArray(
1130                            PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
1131    
1132                    for (String transformerListenerClassName :
1133                                    transformerListenerClassNames) {
1134    
1135                            TransformerListener transformerListener = null;
1136    
1137                            try {
1138                                    transformerListener =
1139                                            (TransformerListener)InstanceFactory.newInstance(
1140                                                    transformerListenerClassName);
1141    
1142                                    continue;
1143                            }
1144                            catch (Exception e) {
1145                                    _log.error(e, e);
1146                            }
1147    
1148                            script = transformerListener.onScript(
1149                                    script, (Document)null, languageId, tokens);
1150                    }
1151    
1152                    return script;
1153            }
1154    
1155            public static String getTemplateScript(
1156                            long groupId, String ddmTemplateKey, Map<String, String> tokens,
1157                            String languageId)
1158                    throws PortalException {
1159    
1160                    return getTemplateScript(
1161                            groupId, ddmTemplateKey, tokens, languageId, true);
1162            }
1163    
1164            public static String getTemplateScript(
1165                            long groupId, String ddmTemplateKey, Map<String, String> tokens,
1166                            String languageId, boolean transform)
1167                    throws PortalException {
1168    
1169                    DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
1170                            groupId, PortalUtil.getClassNameId(DDMStructure.class),
1171                            ddmTemplateKey, true);
1172    
1173                    return getTemplateScript(ddmTemplate, tokens, languageId, transform);
1174            }
1175    
1176            public static Map<String, String> getTokens(
1177                            long articleGroupId, PortletRequestModel portletRequestModel,
1178                            ThemeDisplay themeDisplay)
1179                    throws PortalException {
1180    
1181                    Map<String, String> tokens = new HashMap<String, String>();
1182    
1183                    if (themeDisplay != null) {
1184                            _populateTokens(tokens, articleGroupId, themeDisplay);
1185                    }
1186                    else if (portletRequestModel != null) {
1187                            ThemeDisplayModel themeDisplayModel =
1188                                    portletRequestModel.getThemeDisplayModel();
1189    
1190                            if (themeDisplayModel != null) {
1191                                    try {
1192                                            _populateTokens(tokens, articleGroupId, themeDisplayModel);
1193                                    }
1194                                    catch (Exception e) {
1195                                            if (_log.isWarnEnabled()) {
1196                                                    _log.warn(e, e);
1197                                            }
1198                                    }
1199                            }
1200                    }
1201    
1202                    return tokens;
1203            }
1204    
1205            public static Map<String, String> getTokens(
1206                            long articleGroupId, ThemeDisplay themeDisplay)
1207                    throws PortalException {
1208    
1209                    return getTokens(
1210                            articleGroupId, (PortletRequestModel)null, themeDisplay);
1211            }
1212    
1213            public static String getUrlTitle(long id, String title) {
1214                    if (title == null) {
1215                            return String.valueOf(id);
1216                    }
1217    
1218                    title = StringUtil.toLowerCase(title.trim());
1219    
1220                    if (Validator.isNull(title) || Validator.isNumber(title) ||
1221                            title.equals("rss")) {
1222    
1223                            title = String.valueOf(id);
1224                    }
1225                    else {
1226                            title = FriendlyURLNormalizerUtil.normalize(
1227                                    title, _friendlyURLPattern);
1228                    }
1229    
1230                    return ModelHintsUtil.trimString(
1231                            JournalArticle.class.getName(), "urlTitle", title);
1232            }
1233    
1234            public static boolean isSubscribedToFolder(
1235                            long companyId, long groupId, long userId, long folderId)
1236                    throws PortalException {
1237    
1238                    return isSubscribedToFolder(companyId, groupId, userId, folderId, true);
1239            }
1240    
1241            public static boolean isSubscribedToFolder(
1242                            long companyId, long groupId, long userId, long folderId,
1243                            boolean recursive)
1244                    throws PortalException {
1245    
1246                    List<Long> ancestorFolderIds = new ArrayList<Long>();
1247    
1248                    if (folderId != JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
1249                            JournalFolder folder = JournalFolderLocalServiceUtil.getFolder(
1250                                    folderId);
1251    
1252                            ancestorFolderIds.add(folderId);
1253    
1254                            if (recursive) {
1255                                    ancestorFolderIds.addAll(folder.getAncestorFolderIds());
1256    
1257                                    ancestorFolderIds.add(groupId);
1258                            }
1259                    }
1260                    else {
1261                            ancestorFolderIds.add(groupId);
1262                    }
1263    
1264                    return SubscriptionLocalServiceUtil.isSubscribed(
1265                            companyId, userId, JournalFolder.class.getName(),
1266                            ArrayUtil.toLongArray(ancestorFolderIds));
1267            }
1268    
1269            public static boolean isSubscribedToStructure(
1270                    long companyId, long groupId, long userId, long ddmStructureId) {
1271    
1272                    return SubscriptionLocalServiceUtil.isSubscribed(
1273                            companyId, userId, DDMStructure.class.getName(), ddmStructureId);
1274            }
1275    
1276            public static String mergeArticleContent(
1277                    String curContent, String newContent, boolean removeNullElements) {
1278    
1279                    try {
1280                            Document curDocument = SAXReaderUtil.read(curContent);
1281                            Document newDocument = SAXReaderUtil.read(newContent);
1282    
1283                            Element curRootElement = curDocument.getRootElement();
1284                            Element newRootElement = newDocument.getRootElement();
1285    
1286                            curRootElement.addAttribute(
1287                                    "default-locale",
1288                                    newRootElement.attributeValue("default-locale"));
1289                            curRootElement.addAttribute(
1290                                    "available-locales",
1291                                    newRootElement.attributeValue("available-locales"));
1292    
1293                            _mergeArticleContentUpdate(
1294                                    curDocument, newRootElement,
1295                                    LocaleUtil.toLanguageId(LocaleUtil.getSiteDefault()));
1296    
1297                            if (removeNullElements) {
1298                                    _mergeArticleContentDelete(curRootElement, newDocument);
1299                            }
1300    
1301                            curContent = DDMXMLUtil.formatXML(curDocument);
1302                    }
1303                    catch (Exception e) {
1304                            _log.error(e, e);
1305                    }
1306    
1307                    return curContent;
1308            }
1309    
1310            public static String prepareLocalizedContentForImport(
1311                            String content, Locale defaultImportLocale)
1312                    throws LocaleException {
1313    
1314                    try {
1315                            Document oldDocument = SAXReaderUtil.read(content);
1316    
1317                            Document newDocument = SAXReaderUtil.read(content);
1318    
1319                            Element newRootElement = newDocument.getRootElement();
1320    
1321                            Attribute availableLocalesAttribute = newRootElement.attribute(
1322                                    "available-locales");
1323    
1324                            String defaultImportLanguageId = LocaleUtil.toLanguageId(
1325                                    defaultImportLocale);
1326    
1327                            if (!StringUtil.contains(
1328                                            availableLocalesAttribute.getValue(),
1329                                            defaultImportLanguageId)) {
1330    
1331                                    availableLocalesAttribute.setValue(
1332                                            availableLocalesAttribute.getValue() + StringPool.COMMA +
1333                                                    defaultImportLanguageId);
1334    
1335                                    _mergeArticleContentUpdate(
1336                                            oldDocument, newRootElement,
1337                                            LocaleUtil.toLanguageId(defaultImportLocale));
1338    
1339                                    content = DDMXMLUtil.formatXML(newDocument);
1340                            }
1341    
1342                            Attribute defaultLocaleAttribute = newRootElement.attribute(
1343                                    "default-locale");
1344    
1345                            Locale defaultContentLocale = LocaleUtil.fromLanguageId(
1346                                    defaultLocaleAttribute.getValue());
1347    
1348                            if (!LocaleUtil.equals(defaultContentLocale, defaultImportLocale)) {
1349                                    defaultLocaleAttribute.setValue(defaultImportLanguageId);
1350    
1351                                    content = DDMXMLUtil.formatXML(newDocument);
1352                            }
1353                    }
1354                    catch (Exception e) {
1355                            throw new LocaleException(
1356                                    LocaleException.TYPE_CONTENT,
1357                                    "The locale " + defaultImportLocale + " is not available");
1358                    }
1359    
1360                    return content;
1361            }
1362    
1363            public static String removeArticleLocale(
1364                    Document document, String content, String languageId) {
1365    
1366                    try {
1367                            Element rootElement = document.getRootElement();
1368    
1369                            String availableLocales = rootElement.attributeValue(
1370                                    "available-locales");
1371    
1372                            if (availableLocales == null) {
1373                                    return content;
1374                            }
1375    
1376                            availableLocales = StringUtil.removeFromList(
1377                                    availableLocales, languageId);
1378    
1379                            if (availableLocales.endsWith(",")) {
1380                                    availableLocales = availableLocales.substring(
1381                                            0, availableLocales.length() - 1);
1382                            }
1383    
1384                            rootElement.addAttribute("available-locales", availableLocales);
1385    
1386                            removeArticleLocale(rootElement, languageId);
1387    
1388                            content = DDMXMLUtil.formatXML(document);
1389                    }
1390                    catch (Exception e) {
1391                            _log.error(e, e);
1392                    }
1393    
1394                    return content;
1395            }
1396    
1397            public static void removeArticleLocale(Element element, String languageId)
1398                    throws PortalException {
1399    
1400                    for (Element dynamicElementElement :
1401                                    element.elements("dynamic-element")) {
1402    
1403                            for (Element dynamicContentElement :
1404                                            dynamicElementElement.elements("dynamic-content")) {
1405    
1406                                    String curLanguageId = GetterUtil.getString(
1407                                            dynamicContentElement.attributeValue("language-id"));
1408    
1409                                    if (curLanguageId.equals(languageId)) {
1410                                            long id = GetterUtil.getLong(
1411                                                    dynamicContentElement.attributeValue("id"));
1412    
1413                                            if (id > 0) {
1414                                                    ImageLocalServiceUtil.deleteImage(id);
1415                                            }
1416    
1417                                            dynamicContentElement.detach();
1418                                    }
1419                            }
1420    
1421                            removeArticleLocale(dynamicElementElement, languageId);
1422                    }
1423            }
1424    
1425            public static String removeOldContent(String content, String xsd) {
1426                    try {
1427                            Document contentDoc = SAXReaderUtil.read(content);
1428                            Document xsdDoc = SAXReaderUtil.read(xsd);
1429    
1430                            Element contentRoot = contentDoc.getRootElement();
1431    
1432                            Stack<String> path = new Stack<String>();
1433    
1434                            path.push(contentRoot.getName());
1435    
1436                            _removeOldContent(path, contentRoot, xsdDoc);
1437    
1438                            content = DDMXMLUtil.formatXML(contentDoc);
1439                    }
1440                    catch (Exception e) {
1441                            _log.error(e, e);
1442                    }
1443    
1444                    return content;
1445            }
1446    
1447            public static void removeRecentArticle(
1448                    PortletRequest portletRequest, String articleId) {
1449    
1450                    removeRecentArticle(portletRequest, articleId, 0);
1451            }
1452    
1453            public static void removeRecentArticle(
1454                    PortletRequest portletRequest, String articleId, double version) {
1455    
1456                    Stack<JournalArticle> stack = getRecentArticles(portletRequest);
1457    
1458                    Iterator<JournalArticle> itr = stack.iterator();
1459    
1460                    while (itr.hasNext()) {
1461                            JournalArticle journalArticle = itr.next();
1462    
1463                            if (journalArticle.getArticleId().equals(articleId) &&
1464                                    ((journalArticle.getVersion() == version) ||
1465                                     (version == 0))) {
1466    
1467                                    itr.remove();
1468                            }
1469                    }
1470            }
1471    
1472            public static void removeRecentDDMStructure(
1473                    PortletRequest portletRequest, String ddmStructureKey) {
1474    
1475                    Stack<DDMStructure> stack = getRecentDDMStructures(portletRequest);
1476    
1477                    Iterator<DDMStructure> itr = stack.iterator();
1478    
1479                    while (itr.hasNext()) {
1480                            DDMStructure ddmStructure = itr.next();
1481    
1482                            if (ddmStructureKey.equals(ddmStructure.getStructureKey())) {
1483                                    itr.remove();
1484    
1485                                    break;
1486                            }
1487                    }
1488            }
1489    
1490            public static void removeRecentDDMTemplate(
1491                    PortletRequest portletRequest, String ddmTemplateKey) {
1492    
1493                    Stack<DDMTemplate> stack = getRecentDDMTemplates(portletRequest);
1494    
1495                    Iterator<DDMTemplate> itr = stack.iterator();
1496    
1497                    while (itr.hasNext()) {
1498                            DDMTemplate ddmTemplate = itr.next();
1499    
1500                            if (ddmTemplateKey.equals(ddmTemplate.getTemplateKey())) {
1501                                    itr.remove();
1502    
1503                                    break;
1504                            }
1505                    }
1506            }
1507    
1508            public static String transform(
1509                            ThemeDisplay themeDisplay, Map<String, String> tokens,
1510                            String viewMode, String languageId, Document document,
1511                            PortletRequestModel portletRequestModel, String script,
1512                            String langType)
1513                    throws Exception {
1514    
1515                    return _transformer.transform(
1516                            themeDisplay, tokens, viewMode, languageId, document,
1517                            portletRequestModel, script, langType);
1518            }
1519    
1520            private static void _addElementOptions(
1521                    Element curContentElement, Element newContentElement) {
1522    
1523                    List<Element> newElementOptions = newContentElement.elements("option");
1524    
1525                    for (Element newElementOption : newElementOptions) {
1526                            Element curElementOption = SAXReaderUtil.createElement("option");
1527    
1528                            curElementOption.addCDATA(newElementOption.getText());
1529    
1530                            curContentElement.add(curElementOption);
1531                    }
1532            }
1533    
1534            private static Element _getElementByInstanceId(
1535                    Document document, String instanceId) {
1536    
1537                    if (Validator.isNull(instanceId)) {
1538                            return null;
1539                    }
1540    
1541                    XPath xPathSelector = SAXReaderUtil.createXPath(
1542                            "//dynamic-element[@instance-id=" +
1543                                    HtmlUtil.escapeXPathAttribute(instanceId) + "]");
1544    
1545                    List<Node> nodes = xPathSelector.selectNodes(document);
1546    
1547                    if (nodes.size() == 1) {
1548                            return (Element)nodes.get(0);
1549                    }
1550                    else {
1551                            return null;
1552                    }
1553            }
1554    
1555            private static void _mergeArticleContentDelete(
1556                            Element curParentElement, Document newDocument)
1557                    throws Exception {
1558    
1559                    List<Element> curElements = curParentElement.elements(
1560                            "dynamic-element");
1561    
1562                    for (int i = 0; i < curElements.size(); i++) {
1563                            Element curElement = curElements.get(i);
1564    
1565                            _mergeArticleContentDelete(curElement, newDocument);
1566    
1567                            String instanceId = curElement.attributeValue("instance-id");
1568    
1569                            Element newElement = _getElementByInstanceId(
1570                                    newDocument, instanceId);
1571    
1572                            if (newElement == null) {
1573                                    curElement.detach();
1574                            }
1575                    }
1576            }
1577    
1578            private static void _mergeArticleContentUpdate(
1579                            Document curDocument, Element newParentElement, Element newElement,
1580                            int pos, String defaultLocale)
1581                    throws Exception {
1582    
1583                    _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1584    
1585                    String instanceId = newElement.attributeValue("instance-id");
1586    
1587                    Element curElement = _getElementByInstanceId(curDocument, instanceId);
1588    
1589                    if (curElement != null) {
1590                            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1591                    }
1592                    else {
1593                            String parentInstanceId = newParentElement.attributeValue(
1594                                    "instance-id");
1595    
1596                            if (Validator.isNull(parentInstanceId)) {
1597                                    Element curRoot = curDocument.getRootElement();
1598    
1599                                    List<Element> curRootElements = curRoot.elements();
1600    
1601                                    curRootElements.add(pos, newElement.createCopy());
1602                            }
1603                            else {
1604                                    Element curParentElement = _getElementByInstanceId(
1605                                            curDocument, parentInstanceId);
1606    
1607                                    if (curParentElement != null) {
1608                                            List<Element> curParentElements =
1609                                                    curParentElement.elements();
1610    
1611                                            curParentElements.add(pos, newElement.createCopy());
1612                                    }
1613                            }
1614                    }
1615            }
1616    
1617            private static void _mergeArticleContentUpdate(
1618                            Document curDocument, Element newParentElement,
1619                            String defaultLocale)
1620                    throws Exception {
1621    
1622                    List<Element> newElements = newParentElement.elements(
1623                            "dynamic-element");
1624    
1625                    for (int i = 0; i < newElements.size(); i++) {
1626                            Element newElement = newElements.get(i);
1627    
1628                            _mergeArticleContentUpdate(
1629                                    curDocument, newParentElement, newElement, i, defaultLocale);
1630                    }
1631            }
1632    
1633            private static void _mergeArticleContentUpdate(
1634                    Element curElement, Element newElement, String defaultLocale) {
1635    
1636                    Attribute curTypeAttribute = curElement.attribute("type");
1637                    Attribute newTypeAttribute = newElement.attribute("type");
1638    
1639                    curTypeAttribute.setValue(newTypeAttribute.getValue());
1640    
1641                    Attribute curIndexTypeAttribute = curElement.attribute("index-type");
1642                    Attribute newIndexTypeAttribute = newElement.attribute("index-type");
1643    
1644                    if (newIndexTypeAttribute != null) {
1645                            if (curIndexTypeAttribute == null) {
1646                                    curElement.addAttribute(
1647                                            "index-type", newIndexTypeAttribute.getValue());
1648                            }
1649                            else {
1650                                    curIndexTypeAttribute.setValue(
1651                                            newIndexTypeAttribute.getValue());
1652                            }
1653                    }
1654    
1655                    List<Element> elements = newElement.elements("dynamic-content");
1656    
1657                    Element newContentElement = elements.get(0);
1658    
1659                    String newLanguageId = newContentElement.attributeValue("language-id");
1660                    String newValue = newContentElement.getText();
1661    
1662                    String indexType = newElement.attributeValue("index-type");
1663    
1664                    if (Validator.isNotNull(indexType)) {
1665                            curElement.addAttribute("index-type", indexType);
1666                    }
1667    
1668                    List<Element> curContentElements = curElement.elements(
1669                            "dynamic-content");
1670    
1671                    if (Validator.isNull(newLanguageId)) {
1672                            for (Element curContentElement : curContentElements) {
1673                                    curContentElement.detach();
1674                            }
1675    
1676                            Element curContentElement = SAXReaderUtil.createElement(
1677                                    "dynamic-content");
1678    
1679                            if (newContentElement.element("option") != null) {
1680                                    _addElementOptions(curContentElement, newContentElement);
1681                            }
1682                            else {
1683                                    curContentElement.addCDATA(newValue);
1684                            }
1685    
1686                            curElement.add(curContentElement);
1687                    }
1688                    else {
1689                            boolean alreadyExists = false;
1690    
1691                            for (Element curContentElement : curContentElements) {
1692                                    String curLanguageId = curContentElement.attributeValue(
1693                                            "language-id");
1694    
1695                                    if (newLanguageId.equals(curLanguageId)) {
1696                                            alreadyExists = true;
1697    
1698                                            curContentElement.clearContent();
1699    
1700                                            if (newContentElement.element("option") != null) {
1701                                                    _addElementOptions(
1702                                                            curContentElement, newContentElement);
1703                                            }
1704                                            else {
1705                                                    curContentElement.addCDATA(newValue);
1706                                            }
1707    
1708                                            break;
1709                                    }
1710                            }
1711    
1712                            if (!alreadyExists) {
1713                                    Element curContentElement = curContentElements.get(0);
1714    
1715                                    String curLanguageId = curContentElement.attributeValue(
1716                                            "language-id");
1717    
1718                                    if (Validator.isNull(curLanguageId)) {
1719                                            if (newLanguageId.equals(defaultLocale)) {
1720                                                    curContentElement.clearContent();
1721    
1722                                                    if (newContentElement.element("option") != null) {
1723                                                            _addElementOptions(
1724                                                                    curContentElement, newContentElement);
1725                                                    }
1726                                                    else {
1727                                                            curContentElement.addCDATA(newValue);
1728                                                    }
1729                                            }
1730                                            else {
1731                                                    curElement.add(newContentElement.createCopy());
1732                                            }
1733    
1734                                            curContentElement.addAttribute(
1735                                                    "language-id", defaultLocale);
1736                                    }
1737                                    else {
1738                                            curElement.add(newContentElement.createCopy());
1739                                    }
1740                            }
1741                    }
1742            }
1743    
1744            private static void _populateCustomTokens(Map<String, String> tokens) {
1745                    if (_customTokens == null) {
1746                            synchronized (JournalUtil.class) {
1747                                    _customTokens = new HashMap<String, String>();
1748    
1749                                    for (String customToken :
1750                                                    PropsValues.JOURNAL_ARTICLE_CUSTOM_TOKENS) {
1751    
1752                                            String value = PropsUtil.get(
1753                                                    PropsKeys.JOURNAL_ARTICLE_CUSTOM_TOKEN_VALUE,
1754                                                    new Filter(customToken));
1755    
1756                                            _customTokens.put(customToken, value);
1757                                    }
1758                            }
1759                    }
1760    
1761                    if (!_customTokens.isEmpty()) {
1762                            tokens.putAll(_customTokens);
1763                    }
1764            }
1765    
1766            private static void _populateTokens(
1767                            Map<String, String> tokens, long articleGroupId,
1768                            ThemeDisplay themeDisplay)
1769                    throws PortalException {
1770    
1771                    Layout layout = themeDisplay.getLayout();
1772    
1773                    Group group = layout.getGroup();
1774    
1775                    LayoutSet layoutSet = layout.getLayoutSet();
1776    
1777                    String friendlyUrlCurrent = null;
1778    
1779                    if (layout.isPublicLayout()) {
1780                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1781                    }
1782                    else if (group.isUserGroup()) {
1783                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1784                    }
1785                    else {
1786                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1787                    }
1788    
1789                    String layoutSetFriendlyUrl = themeDisplay.getI18nPath();
1790    
1791                    String virtualHostname = layoutSet.getVirtualHostname();
1792    
1793                    if (Validator.isNull(virtualHostname) ||
1794                            !virtualHostname.equals(themeDisplay.getServerName())) {
1795    
1796                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1797                    }
1798    
1799                    tokens.put("article_group_id", String.valueOf(articleGroupId));
1800                    tokens.put("cdn_host", themeDisplay.getCDNHost());
1801                    tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1802                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1803                    tokens.put(
1804                            "friendly_url_private_group",
1805                            themeDisplay.getPathFriendlyURLPrivateGroup());
1806                    tokens.put(
1807                            "friendly_url_private_user",
1808                            themeDisplay.getPathFriendlyURLPrivateUser());
1809                    tokens.put(
1810                            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1811                    tokens.put("group_friendly_url", group.getFriendlyURL());
1812                    tokens.put("image_path", themeDisplay.getPathImage());
1813                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1814                    tokens.put("main_path", themeDisplay.getPathMain());
1815                    tokens.put("portal_ctx", themeDisplay.getPathContext());
1816                    tokens.put(
1817                            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1818                    tokens.put(
1819                            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1820                    tokens.put("root_path", themeDisplay.getPathContext());
1821                    tokens.put(
1822                            "site_group_id", String.valueOf(themeDisplay.getSiteGroupId()));
1823                    tokens.put(
1824                            "scope_group_id", String.valueOf(themeDisplay.getScopeGroupId()));
1825                    tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1826    
1827                    _populateCustomTokens(tokens);
1828    
1829                    // Deprecated tokens
1830    
1831                    tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1832                    tokens.put(
1833                            "friendly_url_private",
1834                            themeDisplay.getPathFriendlyURLPrivateGroup());
1835                    tokens.put("group_id", String.valueOf(articleGroupId));
1836                    tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1837            }
1838    
1839            private static void _populateTokens(
1840                            Map<String, String> tokens, long articleGroupId,
1841                            ThemeDisplayModel themeDisplayModel)
1842                    throws Exception {
1843    
1844                    Layout layout = LayoutLocalServiceUtil.getLayout(
1845                            themeDisplayModel.getPlid());
1846    
1847                    Group group = layout.getGroup();
1848    
1849                    LayoutSet layoutSet = layout.getLayoutSet();
1850    
1851                    String friendlyUrlCurrent = null;
1852    
1853                    if (layout.isPublicLayout()) {
1854                            friendlyUrlCurrent = themeDisplayModel.getPathFriendlyURLPublic();
1855                    }
1856                    else if (group.isUserGroup()) {
1857                            friendlyUrlCurrent =
1858                                    themeDisplayModel.getPathFriendlyURLPrivateUser();
1859                    }
1860                    else {
1861                            friendlyUrlCurrent =
1862                                    themeDisplayModel.getPathFriendlyURLPrivateGroup();
1863                    }
1864    
1865                    String layoutSetFriendlyUrl = themeDisplayModel.getI18nPath();
1866    
1867                    String virtualHostname = layoutSet.getVirtualHostname();
1868    
1869                    if (Validator.isNull(virtualHostname) ||
1870                            !virtualHostname.equals(themeDisplayModel.getServerName())) {
1871    
1872                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1873                    }
1874    
1875                    tokens.put("article_group_id", String.valueOf(articleGroupId));
1876                    tokens.put("cdn_host", themeDisplayModel.getCdnHost());
1877                    tokens.put(
1878                            "company_id", String.valueOf(themeDisplayModel.getCompanyId()));
1879                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1880                    tokens.put(
1881                            "friendly_url_private_group",
1882                            themeDisplayModel.getPathFriendlyURLPrivateGroup());
1883                    tokens.put(
1884                            "friendly_url_private_user",
1885                            themeDisplayModel.getPathFriendlyURLPrivateUser());
1886                    tokens.put(
1887                            "friendly_url_public",
1888                            themeDisplayModel.getPathFriendlyURLPublic());
1889                    tokens.put("group_friendly_url", group.getFriendlyURL());
1890                    tokens.put("image_path", themeDisplayModel.getPathImage());
1891                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1892                    tokens.put("main_path", themeDisplayModel.getPathMain());
1893                    tokens.put("portal_ctx", themeDisplayModel.getPathContext());
1894                    tokens.put(
1895                            "portal_url",
1896                            HttpUtil.removeProtocol(themeDisplayModel.getURLPortal()));
1897                    tokens.put(
1898                            "protocol", HttpUtil.getProtocol(themeDisplayModel.getURLPortal()));
1899                    tokens.put("root_path", themeDisplayModel.getPathContext());
1900                    tokens.put(
1901                            "scope_group_id",
1902                            String.valueOf(themeDisplayModel.getScopeGroupId()));
1903                    tokens.put("theme_image_path", themeDisplayModel.getPathThemeImages());
1904    
1905                    _populateCustomTokens(tokens);
1906    
1907                    // Deprecated tokens
1908    
1909                    tokens.put(
1910                            "friendly_url", themeDisplayModel.getPathFriendlyURLPublic());
1911                    tokens.put(
1912                            "friendly_url_private",
1913                            themeDisplayModel.getPathFriendlyURLPrivateGroup());
1914                    tokens.put("group_id", String.valueOf(articleGroupId));
1915                    tokens.put("page_url", themeDisplayModel.getPathFriendlyURLPublic());
1916            }
1917    
1918            private static void _removeOldContent(
1919                    Stack<String> path, Element contentElement, Document xsdDocument) {
1920    
1921                    String elementPath = "";
1922    
1923                    for (int i = 0; i < path.size(); i++) {
1924                            elementPath += "/" + path.elementAt(i);
1925                    }
1926    
1927                    for (int i = 0; i < contentElement.nodeCount(); i++) {
1928                            Node contentNode = contentElement.node(i);
1929    
1930                            if (contentNode instanceof Element) {
1931                                    _removeOldContent(
1932                                            path, (Element)contentNode, xsdDocument, elementPath);
1933                            }
1934                    }
1935            }
1936    
1937            private static void _removeOldContent(
1938                    Stack<String> path, Element contentElement, Document xsdDocument,
1939                    String elementPath) {
1940    
1941                    String name = contentElement.attributeValue("name");
1942    
1943                    if (Validator.isNull(name)) {
1944                            return;
1945                    }
1946    
1947                    String localPath =
1948                            "dynamic-element[@name=" + HtmlUtil.escapeXPathAttribute(name) +
1949                                    "]";
1950    
1951                    String fullPath = elementPath + "/" + localPath;
1952    
1953                    XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1954    
1955                    List<Node> curNodes = xPathSelector.selectNodes(xsdDocument);
1956    
1957                    if (curNodes.isEmpty()) {
1958                            contentElement.detach();
1959                    }
1960    
1961                    path.push(localPath);
1962    
1963                    _removeOldContent(path, contentElement, xsdDocument);
1964    
1965                    path.pop();
1966            }
1967    
1968            private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1969    
1970            private static Map<String, String> _customTokens;
1971            private static Pattern _friendlyURLPattern = Pattern.compile("[^a-z0-9_-]");
1972            private static Transformer _transformer = new Transformer(
1973                    PropsKeys.JOURNAL_TRANSFORMER_LISTENER,
1974                    PropsKeys.JOURNAL_ERROR_TEMPLATE, true);
1975    
1976    }