com.liferay.journal.util.impl.JournalUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.journal.util.impl.JournalUtil.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.journal.util.impl;

import com.liferay.asset.kernel.service.AssetTagLocalServiceUtil;
import com.liferay.dynamic.data.mapping.model.DDMStructure;
import com.liferay.dynamic.data.mapping.model.DDMTemplate;
import com.liferay.dynamic.data.mapping.service.DDMTemplateLocalServiceUtil;
import com.liferay.journal.configuration.JournalGroupServiceConfiguration;
import com.liferay.journal.configuration.JournalServiceConfiguration;
import com.liferay.journal.model.JournalArticle;
import com.liferay.journal.model.JournalArticleDisplay;
import com.liferay.journal.model.JournalFolder;
import com.liferay.journal.model.JournalFolderConstants;
import com.liferay.journal.model.JournalStructureConstants;
import com.liferay.journal.service.JournalArticleLocalServiceUtil;
import com.liferay.journal.service.JournalArticleServiceUtil;
import com.liferay.journal.service.JournalFolderLocalServiceUtil;
import com.liferay.journal.transformer.JournalTransformer;
import com.liferay.journal.transformer.JournalTransformerListenerRegistryUtil;
import com.liferay.journal.util.comparator.ArticleVersionComparator;
import com.liferay.petra.collection.stack.FiniteUniqueStack;
import com.liferay.petra.xml.XMLUtil;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.diff.CompareVersionsException;
import com.liferay.portal.kernel.diff.DiffHtmlUtil;
import com.liferay.portal.kernel.diff.DiffVersion;
import com.liferay.portal.kernel.diff.DiffVersionsInfo;
import com.liferay.portal.kernel.exception.LocaleException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Company;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.model.Layout;
import com.liferay.portal.kernel.model.LayoutConstants;
import com.liferay.portal.kernel.model.LayoutSet;
import com.liferay.portal.kernel.model.ModelHintsUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.module.configuration.ConfigurationProviderUtil;
import com.liferay.portal.kernel.portlet.PortletProvider;
import com.liferay.portal.kernel.portlet.PortletProviderUtil;
import com.liferay.portal.kernel.portlet.PortletRequestModel;
import com.liferay.portal.kernel.portlet.ThemeDisplayModel;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.Hits;
import com.liferay.portal.kernel.search.Indexer;
import com.liferay.portal.kernel.search.IndexerRegistryUtil;
import com.liferay.portal.kernel.service.ImageLocalServiceUtil;
import com.liferay.portal.kernel.service.LayoutLocalServiceUtil;
import com.liferay.portal.kernel.service.SubscriptionLocalServiceUtil;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import com.liferay.portal.kernel.template.TemplateHandler;
import com.liferay.portal.kernel.template.TemplateHandlerRegistryUtil;
import com.liferay.portal.kernel.template.TemplateManager;
import com.liferay.portal.kernel.template.TemplateManagerUtil;
import com.liferay.portal.kernel.templateparser.TransformerListener;
import com.liferay.portal.kernel.theme.PortletDisplay;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.Constants;
import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HtmlUtil;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.MapUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.kernel.webserver.WebServerServletTokenUtil;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.xml.Attribute;
import com.liferay.portal.kernel.xml.Document;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.kernel.xml.Node;
import com.liferay.portal.kernel.xml.SAXReaderUtil;
import com.liferay.portal.kernel.xml.XPath;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;

import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.PortletURL;

/**
 * @author Brian Wing Shun Chan
 * @author Raymond Aug
 * @author Wesley Gong
 * @author Angelo Jefferson
 * @author Hugo Huijser
 */
public class JournalUtil {

    public static final int MAX_STACK_SIZE = 20;

    public static final String[] SELECTED_FIELD_NAMES = { Field.ARTICLE_ID, Field.COMPANY_ID, Field.GROUP_ID,
            Field.UID };

    public static void addAllReservedEls(Element rootElement, Map<String, String> tokens, JournalArticle article,
            String languageId, ThemeDisplay themeDisplay) {

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_ID, article.getArticleId());

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_VERSION,
                article.getVersion());

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_TITLE,
                article.getTitle(languageId));

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_URL_TITLE,
                article.getUrlTitle());

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_DESCRIPTION,
                article.getDescription(languageId));

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_CREATE_DATE,
                article.getCreateDate());

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_MODIFIED_DATE,
                article.getModifiedDate());

        if (article.getDisplayDate() != null) {
            addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_DISPLAY_DATE,
                    article.getDisplayDate());
        }

        String smallImageURL = StringPool.BLANK;

        if (Validator.isNotNull(article.getSmallImageURL())) {
            smallImageURL = article.getSmallImageURL();
        } else if ((themeDisplay != null) && article.isSmallImage()) {
            StringBundler sb = new StringBundler(5);

            sb.append(themeDisplay.getPathImage());
            sb.append("/journal/article?img_id=");
            sb.append(article.getSmallImageId());
            sb.append("&t=");
            sb.append(WebServerServletTokenUtil.getToken(article.getSmallImageId()));

            smallImageURL = sb.toString();
        }

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_SMALL_IMAGE_URL,
                smallImageURL);

        String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(JournalArticle.class.getName(),
                article.getResourcePrimKey());

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_ASSET_TAG_NAMES,
                StringUtil.merge(assetTagNames));

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_ID,
                String.valueOf(article.getUserId()));

        String userName = StringPool.BLANK;
        String userEmailAddress = StringPool.BLANK;
        String userComments = StringPool.BLANK;
        String userJobTitle = StringPool.BLANK;

        User user = UserLocalServiceUtil.fetchUserById(article.getUserId());

        if (user != null) {
            userName = user.getFullName();
            userEmailAddress = user.getEmailAddress();
            userComments = user.getComments();
            userJobTitle = user.getJobTitle();
        }

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_NAME, userName);

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_EMAIL_ADDRESS,
                userEmailAddress);

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_COMMENTS,
                userComments);

        addReservedEl(rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_JOB_TITLE,
                userJobTitle);
    }

    public static void addRecentArticle(PortletRequest portletRequest, JournalArticle article) {

        if (article != null) {
            Stack<JournalArticle> stack = getRecentArticles(portletRequest);

            stack.push(article);
        }
    }

    public static void addRecentDDMStructure(PortletRequest portletRequest, DDMStructure ddmStructure) {

        if (ddmStructure != null) {
            Stack<DDMStructure> stack = getRecentDDMStructures(portletRequest);

            stack.push(ddmStructure);
        }
    }

    public static void addRecentDDMTemplate(PortletRequest portletRequest, DDMTemplate ddmTemplate) {

        if (ddmTemplate != null) {
            Stack<DDMTemplate> stack = getRecentDDMTemplates(portletRequest);

            stack.push(ddmTemplate);
        }
    }

    public static void addReservedEl(Element rootElement, Map<String, String> tokens, String name, Date value) {

        addReservedEl(rootElement, tokens, name, Time.getRFC822(value));
    }

    public static void addReservedEl(Element rootElement, Map<String, String> tokens, String name, double value) {

        addReservedEl(rootElement, tokens, name, String.valueOf(value));
    }

    public static void addReservedEl(Element rootElement, Map<String, String> tokens, String name, String value) {

        // XML

        if (rootElement != null) {
            Element dynamicElementElement = rootElement.addElement("dynamic-element");

            dynamicElementElement.addAttribute("name", name);

            dynamicElementElement.addAttribute("type", "text");

            Element dynamicContentElement = dynamicElementElement.addElement("dynamic-content");

            //dynamicContentElement.setText("<![CDATA[" + value + "]]>");
            dynamicContentElement.setText(value);
        }

        // Tokens

        tokens.put(StringUtil.replace(name, CharPool.DASH, CharPool.UNDERLINE), value);
    }

    public static String diffHtml(long groupId, String articleId, double sourceVersion, double targetVersion,
            String languageId, PortletRequestModel portletRequestModel, ThemeDisplay themeDisplay)
            throws Exception {

        JournalArticle sourceArticle = JournalArticleLocalServiceUtil.getArticle(groupId, articleId, sourceVersion);

        if (!JournalArticleLocalServiceUtil.isRenderable(sourceArticle, portletRequestModel, themeDisplay)) {

            throw new CompareVersionsException(sourceVersion);
        }

        JournalArticleDisplay sourceArticleDisplay = JournalArticleLocalServiceUtil.getArticleDisplay(sourceArticle,
                null, Constants.VIEW, languageId, 1, portletRequestModel, themeDisplay);

        JournalArticle targetArticle = JournalArticleLocalServiceUtil.getArticle(groupId, articleId, targetVersion);

        if (!JournalArticleLocalServiceUtil.isRenderable(targetArticle, portletRequestModel, themeDisplay)) {

            throw new CompareVersionsException(targetVersion);
        }

        JournalArticleDisplay targetArticleDisplay = JournalArticleLocalServiceUtil.getArticleDisplay(targetArticle,
                null, Constants.VIEW, languageId, 1, portletRequestModel, themeDisplay);

        return DiffHtmlUtil.diff(new UnsyncStringReader(sourceArticleDisplay.getContent()),
                new UnsyncStringReader(targetArticleDisplay.getContent()));
    }

    public static String formatVM(String vm) {
        return vm;
    }

    public static String getAbsolutePath(PortletRequest portletRequest, long folderId) throws PortalException {

        ThemeDisplay themeDisplay = (ThemeDisplay) portletRequest.getAttribute(WebKeys.THEME_DISPLAY);

        if (folderId == JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
            return themeDisplay.translate("home");
        }

        JournalFolder folder = JournalFolderLocalServiceUtil.getFolder(folderId);

        List<JournalFolder> folders = folder.getAncestors();

        Collections.reverse(folders);

        StringBundler sb = new StringBundler((folders.size() * 3) + 5);

        sb.append(themeDisplay.translate("home"));
        sb.append(StringPool.SPACE);

        for (JournalFolder curFolder : folders) {
            sb.append(StringPool.RAQUO_CHAR);
            sb.append(StringPool.SPACE);
            sb.append(curFolder.getName());
        }

        sb.append(StringPool.RAQUO_CHAR);
        sb.append(StringPool.SPACE);
        sb.append(folder.getName());

        return sb.toString();
    }

    public static Layout getArticleLayout(String layoutUuid, long groupId) {
        if (Validator.isNull(layoutUuid)) {
            return null;
        }

        // The target page and the article must belong to the same group

        Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(layoutUuid, groupId, false);

        if (layout == null) {
            layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(layoutUuid, groupId, true);
        }

        return layout;
    }

    /**
     * @deprecated As of 4.0.0, with no direct replacement
     */
    @Deprecated
    public static List<JournalArticle> getArticles(Hits hits) throws PortalException {

        List<com.liferay.portal.kernel.search.Document> documents = hits.toList();

        List<JournalArticle> articles = new ArrayList<>(documents.size());

        for (com.liferay.portal.kernel.search.Document document : documents) {
            String articleId = document.get(Field.ARTICLE_ID);
            long groupId = GetterUtil.getLong(document.get(Field.SCOPE_GROUP_ID));

            JournalArticle article = JournalArticleLocalServiceUtil.fetchLatestArticle(groupId, articleId,
                    WorkflowConstants.STATUS_APPROVED);

            if (article == null) {
                articles = null;

                Indexer<JournalArticle> indexer = IndexerRegistryUtil.getIndexer(JournalArticle.class);

                long companyId = GetterUtil.getLong(document.get(Field.COMPANY_ID));

                indexer.delete(companyId, document.getUID());
            } else if (articles != null) {
                articles.add(article);
            }
        }

        return articles;
    }

    public static DiffVersionsInfo getDiffVersionsInfo(long groupId, String articleId, double sourceVersion,
            double targetVersion) {

        double previousVersion = 0;
        double nextVersion = 0;

        List<JournalArticle> articles = JournalArticleServiceUtil.getArticlesByArticleId(groupId, articleId,
                QueryUtil.ALL_POS, QueryUtil.ALL_POS, new ArticleVersionComparator(true));

        for (JournalArticle article : articles) {
            if ((article.getVersion() < sourceVersion) && (article.getVersion() > previousVersion)) {

                previousVersion = article.getVersion();
            }

            if ((article.getVersion() > targetVersion)
                    && ((article.getVersion() < nextVersion) || (nextVersion == 0))) {

                nextVersion = article.getVersion();
            }
        }

        List<DiffVersion> diffVersions = new ArrayList<>();

        for (JournalArticle article : articles) {
            DiffVersion diffVersion = new DiffVersion(article.getUserId(), article.getVersion(),
                    article.getModifiedDate());

            diffVersions.add(diffVersion);
        }

        return new DiffVersionsInfo(diffVersions, nextVersion, previousVersion);
    }

    public static boolean getEmailArticleAnyEventEnabled(
            JournalGroupServiceConfiguration journalGroupServiceConfiguration) {

        if (journalGroupServiceConfiguration.emailArticleAddedEnabled()
                || journalGroupServiceConfiguration.emailArticleApprovalDeniedEnabled()
                || journalGroupServiceConfiguration.emailArticleApprovalGrantedEnabled()
                || journalGroupServiceConfiguration.emailArticleApprovalRequestedEnabled()
                || journalGroupServiceConfiguration.emailArticleReviewEnabled()
                || journalGroupServiceConfiguration.emailArticleUpdatedEnabled()) {

            return true;
        }

        return false;
    }

    public static Map<String, String> getEmailDefinitionTerms(PortletRequest portletRequest,
            String emailFromAddress, String emailFromName) {

        return getEmailDefinitionTerms(portletRequest, emailFromAddress, emailFromName, StringPool.BLANK);
    }

    public static Map<String, String> getEmailDefinitionTerms(PortletRequest portletRequest,
            String emailFromAddress, String emailFromName, String emailType) {

        ThemeDisplay themeDisplay = (ThemeDisplay) portletRequest.getAttribute(WebKeys.THEME_DISPLAY);

        String fromAddress = HtmlUtil.escape(emailFromAddress);
        String fromName = HtmlUtil.escape(emailFromName);
        String toAddress = LanguageUtil.get(themeDisplay.getLocale(), "the-address-of-the-email-recipient");
        String toName = LanguageUtil.get(themeDisplay.getLocale(), "the-name-of-the-email-recipient");

        if (emailType.equals("requested")) {
            toName = fromName;
            toAddress = fromAddress;

            fromName = LanguageUtil.get(themeDisplay.getLocale(), "the-name-of-the-email-sender");
            fromAddress = LanguageUtil.get(themeDisplay.getLocale(), "the-address-of-the-email-sender");
        }

        Map<String, String> definitionTerms = new LinkedHashMap<>();

        definitionTerms.put("[$ARTICLE_CONTENT]", LanguageUtil.get(themeDisplay.getLocale(), "the-web-content"));
        definitionTerms.put("[$ARTICLE_DIFFS$]", LanguageUtil.get(themeDisplay.getLocale(),
                "the-web-content-compared-with-the-previous-version-web-" + "content"));
        definitionTerms.put("[$ARTICLE_ID$]", LanguageUtil.get(themeDisplay.getLocale(), "the-web-content-id"));
        definitionTerms.put("[$ARTICLE_TITLE$]",
                LanguageUtil.get(themeDisplay.getLocale(), "the-web-content-title"));
        definitionTerms.put("[$ARTICLE_URL$]", LanguageUtil.get(themeDisplay.getLocale(), "the-web-content-url"));
        definitionTerms.put("[$ARTICLE_VERSION$]",
                LanguageUtil.get(themeDisplay.getLocale(), "the-web-content-version"));
        definitionTerms.put("[$FROM_ADDRESS$]", fromAddress);
        definitionTerms.put("[$FROM_NAME$]", fromName);

        Company company = themeDisplay.getCompany();

        definitionTerms.put("[$PORTAL_URL$]", company.getVirtualHostname());

        PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();

        definitionTerms.put("[$PORTLET_NAME$]", HtmlUtil.escape(portletDisplay.getTitle()));

        definitionTerms.put("[$TO_ADDRESS$]", toAddress);
        definitionTerms.put("[$TO_NAME$]", toName);

        return definitionTerms;
    }

    public static String getJournalControlPanelLink(PortletRequest portletRequest, long folderId)
            throws PortalException {

        PortletURL portletURL = PortletProviderUtil.getPortletURL(portletRequest, JournalArticle.class.getName(),
                PortletProvider.Action.EDIT);

        portletURL.setParameter("folderId", String.valueOf(folderId));

        return portletURL.toString();
    }

    public static long getPreviewPlid(JournalArticle article, ThemeDisplay themeDisplay) throws Exception {

        if (article != null) {
            Layout layout = article.getLayout();

            if (layout != null) {
                return layout.getPlid();
            }
        }

        Layout layout = LayoutLocalServiceUtil.fetchFirstLayout(themeDisplay.getScopeGroupId(), false,
                LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);

        if (layout == null) {
            layout = LayoutLocalServiceUtil.fetchFirstLayout(themeDisplay.getScopeGroupId(), true,
                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
        }

        if (layout != null) {
            return layout.getPlid();
        }

        return themeDisplay.getPlid();
    }

    public static Stack<JournalArticle> getRecentArticles(PortletRequest portletRequest) {

        PortletSession portletSession = portletRequest.getPortletSession();

        Stack<JournalArticle> recentArticles = (Stack<JournalArticle>) portletSession
                .getAttribute(WebKeys.JOURNAL_RECENT_ARTICLES);

        if (recentArticles == null) {
            recentArticles = new FiniteUniqueStack<>(MAX_STACK_SIZE);

            portletSession.setAttribute(WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
        }

        return recentArticles;
    }

    public static Stack<DDMStructure> getRecentDDMStructures(PortletRequest portletRequest) {

        PortletSession portletSession = portletRequest.getPortletSession();

        Stack<DDMStructure> recentDDMStructures = (Stack<DDMStructure>) portletSession
                .getAttribute(WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_STRUCTURES);

        if (recentDDMStructures == null) {
            recentDDMStructures = new FiniteUniqueStack<>(MAX_STACK_SIZE);

            portletSession.setAttribute(WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_STRUCTURES,
                    recentDDMStructures);
        }

        return recentDDMStructures;
    }

    public static Stack<DDMTemplate> getRecentDDMTemplates(PortletRequest portletRequest) {

        PortletSession portletSession = portletRequest.getPortletSession();

        Stack<DDMTemplate> recentDDMTemplates = (Stack<DDMTemplate>) portletSession
                .getAttribute(WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_TEMPLATES);

        if (recentDDMTemplates == null) {
            recentDDMTemplates = new FiniteUniqueStack<>(MAX_STACK_SIZE);

            portletSession.setAttribute(WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_TEMPLATES, recentDDMTemplates);
        }

        return recentDDMTemplates;
    }

    public static int getRestrictionType(long folderId) {
        int restrictionType = JournalFolderConstants.RESTRICTION_TYPE_INHERIT;

        JournalFolder folder = JournalFolderLocalServiceUtil.fetchFolder(folderId);

        if (folder != null) {
            restrictionType = folder.getRestrictionType();
        }

        return restrictionType;
    }

    public static String getTemplateScript(DDMTemplate ddmTemplate, Map<String, String> tokens, String languageId,
            boolean transform) {

        String script = ddmTemplate.getScript();

        if (!transform) {
            return script;
        }

        for (TransformerListener transformerListener : JournalTransformerListenerRegistryUtil
                .getTransformerListeners()) {

            script = transformerListener.onScript(script, (Document) null, languageId, tokens);
        }

        return script;
    }

    public static String getTemplateScript(long groupId, String ddmTemplateKey, Map<String, String> tokens,
            String languageId) throws PortalException {

        return getTemplateScript(groupId, ddmTemplateKey, tokens, languageId, true);
    }

    public static String getTemplateScript(long groupId, String ddmTemplateKey, Map<String, String> tokens,
            String languageId, boolean transform) throws PortalException {

        DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(groupId,
                PortalUtil.getClassNameId(DDMStructure.class), ddmTemplateKey, true);

        return getTemplateScript(ddmTemplate, tokens, languageId, transform);
    }

    public static Map<String, String> getTokens(long articleGroupId, PortletRequestModel portletRequestModel,
            ThemeDisplay themeDisplay) throws PortalException {

        Map<String, String> tokens = new HashMap<>();

        if (themeDisplay != null) {
            _populateTokens(tokens, articleGroupId, themeDisplay);
        } else if (portletRequestModel != null) {
            ThemeDisplayModel themeDisplayModel = portletRequestModel.getThemeDisplayModel();

            if (themeDisplayModel != null) {
                try {
                    _populateTokens(tokens, articleGroupId, themeDisplayModel);
                } catch (Exception e) {
                    if (_log.isWarnEnabled()) {
                        _log.warn(e, e);
                    }
                }
            }
        }

        return tokens;
    }

    public static Map<String, String> getTokens(long articleGroupId, ThemeDisplay themeDisplay)
            throws PortalException {

        return getTokens(articleGroupId, (PortletRequestModel) null, themeDisplay);
    }

    public static String getUrlTitle(long id, String title) {
        if (title == null) {
            return String.valueOf(id);
        }

        title = StringUtil.toLowerCase(title.trim());

        if (Validator.isNull(title) || Validator.isNumber(title) || title.equals("rss")) {

            title = String.valueOf(id);
        } else {
            title = FriendlyURLNormalizerUtil.normalizeWithPeriodsAndSlashes(title);
        }

        return ModelHintsUtil.trimString(JournalArticle.class.getName(), "urlTitle", title);
    }

    public static boolean isHead(JournalArticle article) {
        JournalArticle latestArticle = JournalArticleLocalServiceUtil.fetchLatestArticle(
                article.getResourcePrimKey(),
                new int[] { WorkflowConstants.STATUS_APPROVED, WorkflowConstants.STATUS_IN_TRASH });

        if ((latestArticle != null) && !latestArticle.isIndexable()) {
            return false;
        } else if ((latestArticle != null) && (article.getId() == latestArticle.getId())) {

            return true;
        }

        return false;
    }

    public static boolean isHeadListable(JournalArticle article) {
        JournalArticle latestArticle = JournalArticleLocalServiceUtil
                .fetchLatestArticle(article.getResourcePrimKey(), new int[] { WorkflowConstants.STATUS_APPROVED,
                        WorkflowConstants.STATUS_IN_TRASH, WorkflowConstants.STATUS_SCHEDULED });

        if ((latestArticle != null) && (article.getId() == latestArticle.getId())) {

            return true;
        }

        return false;
    }

    public static boolean isSubscribedToFolder(long companyId, long groupId, long userId, long folderId)
            throws PortalException {

        return isSubscribedToFolder(companyId, groupId, userId, folderId, true);
    }

    public static boolean isSubscribedToFolder(long companyId, long groupId, long userId, long folderId,
            boolean recursive) throws PortalException {

        List<Long> ancestorFolderIds = new ArrayList<>();

        if (folderId != JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
            JournalFolder folder = JournalFolderLocalServiceUtil.getFolder(folderId);

            ancestorFolderIds.add(folderId);

            if (recursive) {
                ancestorFolderIds.addAll(folder.getAncestorFolderIds());

                ancestorFolderIds.add(groupId);
            }
        } else {
            ancestorFolderIds.add(groupId);
        }

        return SubscriptionLocalServiceUtil.isSubscribed(companyId, userId, JournalFolder.class.getName(),
                ArrayUtil.toLongArray(ancestorFolderIds));
    }

    public static boolean isSubscribedToStructure(long companyId, long groupId, long userId, long ddmStructureId) {

        return SubscriptionLocalServiceUtil.isSubscribed(companyId, userId, DDMStructure.class.getName(),
                ddmStructureId);
    }

    public static String mergeArticleContent(String curContent, String newContent, boolean removeNullElements) {

        try {
            Document curDocument = SAXReaderUtil.read(curContent);
            Document newDocument = SAXReaderUtil.read(newContent);

            Element curRootElement = curDocument.getRootElement();
            Element newRootElement = newDocument.getRootElement();

            curRootElement.addAttribute("default-locale", newRootElement.attributeValue("default-locale"));
            curRootElement.addAttribute("available-locales", newRootElement.attributeValue("available-locales"));

            _mergeArticleContentUpdate(curDocument, newRootElement,
                    LocaleUtil.toLanguageId(LocaleUtil.getSiteDefault()));

            if (removeNullElements) {
                _mergeArticleContentDelete(curRootElement, newDocument);
            }

            curContent = XMLUtil.formatXML(curDocument);
        } catch (Exception e) {
            _log.error(e, e);
        }

        return curContent;
    }

    public static String prepareLocalizedContentForImport(String content, Locale defaultImportLocale)
            throws LocaleException {

        try {
            Document oldDocument = SAXReaderUtil.read(content);

            Document newDocument = SAXReaderUtil.read(content);

            Element newRootElement = newDocument.getRootElement();

            Attribute availableLocalesAttribute = newRootElement.attribute("available-locales");

            if (availableLocalesAttribute == null) {
                newRootElement = newRootElement.addAttribute("available-locales", StringPool.BLANK);

                availableLocalesAttribute = newRootElement.attribute("available-locales");
            }

            String defaultImportLanguageId = LocaleUtil.toLanguageId(defaultImportLocale);

            if (!StringUtil.contains(availableLocalesAttribute.getValue(), defaultImportLanguageId)) {

                if (Validator.isNull(availableLocalesAttribute.getValue())) {
                    availableLocalesAttribute.setValue(defaultImportLanguageId);
                } else {
                    availableLocalesAttribute.setValue(
                            availableLocalesAttribute.getValue() + StringPool.COMMA + defaultImportLanguageId);
                }

                _mergeArticleContentUpdate(oldDocument, newRootElement,
                        LocaleUtil.toLanguageId(defaultImportLocale));

                content = XMLUtil.formatXML(newDocument);
            }

            Attribute defaultLocaleAttribute = newRootElement.attribute("default-locale");

            if (defaultLocaleAttribute == null) {
                newRootElement = newRootElement.addAttribute("default-locale", StringPool.BLANK);

                defaultLocaleAttribute = newRootElement.attribute("default-locale");
            }

            Locale defaultContentLocale = LocaleUtil.fromLanguageId(defaultLocaleAttribute.getValue());

            if (!LocaleUtil.equals(defaultContentLocale, defaultImportLocale)) {
                defaultLocaleAttribute.setValue(defaultImportLanguageId);

                content = XMLUtil.formatXML(newDocument);
            }
        } catch (Exception e) {
            throw new LocaleException(LocaleException.TYPE_CONTENT,
                    "The locale " + defaultImportLocale + " is not available");
        }

        return content;
    }

    public static String removeArticleLocale(Document document, String content, String languageId) {

        try {
            Element rootElement = document.getRootElement();

            String availableLocales = rootElement.attributeValue("available-locales");

            if (availableLocales == null) {
                return content;
            }

            availableLocales = StringUtil.removeFromList(availableLocales, languageId);

            if (availableLocales.endsWith(",")) {
                availableLocales = availableLocales.substring(0, availableLocales.length() - 1);
            }

            rootElement.addAttribute("available-locales", availableLocales);

            removeArticleLocale(rootElement, languageId);

            content = XMLUtil.formatXML(document);
        } catch (Exception e) {
            _log.error(e, e);
        }

        return content;
    }

    public static void removeArticleLocale(Element element, String languageId) throws PortalException {

        for (Element dynamicElementElement : element.elements("dynamic-element")) {

            for (Element dynamicContentElement : dynamicElementElement.elements("dynamic-content")) {

                String curLanguageId = GetterUtil.getString(dynamicContentElement.attributeValue("language-id"));

                if (curLanguageId.equals(languageId)) {
                    long id = GetterUtil.getLong(dynamicContentElement.attributeValue("id"));

                    if (id > 0) {
                        ImageLocalServiceUtil.deleteImage(id);
                    }

                    dynamicContentElement.detach();
                }
            }

            removeArticleLocale(dynamicElementElement, languageId);
        }
    }

    public static String removeOldContent(String content, String xsd) {
        try {
            Document contentDoc = SAXReaderUtil.read(content);
            Document xsdDoc = SAXReaderUtil.read(xsd);

            Element contentRoot = contentDoc.getRootElement();

            Stack<String> path = new Stack<>();

            path.push(contentRoot.getName());

            _removeOldContent(path, contentRoot, xsdDoc);

            content = XMLUtil.formatXML(contentDoc);
        } catch (Exception e) {
            _log.error(e, e);
        }

        return content;
    }

    public static void removeRecentArticle(PortletRequest portletRequest, String articleId) {

        removeRecentArticle(portletRequest, articleId, 0);
    }

    public static void removeRecentArticle(PortletRequest portletRequest, String articleId, double version) {

        Stack<JournalArticle> stack = getRecentArticles(portletRequest);

        Iterator<JournalArticle> itr = stack.iterator();

        while (itr.hasNext()) {
            JournalArticle journalArticle = itr.next();

            if (journalArticle.getArticleId().equals(articleId)
                    && ((journalArticle.getVersion() == version) || (version == 0))) {

                itr.remove();
            }
        }
    }

    public static void removeRecentDDMStructure(PortletRequest portletRequest, String ddmStructureKey) {

        Stack<DDMStructure> stack = getRecentDDMStructures(portletRequest);

        Iterator<DDMStructure> itr = stack.iterator();

        while (itr.hasNext()) {
            DDMStructure ddmStructure = itr.next();

            if (ddmStructureKey.equals(ddmStructure.getStructureKey())) {
                itr.remove();

                break;
            }
        }
    }

    public static void removeRecentDDMTemplate(PortletRequest portletRequest, String ddmTemplateKey) {

        Stack<DDMTemplate> stack = getRecentDDMTemplates(portletRequest);

        Iterator<DDMTemplate> itr = stack.iterator();

        while (itr.hasNext()) {
            DDMTemplate ddmTemplate = itr.next();

            if (ddmTemplateKey.equals(ddmTemplate.getTemplateKey())) {
                itr.remove();

                break;
            }
        }
    }

    public static String transform(ThemeDisplay themeDisplay, Map<String, String> tokens, String viewMode,
            String languageId, Document document, PortletRequestModel portletRequestModel, String script,
            String langType) throws Exception {

        return transform(themeDisplay, tokens, viewMode, languageId, document, portletRequestModel, script,
                langType, false);
    }

    public static String transform(ThemeDisplay themeDisplay, Map<String, String> tokens, String viewMode,
            String languageId, Document document, PortletRequestModel portletRequestModel, String script,
            String langType, boolean propagateException) throws Exception {

        TemplateManager templateManager = TemplateManagerUtil.getTemplateManager(langType);

        TemplateHandler templateHandler = TemplateHandlerRegistryUtil
                .getTemplateHandler(JournalArticle.class.getName());

        Map<String, Object> contextObjects = new HashMap<>();

        templateManager.addContextObjects(contextObjects, templateHandler.getCustomContextObjects());

        return _journalTransformer.transform(themeDisplay, contextObjects, tokens, viewMode, languageId, document,
                portletRequestModel, script, langType, propagateException);
    }

    private static void _addElementOptions(Element curContentElement, Element newContentElement) {

        List<Element> newElementOptions = newContentElement.elements("option");

        for (Element newElementOption : newElementOptions) {
            Element curElementOption = SAXReaderUtil.createElement("option");

            curElementOption.addCDATA(newElementOption.getText());

            curContentElement.add(curElementOption);
        }
    }

    private static String _getCustomTokenValue(String tokenName,
            JournalServiceConfiguration journalServiceConfiguration) {

        for (String tokenValue : journalServiceConfiguration.customTokenValues()) {

            String[] tokenValueParts = tokenValue.split("\\=");

            if (tokenValueParts.length != 2) {
                continue;
            }

            if (tokenValueParts[0].equals(tokenName)) {
                return tokenValueParts[1];
            }
        }

        return null;
    }

    private static Element _getElementByInstanceId(Document document, String instanceId) {

        if (Validator.isNull(instanceId)) {
            return null;
        }

        XPath xPathSelector = SAXReaderUtil
                .createXPath("//dynamic-element[@instance-id=" + HtmlUtil.escapeXPathAttribute(instanceId) + "]");

        List<Node> nodes = xPathSelector.selectNodes(document);

        if (nodes.size() == 1) {
            return (Element) nodes.get(0);
        } else {
            return null;
        }
    }

    private static void _mergeArticleContentDelete(Element curParentElement, Document newDocument)
            throws Exception {

        List<Element> curElements = curParentElement.elements("dynamic-element");

        for (int i = 0; i < curElements.size(); i++) {
            Element curElement = curElements.get(i);

            _mergeArticleContentDelete(curElement, newDocument);

            String instanceId = curElement.attributeValue("instance-id");

            Element newElement = _getElementByInstanceId(newDocument, instanceId);

            if (newElement == null) {
                curElement.detach();
            }
        }
    }

    private static void _mergeArticleContentUpdate(Document curDocument, Element newParentElement,
            Element newElement, int pos, String defaultLocale) throws Exception {

        _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);

        String instanceId = newElement.attributeValue("instance-id");

        Element curElement = _getElementByInstanceId(curDocument, instanceId);

        if (curElement != null) {
            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
        } else {
            String parentInstanceId = newParentElement.attributeValue("instance-id");

            if (Validator.isNull(parentInstanceId)) {
                Element curRoot = curDocument.getRootElement();

                List<Element> curRootElements = curRoot.elements();

                curRootElements.add(pos, newElement.createCopy());
            } else {
                Element curParentElement = _getElementByInstanceId(curDocument, parentInstanceId);

                if (curParentElement != null) {
                    List<Element> curParentElements = curParentElement.elements();

                    curParentElements.add(pos, newElement.createCopy());
                }
            }
        }
    }

    private static void _mergeArticleContentUpdate(Document curDocument, Element newParentElement,
            String defaultLocale) throws Exception {

        List<Element> newElements = newParentElement.elements("dynamic-element");

        for (int i = 0; i < newElements.size(); i++) {
            Element newElement = newElements.get(i);

            _mergeArticleContentUpdate(curDocument, newParentElement, newElement, i, defaultLocale);
        }
    }

    private static void _mergeArticleContentUpdate(Element curElement, Element newElement, String defaultLocale) {

        Attribute curTypeAttribute = curElement.attribute("type");
        Attribute newTypeAttribute = newElement.attribute("type");

        curTypeAttribute.setValue(newTypeAttribute.getValue());

        Attribute curIndexTypeAttribute = curElement.attribute("index-type");
        Attribute newIndexTypeAttribute = newElement.attribute("index-type");

        if (newIndexTypeAttribute != null) {
            if (curIndexTypeAttribute == null) {
                curElement.addAttribute("index-type", newIndexTypeAttribute.getValue());
            } else {
                curIndexTypeAttribute.setValue(newIndexTypeAttribute.getValue());
            }
        }

        List<Element> elements = newElement.elements("dynamic-content");

        if ((elements == null) || elements.isEmpty()) {
            return;
        }

        Element newContentElement = elements.get(0);

        String newLanguageId = newContentElement.attributeValue("language-id");
        String newValue = newContentElement.getText();

        String indexType = newElement.attributeValue("index-type");

        if (Validator.isNotNull(indexType)) {
            curElement.addAttribute("index-type", indexType);
        }

        List<Element> curContentElements = curElement.elements("dynamic-content");

        if (Validator.isNull(newLanguageId)) {
            for (Element curContentElement : curContentElements) {
                curContentElement.detach();
            }

            Element curContentElement = SAXReaderUtil.createElement("dynamic-content");

            if (newContentElement.element("option") != null) {
                _addElementOptions(curContentElement, newContentElement);
            } else {
                curContentElement.addCDATA(newValue);
            }

            curElement.add(curContentElement);
        } else {
            boolean alreadyExists = false;

            for (Element curContentElement : curContentElements) {
                String curLanguageId = curContentElement.attributeValue("language-id");

                if (newLanguageId.equals(curLanguageId)) {
                    alreadyExists = true;

                    curContentElement.clearContent();

                    if (newContentElement.element("option") != null) {
                        _addElementOptions(curContentElement, newContentElement);
                    } else {
                        curContentElement.addCDATA(newValue);
                    }

                    break;
                }
            }

            if (!alreadyExists) {
                Element curContentElement = curContentElements.get(0);

                String curLanguageId = curContentElement.attributeValue("language-id");

                if (Validator.isNull(curLanguageId)) {
                    if (newLanguageId.equals(defaultLocale)) {
                        curContentElement.clearContent();

                        if (newContentElement.element("option") != null) {
                            _addElementOptions(curContentElement, newContentElement);
                        } else {
                            curContentElement.addCDATA(newValue);
                        }
                    } else {
                        curElement.add(newContentElement.createCopy());
                    }

                    curContentElement.addAttribute("language-id", defaultLocale);
                } else {
                    curElement.add(newContentElement.createCopy());
                }
            }
        }
    }

    private static void _populateCustomTokens(Map<String, String> tokens, long companyId) {

        JournalServiceConfiguration journalServiceConfiguration = null;

        try {
            journalServiceConfiguration = ConfigurationProviderUtil
                    .getCompanyConfiguration(JournalServiceConfiguration.class, companyId);
        } catch (Exception e) {
            _log.error(e, e);
        }

        if (journalServiceConfiguration == null) {
            return;
        }

        if (MapUtil.isEmpty(_customTokens)) {
            synchronized (JournalUtil.class) {
                _customTokens = new HashMap<>();

                for (String tokenName : journalServiceConfiguration.customTokenNames()) {

                    String tokenValue = _getCustomTokenValue(tokenName, journalServiceConfiguration);

                    if (Validator.isNull(tokenValue)) {
                        continue;
                    }

                    _customTokens.put(tokenName, tokenValue);
                }
            }
        }

        if (!_customTokens.isEmpty()) {
            tokens.putAll(_customTokens);
        }
    }

    private static void _populateTokens(Map<String, String> tokens, long articleGroupId, ThemeDisplay themeDisplay)
            throws PortalException {

        Layout layout = themeDisplay.getLayout();

        Group group = layout.getGroup();

        LayoutSet layoutSet = layout.getLayoutSet();

        String friendlyUrlCurrent = null;

        if (layout.isPublicLayout()) {
            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
        } else if (group.isUserGroup()) {
            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
        } else {
            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
        }

        String layoutSetFriendlyUrl = themeDisplay.getI18nPath();

        String virtualHostname = layoutSet.getVirtualHostname();

        if (Validator.isNull(virtualHostname) || !virtualHostname.equals(themeDisplay.getServerName())) {

            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
        }

        tokens.put("article_group_id", String.valueOf(articleGroupId));
        tokens.put("cdn_host", themeDisplay.getCDNHost());
        tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
        tokens.put("friendly_url_current", friendlyUrlCurrent);
        tokens.put("friendly_url_private_group", themeDisplay.getPathFriendlyURLPrivateGroup());
        tokens.put("friendly_url_private_user", themeDisplay.getPathFriendlyURLPrivateUser());
        tokens.put("friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
        tokens.put("group_friendly_url", group.getFriendlyURL());
        tokens.put("image_path", themeDisplay.getPathImage());
        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
        tokens.put("main_path", themeDisplay.getPathMain());
        tokens.put("portal_ctx", themeDisplay.getPathContext());
        tokens.put("portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
        tokens.put("protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
        tokens.put("root_path", themeDisplay.getPathContext());
        tokens.put("scope_group_id", String.valueOf(themeDisplay.getScopeGroupId()));
        tokens.put("site_group_id", String.valueOf(themeDisplay.getSiteGroupId()));
        tokens.put("theme_image_path", themeDisplay.getPathThemeImages());

        _populateCustomTokens(tokens, themeDisplay.getCompanyId());

        // Deprecated tokens

        tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
        tokens.put("friendly_url_private", themeDisplay.getPathFriendlyURLPrivateGroup());
        tokens.put("group_id", String.valueOf(articleGroupId));
        tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
    }

    private static void _populateTokens(Map<String, String> tokens, long articleGroupId,
            ThemeDisplayModel themeDisplayModel) throws Exception {

        Layout layout = LayoutLocalServiceUtil.getLayout(themeDisplayModel.getPlid());

        Group group = layout.getGroup();

        LayoutSet layoutSet = layout.getLayoutSet();

        String friendlyUrlCurrent = null;

        if (layout.isPublicLayout()) {
            friendlyUrlCurrent = themeDisplayModel.getPathFriendlyURLPublic();
        } else if (group.isUserGroup()) {
            friendlyUrlCurrent = themeDisplayModel.getPathFriendlyURLPrivateUser();
        } else {
            friendlyUrlCurrent = themeDisplayModel.getPathFriendlyURLPrivateGroup();
        }

        String layoutSetFriendlyUrl = themeDisplayModel.getI18nPath();

        String virtualHostname = layoutSet.getVirtualHostname();

        if (Validator.isNull(virtualHostname) || !virtualHostname.equals(themeDisplayModel.getServerName())) {

            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
        }

        tokens.put("article_group_id", String.valueOf(articleGroupId));
        tokens.put("cdn_host", themeDisplayModel.getCdnHost());
        tokens.put("company_id", String.valueOf(themeDisplayModel.getCompanyId()));
        tokens.put("friendly_url_current", friendlyUrlCurrent);
        tokens.put("friendly_url_private_group", themeDisplayModel.getPathFriendlyURLPrivateGroup());
        tokens.put("friendly_url_private_user", themeDisplayModel.getPathFriendlyURLPrivateUser());
        tokens.put("friendly_url_public", themeDisplayModel.getPathFriendlyURLPublic());
        tokens.put("group_friendly_url", group.getFriendlyURL());
        tokens.put("image_path", themeDisplayModel.getPathImage());
        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
        tokens.put("main_path", themeDisplayModel.getPathMain());
        tokens.put("portal_ctx", themeDisplayModel.getPathContext());
        tokens.put("portal_url", HttpUtil.removeProtocol(themeDisplayModel.getURLPortal()));
        tokens.put("protocol", HttpUtil.getProtocol(themeDisplayModel.getURLPortal()));
        tokens.put("root_path", themeDisplayModel.getPathContext());
        tokens.put("scope_group_id", String.valueOf(themeDisplayModel.getScopeGroupId()));
        tokens.put("theme_image_path", themeDisplayModel.getPathThemeImages());

        _populateCustomTokens(tokens, themeDisplayModel.getCompanyId());

        // Deprecated tokens

        tokens.put("friendly_url", themeDisplayModel.getPathFriendlyURLPublic());
        tokens.put("friendly_url_private", themeDisplayModel.getPathFriendlyURLPrivateGroup());
        tokens.put("group_id", String.valueOf(articleGroupId));
        tokens.put("page_url", themeDisplayModel.getPathFriendlyURLPublic());
    }

    private static void _removeOldContent(Stack<String> path, Element contentElement, Document xsdDocument) {

        String elementPath = "";

        for (int i = 0; i < path.size(); i++) {
            elementPath += "/" + path.elementAt(i);
        }

        for (int i = 0; i < contentElement.nodeCount(); i++) {
            Node contentNode = contentElement.node(i);

            if (contentNode instanceof Element) {
                _removeOldContent(path, (Element) contentNode, xsdDocument, elementPath);
            }
        }
    }

    private static void _removeOldContent(Stack<String> path, Element contentElement, Document xsdDocument,
            String elementPath) {

        String name = contentElement.attributeValue("name");

        if (Validator.isNull(name)) {
            return;
        }

        String localPath = "dynamic-element[@name=" + HtmlUtil.escapeXPathAttribute(name) + "]";

        String fullPath = elementPath + "/" + localPath;

        XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);

        List<Node> curNodes = xPathSelector.selectNodes(xsdDocument);

        if (curNodes.isEmpty()) {
            contentElement.detach();
        }

        path.push(localPath);

        _removeOldContent(path, contentElement, xsdDocument);

        path.pop();
    }

    private static final Log _log = LogFactoryUtil.getLog(JournalUtil.class);

    private static Map<String, String> _customTokens;
    private static final JournalTransformer _journalTransformer = new JournalTransformer(true);

}