001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.journal.util;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.search.Field;
023    import com.liferay.portal.kernel.search.Hits;
024    import com.liferay.portal.kernel.search.Indexer;
025    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
026    import com.liferay.portal.kernel.templateparser.Transformer;
027    import com.liferay.portal.kernel.templateparser.TransformerListener;
028    import com.liferay.portal.kernel.util.CharPool;
029    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.HttpUtil;
032    import com.liferay.portal.kernel.util.LocaleUtil;
033    import com.liferay.portal.kernel.util.OrderByComparator;
034    import com.liferay.portal.kernel.util.PropsKeys;
035    import com.liferay.portal.kernel.util.StringPool;
036    import com.liferay.portal.kernel.util.StringUtil;
037    import com.liferay.portal.kernel.util.Time;
038    import com.liferay.portal.kernel.util.Tuple;
039    import com.liferay.portal.kernel.util.Validator;
040    import com.liferay.portal.kernel.xml.Attribute;
041    import com.liferay.portal.kernel.xml.Document;
042    import com.liferay.portal.kernel.xml.Element;
043    import com.liferay.portal.kernel.xml.Node;
044    import com.liferay.portal.kernel.xml.SAXReaderUtil;
045    import com.liferay.portal.kernel.xml.XPath;
046    import com.liferay.portal.model.Group;
047    import com.liferay.portal.model.Layout;
048    import com.liferay.portal.model.LayoutSet;
049    import com.liferay.portal.model.User;
050    import com.liferay.portal.service.ImageLocalServiceUtil;
051    import com.liferay.portal.service.LayoutLocalServiceUtil;
052    import com.liferay.portal.service.UserLocalServiceUtil;
053    import com.liferay.portal.theme.ThemeDisplay;
054    import com.liferay.portal.util.PortalUtil;
055    import com.liferay.portal.util.PropsUtil;
056    import com.liferay.portal.util.PropsValues;
057    import com.liferay.portal.util.WebKeys;
058    import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
059    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
060    import com.liferay.portlet.journal.NoSuchArticleException;
061    import com.liferay.portlet.journal.model.JournalArticle;
062    import com.liferay.portlet.journal.model.JournalStructure;
063    import com.liferay.portlet.journal.model.JournalStructureConstants;
064    import com.liferay.portlet.journal.model.JournalTemplate;
065    import com.liferay.portlet.journal.service.JournalArticleImageLocalServiceUtil;
066    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
067    import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
068    import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
069    import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
070    import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
071    import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
072    import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
073    import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
074    import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
075    import com.liferay.util.ContentUtil;
076    import com.liferay.util.FiniteUniqueStack;
077    
078    import java.util.ArrayList;
079    import java.util.Date;
080    import java.util.HashMap;
081    import java.util.Iterator;
082    import java.util.List;
083    import java.util.Map;
084    import java.util.Stack;
085    
086    import javax.portlet.PortletPreferences;
087    import javax.portlet.PortletRequest;
088    import javax.portlet.PortletSession;
089    
090    /**
091     * @author Brian Wing Shun Chan
092     * @author Raymond Augé
093     * @author Wesley Gong
094     * @author Angelo Jefferson
095     * @author Hugo Huijser
096     */
097    public class JournalUtil {
098    
099            public static final int MAX_STACK_SIZE = 20;
100    
101            public static void addAllReservedEls(
102                    Element rootElement, Map<String, String> tokens,
103                    JournalArticle article) {
104    
105                    JournalUtil.addReservedEl(
106                            rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_ID,
107                            article.getArticleId());
108    
109                    JournalUtil.addReservedEl(
110                            rootElement, tokens,
111                            JournalStructureConstants.RESERVED_ARTICLE_VERSION,
112                            article.getVersion());
113    
114                    JournalUtil.addReservedEl(
115                            rootElement, tokens,
116                            JournalStructureConstants.RESERVED_ARTICLE_TITLE,
117                            article.getTitle());
118    
119                    JournalUtil.addReservedEl(
120                            rootElement, tokens,
121                            JournalStructureConstants.RESERVED_ARTICLE_URL_TITLE,
122                            article.getUrlTitle());
123    
124                    JournalUtil.addReservedEl(
125                            rootElement, tokens,
126                            JournalStructureConstants.RESERVED_ARTICLE_DESCRIPTION,
127                            article.getDescription());
128    
129                    JournalUtil.addReservedEl(
130                            rootElement, tokens,
131                            JournalStructureConstants.RESERVED_ARTICLE_TYPE, article.getType());
132    
133                    JournalUtil.addReservedEl(
134                            rootElement, tokens,
135                            JournalStructureConstants.RESERVED_ARTICLE_CREATE_DATE,
136                            article.getCreateDate());
137    
138                    JournalUtil.addReservedEl(
139                            rootElement, tokens,
140                            JournalStructureConstants.RESERVED_ARTICLE_MODIFIED_DATE,
141                            article.getModifiedDate());
142    
143                    if (article.getDisplayDate() != null) {
144                            JournalUtil.addReservedEl(
145                                    rootElement, tokens,
146                                    JournalStructureConstants.RESERVED_ARTICLE_DISPLAY_DATE,
147                                    article.getDisplayDate());
148                    }
149    
150                    JournalUtil.addReservedEl(
151                            rootElement, tokens,
152                            JournalStructureConstants.RESERVED_ARTICLE_SMALL_IMAGE_URL,
153                            article.getSmallImageURL());
154    
155                    String[] assetTagNames = new String[0];
156    
157                    try {
158                            assetTagNames = AssetTagLocalServiceUtil.getTagNames(
159                                    JournalArticle.class.getName(), article.getResourcePrimKey());
160                    }
161                    catch (SystemException se) {
162                    }
163    
164                    JournalUtil.addReservedEl(
165                            rootElement, tokens,
166                            JournalStructureConstants.RESERVED_ARTICLE_ASSET_TAG_NAMES,
167                            StringUtil.merge(assetTagNames));
168    
169                    JournalUtil.addReservedEl(
170                            rootElement, tokens,
171                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_ID,
172                            String.valueOf(article.getUserId()));
173    
174                    String userName = StringPool.BLANK;
175                    String userEmailAddress = StringPool.BLANK;
176                    String userComments = StringPool.BLANK;
177                    String userJobTitle = StringPool.BLANK;
178    
179                    User user = null;
180    
181                    try {
182                            user = UserLocalServiceUtil.getUserById(article.getUserId());
183    
184                            userName = user.getFullName();
185                            userEmailAddress = user.getEmailAddress();
186                            userComments = user.getComments();
187                            userJobTitle = user.getJobTitle();
188                    }
189                    catch (PortalException pe) {
190                    }
191                    catch (SystemException se) {
192                    }
193    
194                    JournalUtil.addReservedEl(
195                            rootElement, tokens,
196                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_NAME, userName);
197    
198                    JournalUtil.addReservedEl(
199                            rootElement, tokens,
200                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_EMAIL_ADDRESS,
201                            userEmailAddress);
202    
203                    JournalUtil.addReservedEl(
204                            rootElement, tokens,
205                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_COMMENTS,
206                            userComments);
207    
208                    JournalUtil.addReservedEl(
209                            rootElement, tokens,
210                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_JOB_TITLE,
211                            userJobTitle);
212            }
213    
214            public static void addRecentArticle(
215                    PortletRequest portletRequest, JournalArticle article) {
216    
217                    if (article != null) {
218                            Stack<JournalArticle> stack = getRecentArticles(portletRequest);
219    
220                            stack.push(article);
221                    }
222            }
223    
224            public static void addRecentStructure(
225                    PortletRequest portletRequest, JournalStructure structure) {
226    
227                    if (structure != null) {
228                            Stack<JournalStructure> stack = getRecentStructures(portletRequest);
229    
230                            stack.push(structure);
231                    }
232            }
233    
234            public static void addRecentTemplate(
235                    PortletRequest portletRequest, JournalTemplate template) {
236    
237                    if (template != null) {
238                            Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
239    
240                            stack.push(template);
241                    }
242            }
243    
244            public static void addReservedEl(
245                    Element rootElement, Map<String, String> tokens, String name,
246                    Date value) {
247    
248                    addReservedEl(rootElement, tokens, name, Time.getRFC822(value));
249            }
250    
251            public static void addReservedEl(
252                    Element rootElement, Map<String, String> tokens, String name,
253                    double value) {
254    
255                    addReservedEl(rootElement, tokens, name, String.valueOf(value));
256            }
257    
258            public static void addReservedEl(
259                    Element rootElement, Map<String, String> tokens, String name,
260                    String value) {
261    
262                    // XML
263    
264                    if (rootElement != null) {
265                            Element dynamicElementElement = SAXReaderUtil.createElement(
266                                    "dynamic-element");
267    
268                            Attribute nameAttribute = SAXReaderUtil.createAttribute(
269                                    dynamicElementElement, "name", name);
270    
271                            dynamicElementElement.add(nameAttribute);
272    
273                            Attribute typeAttribute = SAXReaderUtil.createAttribute(
274                                    dynamicElementElement, "type", "text");
275    
276                            dynamicElementElement.add(typeAttribute);
277    
278                            Element dynamicContentElement = SAXReaderUtil.createElement(
279                                    "dynamic-content");
280    
281                            //dynamicContentElement.setText("<![CDATA[" + value + "]]>");
282                            dynamicContentElement.setText(value);
283    
284                            dynamicElementElement.add(dynamicContentElement);
285    
286                            rootElement.add(dynamicElementElement);
287                    }
288    
289                    // Tokens
290    
291                    tokens.put(
292                            StringUtil.replace(name, CharPool.DASH, CharPool.UNDERLINE),
293                            value);
294            }
295    
296            public static String formatVM(String vm) {
297                    return vm;
298            }
299    
300            public static OrderByComparator getArticleOrderByComparator(
301                    String orderByCol, String orderByType) {
302    
303                    boolean orderByAsc = false;
304    
305                    if (orderByType.equals("asc")) {
306                            orderByAsc = true;
307                    }
308    
309                    OrderByComparator orderByComparator = null;
310    
311                    if (orderByCol.equals("create-date")) {
312                            orderByComparator = new ArticleCreateDateComparator(orderByAsc);
313                    }
314                    else if (orderByCol.equals("display-date")) {
315                            orderByComparator = new ArticleDisplayDateComparator(orderByAsc);
316                    }
317                    else if (orderByCol.equals("id")) {
318                            orderByComparator = new ArticleIDComparator(orderByAsc);
319                    }
320                    else if (orderByCol.equals("modified-date")) {
321                            orderByComparator = new ArticleModifiedDateComparator(orderByAsc);
322                    }
323                    else if (orderByCol.equals("review-date")) {
324                            orderByComparator = new ArticleReviewDateComparator(orderByAsc);
325                    }
326                    else if (orderByCol.equals("title")) {
327                            orderByComparator = new ArticleTitleComparator(orderByAsc);
328                    }
329                    else if (orderByCol.equals("version")) {
330                            orderByComparator = new ArticleVersionComparator(orderByAsc);
331                    }
332    
333                    return orderByComparator;
334            }
335    
336            public static Tuple getArticles(Hits hits)
337                    throws PortalException, SystemException {
338    
339                    List<JournalArticle> articles = new ArrayList<JournalArticle>();
340                    boolean corruptIndex = false;
341    
342                    List<com.liferay.portal.kernel.search.Document> documents =
343                            hits.toList();
344    
345                    for (com.liferay.portal.kernel.search.Document document : documents) {
346                            long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID));
347                            String articleId = document.get("articleId");
348    
349                            try {
350                                    JournalArticle article =
351                                            JournalArticleLocalServiceUtil.getArticle(
352                                                    groupId, articleId);
353    
354                                    articles.add(article);
355                            }
356                            catch (NoSuchArticleException nsae) {
357                                    corruptIndex = true;
358    
359                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
360                                            JournalArticle.class);
361    
362                                    long companyId = GetterUtil.getLong(
363                                            document.get(Field.COMPANY_ID));
364    
365                                    indexer.delete(companyId, document.getUID());
366                            }
367                    }
368    
369                    return new Tuple(articles, corruptIndex);
370            }
371    
372            public static String getEmailArticleAddedBody(
373                    PortletPreferences preferences) {
374    
375                    String emailArticleAddedBody = preferences.getValue(
376                            "emailArticleAddedBody", StringPool.BLANK);
377    
378                    if (Validator.isNotNull(emailArticleAddedBody)) {
379                            return emailArticleAddedBody;
380                    }
381                    else {
382                            return ContentUtil.get(PropsUtil.get(
383                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_BODY));
384                    }
385            }
386    
387            public static boolean getEmailArticleAddedEnabled(
388                    PortletPreferences preferences) {
389    
390                    String emailArticleAddedEnabled = preferences.getValue(
391                            "emailArticleAddedEnabled", StringPool.BLANK);
392    
393                    if (Validator.isNotNull(emailArticleAddedEnabled)) {
394                            return GetterUtil.getBoolean(emailArticleAddedEnabled);
395                    }
396                    else {
397                            return GetterUtil.getBoolean(PropsUtil.get(
398                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_ENABLED));
399                    }
400            }
401    
402            public static String getEmailArticleAddedSubject(
403                    PortletPreferences preferences) {
404    
405                    String emailArticleAddedSubject = preferences.getValue(
406                            "emailArticleAddedSubject", StringPool.BLANK);
407    
408                    if (Validator.isNotNull(emailArticleAddedSubject)) {
409                            return emailArticleAddedSubject;
410                    }
411                    else {
412                            return ContentUtil.get(PropsUtil.get(
413                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_SUBJECT));
414                    }
415            }
416    
417            public static String getEmailArticleApprovalDeniedBody(
418                    PortletPreferences preferences) {
419    
420                    String emailArticleApprovalDeniedBody = preferences.getValue(
421                            "emailArticleApprovalDeniedBody", StringPool.BLANK);
422    
423                    if (Validator.isNotNull(emailArticleApprovalDeniedBody)) {
424                            return emailArticleApprovalDeniedBody;
425                    }
426                    else {
427                            return ContentUtil.get(PropsUtil.get(
428                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_BODY));
429                    }
430            }
431    
432            public static boolean getEmailArticleApprovalDeniedEnabled(
433                    PortletPreferences preferences) {
434    
435                    String emailArticleApprovalDeniedEnabled = preferences.getValue(
436                            "emailArticleApprovalDeniedEnabled", StringPool.BLANK);
437    
438                    if (Validator.isNotNull(emailArticleApprovalDeniedEnabled)) {
439                            return GetterUtil.getBoolean(emailArticleApprovalDeniedEnabled);
440                    }
441                    else {
442                            return GetterUtil.getBoolean(PropsUtil.get(
443                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_ENABLED));
444                    }
445            }
446    
447            public static String getEmailArticleApprovalDeniedSubject(
448                    PortletPreferences preferences) {
449    
450                    String emailArticleApprovalDeniedSubject = preferences.getValue(
451                            "emailArticleApprovalDeniedSubject", StringPool.BLANK);
452    
453                    if (Validator.isNotNull(emailArticleApprovalDeniedSubject)) {
454                            return emailArticleApprovalDeniedSubject;
455                    }
456                    else {
457                            return ContentUtil.get(PropsUtil.get(
458                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_SUBJECT));
459                    }
460            }
461    
462            public static String getEmailArticleApprovalGrantedBody(
463                    PortletPreferences preferences) {
464    
465                    String emailArticleApprovalGrantedBody = preferences.getValue(
466                            "emailArticleApprovalGrantedBody", StringPool.BLANK);
467    
468                    if (Validator.isNotNull(emailArticleApprovalGrantedBody)) {
469                            return emailArticleApprovalGrantedBody;
470                    }
471                    else {
472                            return ContentUtil.get(PropsUtil.get(
473                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_BODY));
474                    }
475            }
476    
477            public static boolean getEmailArticleApprovalGrantedEnabled(
478                    PortletPreferences preferences) {
479    
480                    String emailArticleApprovalGrantedEnabled = preferences.getValue(
481                            "emailArticleApprovalGrantedEnabled", StringPool.BLANK);
482    
483                    if (Validator.isNotNull(emailArticleApprovalGrantedEnabled)) {
484                            return GetterUtil.getBoolean(emailArticleApprovalGrantedEnabled);
485                    }
486                    else {
487                            return GetterUtil.getBoolean(PropsUtil.get(
488                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_ENABLED));
489                    }
490            }
491    
492            public static String getEmailArticleApprovalGrantedSubject(
493                    PortletPreferences preferences) {
494    
495                    String emailArticleApprovalGrantedSubject = preferences.getValue(
496                            "emailArticleApprovalGrantedSubject", StringPool.BLANK);
497    
498                    if (Validator.isNotNull(emailArticleApprovalGrantedSubject)) {
499                            return emailArticleApprovalGrantedSubject;
500                    }
501                    else {
502                            return ContentUtil.get(PropsUtil.get(
503                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_SUBJECT));
504                    }
505            }
506    
507            public static String getEmailArticleApprovalRequestedBody(
508                    PortletPreferences preferences) {
509    
510                    String emailArticleApprovalRequestedBody = preferences.getValue(
511                            "emailArticleApprovalRequestedBody", StringPool.BLANK);
512    
513                    if (Validator.isNotNull(emailArticleApprovalRequestedBody)) {
514                            return emailArticleApprovalRequestedBody;
515                    }
516                    else {
517                            return ContentUtil.get(PropsUtil.get(
518                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_BODY));
519                    }
520            }
521    
522            public static boolean getEmailArticleApprovalRequestedEnabled(
523                    PortletPreferences preferences) {
524    
525                    String emailArticleApprovalRequestedEnabled = preferences.getValue(
526                            "emailArticleApprovalRequestedEnabled", StringPool.BLANK);
527    
528                    if (Validator.isNotNull(emailArticleApprovalRequestedEnabled)) {
529                            return GetterUtil.getBoolean(emailArticleApprovalRequestedEnabled);
530                    }
531                    else {
532                            return GetterUtil.getBoolean(PropsUtil.get(
533                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_ENABLED));
534                    }
535            }
536    
537            public static String getEmailArticleApprovalRequestedSubject(
538                    PortletPreferences preferences) {
539    
540                    String emailArticleApprovalRequestedSubject = preferences.getValue(
541                            "emailArticleApprovalRequestedSubject", StringPool.BLANK);
542    
543                    if (Validator.isNotNull(emailArticleApprovalRequestedSubject)) {
544                            return emailArticleApprovalRequestedSubject;
545                    }
546                    else {
547                            return ContentUtil.get(PropsUtil.get(
548                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_SUBJECT));
549                    }
550            }
551    
552            public static String getEmailArticleReviewBody(
553                    PortletPreferences preferences) {
554    
555                    String emailArticleReviewBody = preferences.getValue(
556                            "emailArticleReviewBody", StringPool.BLANK);
557    
558                    if (Validator.isNotNull(emailArticleReviewBody)) {
559                            return emailArticleReviewBody;
560                    }
561                    else {
562                            return ContentUtil.get(PropsUtil.get(
563                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_BODY));
564                    }
565            }
566    
567            public static boolean getEmailArticleReviewEnabled(
568                    PortletPreferences preferences) {
569    
570                    String emailArticleReviewEnabled = preferences.getValue(
571                            "emailArticleReviewEnabled", StringPool.BLANK);
572    
573                    if (Validator.isNotNull(emailArticleReviewEnabled)) {
574                            return GetterUtil.getBoolean(emailArticleReviewEnabled);
575                    }
576                    else {
577                            return GetterUtil.getBoolean(PropsUtil.get(
578                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_ENABLED));
579                    }
580            }
581    
582            public static String getEmailArticleReviewSubject(
583                    PortletPreferences preferences) {
584    
585                    String emailArticleReviewSubject = preferences.getValue(
586                            "emailArticleReviewSubject", StringPool.BLANK);
587    
588                    if (Validator.isNotNull(emailArticleReviewSubject)) {
589                            return emailArticleReviewSubject;
590                    }
591                    else {
592                            return ContentUtil.get(PropsUtil.get(
593                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_SUBJECT));
594                    }
595            }
596    
597            public static String getEmailArticleUpdatedBody(
598                    PortletPreferences preferences) {
599    
600                    String emailArticleUpdatedBody = preferences.getValue(
601                            "emailArticleUpdatedBody", StringPool.BLANK);
602    
603                    if (Validator.isNotNull(emailArticleUpdatedBody)) {
604                            return emailArticleUpdatedBody;
605                    }
606                    else {
607                            return ContentUtil.get(PropsUtil.get(
608                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_BODY));
609                    }
610            }
611    
612            public static boolean getEmailArticleUpdatedEnabled(
613                    PortletPreferences preferences) {
614    
615                    String emailArticleUpdatedEnabled = preferences.getValue(
616                            "emailArticleUpdatedEnabled", StringPool.BLANK);
617    
618                    if (Validator.isNotNull(emailArticleUpdatedEnabled)) {
619                            return GetterUtil.getBoolean(emailArticleUpdatedEnabled);
620                    }
621                    else {
622                            return GetterUtil.getBoolean(PropsUtil.get(
623                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_ENABLED));
624                    }
625            }
626    
627            public static String getEmailArticleUpdatedSubject(
628                    PortletPreferences preferences) {
629    
630                    String emailArticleUpdatedSubject = preferences.getValue(
631                            "emailArticleUpdatedSubject", StringPool.BLANK);
632    
633                    if (Validator.isNotNull(emailArticleUpdatedSubject)) {
634                            return emailArticleUpdatedSubject;
635                    }
636                    else {
637                            return ContentUtil.get(PropsUtil.get(
638                                    PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_SUBJECT));
639                    }
640            }
641    
642            public static String getEmailFromAddress(
643                            PortletPreferences preferences, long companyId)
644                    throws SystemException {
645    
646                    return PortalUtil.getEmailFromAddress(
647                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_ADDRESS);
648            }
649    
650            public static String getEmailFromName(
651                            PortletPreferences preferences, long companyId)
652                    throws SystemException {
653    
654                    return PortalUtil.getEmailFromName(
655                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_NAME);
656            }
657    
658            public static Stack<JournalArticle> getRecentArticles(
659                    PortletRequest portletRequest) {
660    
661                    PortletSession portletSession = portletRequest.getPortletSession();
662    
663                    Stack<JournalArticle> recentArticles =
664                            (Stack<JournalArticle>)portletSession.getAttribute(
665                                    WebKeys.JOURNAL_RECENT_ARTICLES);
666    
667                    if (recentArticles == null) {
668                            recentArticles = new FiniteUniqueStack<JournalArticle>(
669                                    MAX_STACK_SIZE);
670    
671                            portletSession.setAttribute(
672                                    WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
673                    }
674    
675                    return recentArticles;
676            }
677    
678            public static Stack<JournalStructure> getRecentStructures(
679                    PortletRequest portletRequest) {
680    
681                    PortletSession portletSession = portletRequest.getPortletSession();
682    
683                    Stack<JournalStructure> recentStructures =
684                            (Stack<JournalStructure>)portletSession.getAttribute(
685                                    WebKeys.JOURNAL_RECENT_STRUCTURES);
686    
687                    if (recentStructures == null) {
688                            recentStructures = new FiniteUniqueStack<JournalStructure>(
689                                    MAX_STACK_SIZE);
690    
691                            portletSession.setAttribute(
692                                    WebKeys.JOURNAL_RECENT_STRUCTURES, recentStructures);
693                    }
694    
695                    return recentStructures;
696            }
697    
698            public static Stack<JournalTemplate> getRecentTemplates(
699                    PortletRequest portletRequest) {
700    
701                    PortletSession portletSession = portletRequest.getPortletSession();
702    
703                    Stack<JournalTemplate> recentTemplates =
704                            (Stack<JournalTemplate>)portletSession.getAttribute(
705                                    WebKeys.JOURNAL_RECENT_TEMPLATES);
706    
707                    if (recentTemplates == null) {
708                            recentTemplates = new FiniteUniqueStack<JournalTemplate>(
709                                    MAX_STACK_SIZE);
710    
711                            portletSession.setAttribute(
712                                    WebKeys.JOURNAL_RECENT_TEMPLATES, recentTemplates);
713                    }
714    
715                    return recentTemplates;
716            }
717    
718            public static String getTemplateScript(
719                    JournalTemplate template, Map<String, String> tokens, String languageId,
720                    boolean transform) {
721    
722                    String script = template.getXsl();
723    
724                    if (transform) {
725    
726                            // Listeners
727    
728                            String[] listeners =
729                                    PropsUtil.getArray(PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
730    
731                            for (int i = 0; i < listeners.length; i++) {
732                                    TransformerListener listener = null;
733    
734                                    try {
735                                            listener =
736                                                    (TransformerListener)Class.forName(
737                                                            listeners[i]).newInstance();
738    
739                                            listener.setTemplateDriven(true);
740                                            listener.setLanguageId(languageId);
741                                            listener.setTokens(tokens);
742                                    }
743                                    catch (Exception e) {
744                                            _log.error(e, e);
745                                    }
746    
747                                    // Modify transform script
748    
749                                    if (listener != null) {
750                                            script = listener.onScript(script);
751                                    }
752                            }
753                    }
754    
755                    return script;
756            }
757    
758            public static String getTemplateScript(
759                            long groupId, String templateId, Map<String, String> tokens,
760                            String languageId)
761                    throws PortalException, SystemException {
762    
763                    return getTemplateScript(groupId, templateId, tokens, languageId, true);
764            }
765    
766            public static String getTemplateScript(
767                            long groupId, String templateId, Map<String, String> tokens,
768                            String languageId, boolean transform)
769                    throws PortalException, SystemException {
770    
771                    JournalTemplate template = JournalTemplateLocalServiceUtil.getTemplate(
772                            groupId, templateId);
773    
774                    return getTemplateScript(template, tokens, languageId, transform);
775            }
776    
777            public static Map<String, String> getTokens(
778                            long groupId, ThemeDisplay themeDisplay)
779                    throws PortalException, SystemException {
780    
781                    return getTokens(groupId, themeDisplay, null);
782            }
783    
784            public static Map<String, String> getTokens(
785                            long groupId, ThemeDisplay themeDisplay, String xmlRequest)
786                    throws PortalException, SystemException {
787    
788                    Map<String, String> tokens = new HashMap<String, String>();
789    
790                    if (themeDisplay != null) {
791                            _populateTokens(tokens, groupId, themeDisplay);
792                    }
793                    else if (Validator.isNotNull(xmlRequest)) {
794                            try {
795                                    _populateTokens(tokens, groupId, xmlRequest);
796                            }
797                            catch (Exception e) {
798                                    if (_log.isWarnEnabled()) {
799                                            _log.warn(e, e);
800                                    }
801                            }
802                    }
803    
804                    return tokens;
805            }
806    
807            public static String getUrlTitle(long id, String title) {
808                    title = title.trim().toLowerCase();
809    
810                    if (Validator.isNull(title) || Validator.isNumber(title) ||
811                            title.equals("rss")) {
812    
813                            return String.valueOf(id);
814                    }
815                    else {
816                            return FriendlyURLNormalizerUtil.normalize(
817                                    title, _URL_TITLE_REPLACE_CHARS);
818                    }
819            }
820    
821            public static String mergeArticleContent(
822                    String curContent, String newContent, boolean removeNullElements) {
823    
824                    try {
825                            Document curDocument = SAXReaderUtil.read(curContent);
826                            Document newDocument = SAXReaderUtil.read(newContent);
827    
828                            Element curRootElement = curDocument.getRootElement();
829                            Element newRootElement = newDocument.getRootElement();
830    
831                            curRootElement.addAttribute(
832                                    "default-locale",
833                                    newRootElement.attributeValue("default-locale"));
834                            curRootElement.addAttribute(
835                                    "available-locales",
836                                    newRootElement.attributeValue("available-locales"));
837    
838                            _mergeArticleContentUpdate(
839                                    curDocument, newRootElement,
840                                    LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
841    
842                            if (removeNullElements) {
843                                    _mergeArticleContentDelete(curRootElement, newDocument);
844                            }
845    
846                            curContent = DDMXMLUtil.formatXML(curDocument);
847                    }
848                    catch (Exception e) {
849                            _log.error(e, e);
850                    }
851    
852                    return curContent;
853            }
854    
855            public static void removeArticleLocale(Element element, String languageId)
856                    throws PortalException, SystemException {
857    
858                    for (Element dynamicElementElement :
859                                    element.elements("dynamic-element")) {
860    
861                            for (Element dynamicContentElement :
862                                            dynamicElementElement.elements("dynamic-content")) {
863    
864                                    String curLanguageId = GetterUtil.getString(
865                                            dynamicContentElement.attributeValue("language-id"));
866    
867                                    if (curLanguageId.equals(languageId)) {
868                                            long id = GetterUtil.getLong(
869                                                    dynamicContentElement.attributeValue("id"));
870    
871                                            if (id > 0) {
872                                                    ImageLocalServiceUtil.deleteImage(id);
873                                            }
874    
875                                            dynamicContentElement.detach();
876                                    }
877                            }
878    
879                            removeArticleLocale(dynamicElementElement, languageId);
880                    }
881            }
882    
883            public static String removeArticleLocale(
884                    String content, String languageId) {
885    
886                    try {
887                            Document document = SAXReaderUtil.read(content);
888    
889                            Element rootElement = document.getRootElement();
890    
891                            String availableLocales = rootElement.attributeValue(
892                                    "available-locales");
893    
894                            if (availableLocales == null) {
895                                    return content;
896                            }
897    
898                            availableLocales = StringUtil.remove(availableLocales, languageId);
899    
900                            if (availableLocales.endsWith(",")) {
901                                    availableLocales = availableLocales.substring(
902                                            0, availableLocales.length() - 1);
903                            }
904    
905                            rootElement.addAttribute("available-locales", availableLocales);
906    
907                            removeArticleLocale(rootElement, languageId);
908    
909                            content = DDMXMLUtil.formatXML(document);
910                    }
911                    catch (Exception e) {
912                            _log.error(e, e);
913                    }
914    
915                    return content;
916            }
917    
918            public static String removeOldContent(String content, String xsd) {
919                    try {
920                            Document contentDoc = SAXReaderUtil.read(content);
921                            Document xsdDoc = SAXReaderUtil.read(xsd);
922    
923                            Element contentRoot = contentDoc.getRootElement();
924    
925                            Stack<String> path = new Stack<String>();
926    
927                            path.push(contentRoot.getName());
928    
929                            _removeOldContent(path, contentRoot, xsdDoc);
930    
931                            content = DDMXMLUtil.formatXML(contentDoc);
932                    }
933                    catch (Exception e) {
934                            _log.error(e, e);
935                    }
936    
937                    return content;
938            }
939    
940            public static void removeRecentArticle(
941                    PortletRequest portletRequest, String articleId) {
942    
943                    removeRecentArticle(portletRequest, articleId, 0);
944            }
945    
946            public static void removeRecentArticle(
947                    PortletRequest portletRequest, String articleId, double version) {
948    
949                    Stack<JournalArticle> stack = getRecentArticles(portletRequest);
950    
951                    Iterator<JournalArticle> itr = stack.iterator();
952    
953                    while (itr.hasNext()) {
954                            JournalArticle journalArticle = itr.next();
955    
956                            if (journalArticle.getArticleId().equals(articleId) &&
957                                    ((journalArticle.getVersion() == version) ||
958                                     (version == 0))) {
959    
960                                    itr.remove();
961                            }
962                    }
963            }
964    
965            public static void removeRecentStructure(
966                    PortletRequest portletRequest, String structureId) {
967    
968                    Stack<JournalStructure> stack = getRecentStructures(portletRequest);
969    
970                    Iterator<JournalStructure> itr = stack.iterator();
971    
972                    while (itr.hasNext()) {
973                            JournalStructure journalStructure = itr.next();
974    
975                            if (journalStructure.getStructureId().equals(structureId)) {
976                                    itr.remove();
977    
978                                    break;
979                            }
980                    }
981            }
982    
983            public static void removeRecentTemplate(
984                    PortletRequest portletRequest, String templateId) {
985    
986                    Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
987    
988                    Iterator<JournalTemplate> itr = stack.iterator();
989    
990                    while (itr.hasNext()) {
991                            JournalTemplate journalTemplate = itr.next();
992    
993                            if (journalTemplate.getTemplateId().equals(templateId)) {
994                                    itr.remove();
995    
996                                    break;
997                            }
998                    }
999            }
1000    
1001            public static String transform(
1002                            ThemeDisplay themeDisplay, Map<String, String> tokens,
1003                            String viewMode, String languageId, String xml, String script,
1004                            String langType)
1005                    throws Exception {
1006    
1007                    return _transformer.transform(
1008                            themeDisplay, tokens, viewMode, languageId, xml, script, langType);
1009            }
1010    
1011            private static void _addElementOptions (
1012                    Element curContentElement, Element newContentElement) {
1013    
1014                    List<Element> newElementOptions = newContentElement.elements("option");
1015    
1016                    for (Element newElementOption : newElementOptions) {
1017                            Element curElementOption = SAXReaderUtil.createElement("option");
1018    
1019                            curElementOption.addCDATA(newElementOption.getText());
1020    
1021                            curContentElement.add(curElementOption);
1022                    }
1023            }
1024    
1025            private static Element _getElementByInstanceId(
1026                    Document document, String instanceId) {
1027    
1028                    XPath xPathSelector = SAXReaderUtil.createXPath(
1029                            "//dynamic-element[@instance-id='" + instanceId + "']");
1030    
1031                    List<Node> nodes = xPathSelector.selectNodes(document);
1032    
1033                    if (nodes.size() == 1) {
1034                            return (Element)nodes.get(0);
1035                    }
1036                    else {
1037                            return null;
1038                    }
1039            }
1040    
1041            private static void _mergeArticleContentDelete(
1042                            Element curParentElement, Document newDocument)
1043                    throws Exception {
1044    
1045                    List<Element> curElements = curParentElement.elements(
1046                            "dynamic-element");
1047    
1048                    for (int i = 0; i < curElements.size(); i++) {
1049                            Element curElement = curElements.get(i);
1050    
1051                            _mergeArticleContentDelete(curElement, newDocument);
1052    
1053                            String instanceId = curElement.attributeValue("instance-id");
1054    
1055                            Element newElement = _getElementByInstanceId(
1056                                    newDocument, instanceId);
1057    
1058                            if (newElement == null) {
1059                                    curElement.detach();
1060    
1061                                    String type = curElement.attributeValue("type");
1062    
1063                                    if (type.equals("image")) {
1064                                            _mergeArticleContentDeleteImages(
1065                                                    curElement.elements("dynamic-content"));
1066                                    }
1067                            }
1068                    }
1069            }
1070    
1071            private static void _mergeArticleContentDeleteImages(List<Element> elements)
1072                    throws Exception {
1073    
1074                    for (Element element : elements) {
1075                            long articleImageId = GetterUtil.getLong(
1076                                    element.attributeValue("id"));
1077    
1078                            JournalArticleImageLocalServiceUtil.deleteArticleImage(
1079                                    articleImageId);
1080                    }
1081            }
1082    
1083            private static void _mergeArticleContentUpdate(
1084                            Document curDocument, Element newParentElement, Element newElement,
1085                            int pos, String defaultLocale)
1086                    throws Exception {
1087    
1088                    _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1089    
1090                    String instanceId = newElement.attributeValue("instance-id");
1091    
1092                    Element curElement = _getElementByInstanceId(curDocument, instanceId);
1093    
1094                    if (curElement != null) {
1095                            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1096                    }
1097                    else {
1098                            String parentInstanceId = newParentElement.attributeValue(
1099                                    "instance-id");
1100    
1101                            if (Validator.isNull(parentInstanceId)) {
1102                                    Element curRoot = curDocument.getRootElement();
1103    
1104                                    List<Element> curRootElements = curRoot.elements();
1105    
1106                                    curRootElements.add(pos, newElement.createCopy());
1107                            }
1108                            else {
1109                                    Element curParentElement = _getElementByInstanceId(
1110                                            curDocument, parentInstanceId);
1111    
1112                                    if (curParentElement != null) {
1113                                            List<Element> curParentElements =
1114                                                    curParentElement.elements();
1115    
1116                                            curParentElements.add(pos, newElement.createCopy());
1117                                    }
1118                            }
1119                    }
1120            }
1121    
1122            private static void _mergeArticleContentUpdate(
1123                            Document curDocument, Element newParentElement,
1124                            String defaultLocale)
1125                    throws Exception {
1126    
1127                    List<Element> newElements = newParentElement.elements(
1128                            "dynamic-element");
1129    
1130                    for (int i = 0; i < newElements.size(); i++) {
1131                            Element newElement = newElements.get(i);
1132    
1133                            _mergeArticleContentUpdate(
1134                                    curDocument, newParentElement, newElement, i, defaultLocale);
1135                    }
1136            }
1137    
1138            private static void _mergeArticleContentUpdate(
1139                    Element curElement, Element newElement, String defaultLocale) {
1140    
1141                    Attribute curTypeAttribute = curElement.attribute("type");
1142                    Attribute newTypeAttribute = newElement.attribute("type");
1143    
1144                    curTypeAttribute.setValue(newTypeAttribute.getValue());
1145    
1146                    Attribute curIndexTypeAttribute = curElement.attribute("index-type");
1147                    Attribute newIndexTypeAttribute = newElement.attribute("index-type");
1148    
1149                    if (newIndexTypeAttribute != null) {
1150                            if (curIndexTypeAttribute == null) {
1151                                    curElement.addAttribute(
1152                                            "index-type", newIndexTypeAttribute.getValue());
1153                            } else {
1154                                    curIndexTypeAttribute.setValue(
1155                                            newIndexTypeAttribute.getValue());
1156                            }
1157                    }
1158    
1159                    Element newContentElement = newElement.elements(
1160                            "dynamic-content").get(0);
1161    
1162                    String newLanguageId = newContentElement.attributeValue("language-id");
1163                    String newValue = newContentElement.getText();
1164    
1165                    String indexType = newElement.attributeValue("index-type");
1166    
1167                    if (Validator.isNotNull(indexType)) {
1168                            curElement.addAttribute("index-type", indexType);
1169                    }
1170    
1171                    List<Element> curContentElements = curElement.elements(
1172                            "dynamic-content");
1173    
1174                    if (Validator.isNull(newLanguageId)) {
1175                            for (Element curContentElement : curContentElements) {
1176                                    curContentElement.detach();
1177                            }
1178    
1179                            Element curContentElement = SAXReaderUtil.createElement(
1180                                    "dynamic-content");
1181    
1182                            if (newContentElement.element("option") != null) {
1183                                    _addElementOptions(curContentElement, newContentElement);
1184                            }
1185                            else {
1186                                    curContentElement.addCDATA(newValue);
1187                            }
1188    
1189                            curElement.add(curContentElement);
1190                    }
1191                    else {
1192                            boolean alreadyExists = false;
1193    
1194                            for (Element curContentElement : curContentElements) {
1195                                    String curLanguageId = curContentElement.attributeValue(
1196                                            "language-id");
1197    
1198                                    if (newLanguageId.equals(curLanguageId)) {
1199                                            alreadyExists = true;
1200    
1201                                            curContentElement.clearContent();
1202    
1203                                            if (newContentElement.element("option") != null) {
1204                                                    _addElementOptions(
1205                                                            curContentElement, newContentElement);
1206                                            }
1207                                            else {
1208                                                    curContentElement.addCDATA(newValue);
1209                                            }
1210    
1211                                            break;
1212                                    }
1213                            }
1214    
1215                            if (!alreadyExists) {
1216                                    Element curContentElement = curContentElements.get(0);
1217    
1218                                    String curLanguageId = curContentElement.attributeValue(
1219                                            "language-id");
1220    
1221                                    if (Validator.isNull(curLanguageId)) {
1222                                            if (newLanguageId.equals(defaultLocale)) {
1223                                                    curContentElement.clearContent();
1224    
1225                                                    if (newContentElement.element("option") != null) {
1226                                                            _addElementOptions(
1227                                                                    curContentElement, newContentElement);
1228                                                    }
1229                                                    else {
1230                                                            curContentElement.addCDATA(newValue);
1231                                                    }
1232                                            }
1233                                            else {
1234                                                    curElement.add(newContentElement.createCopy());
1235                                            }
1236    
1237                                            curContentElement.addAttribute(
1238                                                    "language-id", defaultLocale);
1239                                    }
1240                                    else {
1241                                            curElement.add(newContentElement.createCopy());
1242                                    }
1243                            }
1244                    }
1245            }
1246    
1247            private static void _populateCustomTokens(Map<String, String> tokens) {
1248                    if (_customTokens == null) {
1249                            synchronized (JournalUtil.class) {
1250                                    _customTokens = new HashMap<String, String>();
1251    
1252                                    for (String customToken :
1253                                                    PropsValues.JOURNAL_ARTICLE_CUSTOM_TOKENS) {
1254    
1255                                            String value = PropsUtil.get(
1256                                                    PropsKeys.JOURNAL_ARTICLE_CUSTOM_TOKEN_VALUE,
1257                                                    new Filter(customToken));
1258    
1259                                            _customTokens.put(customToken, value);
1260                                    }
1261                            }
1262                    }
1263    
1264                    if (!_customTokens.isEmpty()) {
1265                            tokens.putAll(_customTokens);
1266                    }
1267            }
1268    
1269            private static void _populateTokens(
1270                            Map<String, String> tokens, long groupId, String xmlRequest)
1271                    throws Exception {
1272    
1273                    Document requestDocument = SAXReaderUtil.read(xmlRequest);
1274    
1275                    Element rootElement = requestDocument.getRootElement();
1276    
1277                    Element themeDisplayElement = rootElement.element("theme-display");
1278    
1279                    Layout layout = LayoutLocalServiceUtil.getLayout(
1280                            GetterUtil.getLong(themeDisplayElement.elementText("plid")));
1281    
1282                    Group group = layout.getGroup();
1283    
1284                    LayoutSet layoutSet = layout.getLayoutSet();
1285    
1286                    String friendlyUrlCurrent = null;
1287    
1288                    if (layout.isPublicLayout()) {
1289                            friendlyUrlCurrent = themeDisplayElement.elementText(
1290                                    "path-friendly-url-public");
1291                    }
1292                    else if (group.isUserGroup()) {
1293                            friendlyUrlCurrent = themeDisplayElement.elementText(
1294                                    "path-friendly-url-private-user");
1295                    }
1296                    else {
1297                            friendlyUrlCurrent = themeDisplayElement.elementText(
1298                                    "path-friendly-url-private-group");
1299                    }
1300    
1301                    String layoutSetFriendlyUrl = StringPool.BLANK;
1302    
1303                    String virtualHostname = layoutSet.getVirtualHostname();
1304    
1305                    if (Validator.isNull(virtualHostname) ||
1306                            !virtualHostname.equals(
1307                                    themeDisplayElement.elementText("server-name"))) {
1308    
1309                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1310                    }
1311    
1312                    tokens.put("cdn_host", themeDisplayElement.elementText("cdn-host"));
1313                    tokens.put("company_id", themeDisplayElement.elementText("company-id"));
1314                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1315                    tokens.put(
1316                            "friendly_url_private_group",
1317                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1318                    tokens.put(
1319                            "friendly_url_private_user",
1320                            themeDisplayElement.elementText("path-friendly-url-private-user"));
1321                    tokens.put(
1322                            "friendly_url_public",
1323                            themeDisplayElement.elementText("path-friendly-url-public"));
1324                    tokens.put("group_friendly_url", group.getFriendlyURL());
1325                    tokens.put("group_id", String.valueOf(groupId));
1326                    tokens.put("image_path", themeDisplayElement.elementText("path-image"));
1327                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1328                    tokens.put("main_path", themeDisplayElement.elementText("path-main"));
1329                    tokens.put(
1330                            "portal_ctx", themeDisplayElement.elementText("path-context"));
1331                    tokens.put(
1332                            "portal_url",
1333                            HttpUtil.removeProtocol(
1334                                    themeDisplayElement.elementText("url-portal")));
1335                    tokens.put(
1336                            "protocol",
1337                            HttpUtil.getProtocol(
1338                                    themeDisplayElement.elementText("url-portal")));
1339                    tokens.put(
1340                            "root_path", themeDisplayElement.elementText("path-context"));
1341                    tokens.put(
1342                            "theme_image_path",
1343                            themeDisplayElement.elementText("path-theme-images"));
1344    
1345                    _populateCustomTokens(tokens);
1346    
1347                    // Deprecated tokens
1348    
1349                    tokens.put(
1350                            "friendly_url",
1351                            themeDisplayElement.elementText("path-friendly-url-public"));
1352                    tokens.put(
1353                            "friendly_url_private",
1354                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1355                    tokens.put(
1356                            "page_url",
1357                            themeDisplayElement.elementText("path-friendly-url-public"));
1358            }
1359    
1360            private static void _populateTokens(
1361                            Map<String, String> tokens, long groupId, ThemeDisplay themeDisplay)
1362                    throws PortalException, SystemException {
1363    
1364                    Layout layout = themeDisplay.getLayout();
1365    
1366                    Group group = layout.getGroup();
1367    
1368                    LayoutSet layoutSet = layout.getLayoutSet();
1369    
1370                    String friendlyUrlCurrent = null;
1371    
1372                    if (layout.isPublicLayout()) {
1373                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1374                    }
1375                    else if (group.isUserGroup()) {
1376                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1377                    }
1378                    else {
1379                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1380                    }
1381    
1382                    String layoutSetFriendlyUrl = StringPool.BLANK;
1383    
1384                    String virtualHostname = layoutSet.getVirtualHostname();
1385    
1386                    if (Validator.isNull(virtualHostname) ||
1387                            !virtualHostname.equals(themeDisplay.getServerName())) {
1388    
1389                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1390                    }
1391    
1392                    tokens.put("cdn_host", themeDisplay.getCDNHost());
1393                    tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1394                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1395                    tokens.put(
1396                            "friendly_url_private_group",
1397                            themeDisplay.getPathFriendlyURLPrivateGroup());
1398                    tokens.put(
1399                            "friendly_url_private_user",
1400                            themeDisplay.getPathFriendlyURLPrivateUser());
1401                    tokens.put(
1402                            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1403                    tokens.put("group_friendly_url", group.getFriendlyURL());
1404                    tokens.put("group_id", String.valueOf(groupId));
1405                    tokens.put("image_path", themeDisplay.getPathImage());
1406                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1407                    tokens.put("main_path", themeDisplay.getPathMain());
1408                    tokens.put("portal_ctx", themeDisplay.getPathContext());
1409                    tokens.put(
1410                            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1411                    tokens.put(
1412                            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1413                    tokens.put("root_path", themeDisplay.getPathContext());
1414                    tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1415    
1416                    _populateCustomTokens(tokens);
1417    
1418                    // Deprecated tokens
1419    
1420                    tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1421                    tokens.put(
1422                            "friendly_url_private",
1423                            themeDisplay.getPathFriendlyURLPrivateGroup());
1424                    tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1425            }
1426    
1427            private static void _removeOldContent(
1428                            Stack<String> path, Element contentElement, Document xsdDocument)
1429                    throws SystemException {
1430    
1431                    String elementPath = "";
1432    
1433                    for (int i = 0; i < path.size(); i++) {
1434                            elementPath += "/" + path.elementAt(i);
1435                    }
1436    
1437                    for (int i = 0; i < contentElement.nodeCount(); i++) {
1438                            Node contentNode = contentElement.node(i);
1439    
1440                            if (contentNode instanceof Element) {
1441                                    _removeOldContent(
1442                                            path, (Element)contentNode, xsdDocument, elementPath);
1443                            }
1444                    }
1445            }
1446    
1447            private static void _removeOldContent(
1448                            Stack<String> path, Element contentElement, Document xsdDocument,
1449                            String elementPath)
1450                    throws SystemException {
1451    
1452                    String name = contentElement.attributeValue("name");
1453    
1454                    if (Validator.isNull(name)) {
1455                            return;
1456                    }
1457    
1458                    String localPath = "dynamic-element[@name='" + name + "']";
1459    
1460                    String fullPath = elementPath + "/" + localPath;
1461    
1462                    XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1463    
1464                    List<Node> curNodes = xPathSelector.selectNodes(xsdDocument);
1465    
1466                    if (curNodes.size() == 0) {
1467                            contentElement.detach();
1468                    }
1469    
1470                    path.push(localPath);
1471    
1472                    _removeOldContent(path, contentElement, xsdDocument);
1473    
1474                    path.pop();
1475            }
1476    
1477            private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
1478                    '.', '/'
1479            };
1480    
1481            private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1482    
1483            private static Map<String, String> _customTokens;
1484            private static Transformer _transformer = new JournalTransformer();
1485    
1486    }