1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.journal.util;
16  
17  import com.liferay.portal.kernel.configuration.Filter;
18  import com.liferay.portal.kernel.exception.PortalException;
19  import com.liferay.portal.kernel.exception.SystemException;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.util.Constants;
23  import com.liferay.portal.kernel.util.GetterUtil;
24  import com.liferay.portal.kernel.util.HttpUtil;
25  import com.liferay.portal.kernel.util.InstancePool;
26  import com.liferay.portal.kernel.util.LocaleUtil;
27  import com.liferay.portal.kernel.util.OrderByComparator;
28  import com.liferay.portal.kernel.util.PropertiesUtil;
29  import com.liferay.portal.kernel.util.PropsKeys;
30  import com.liferay.portal.kernel.util.StringBundler;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.util.Time;
34  import com.liferay.portal.kernel.util.Validator;
35  import com.liferay.portal.kernel.xml.Document;
36  import com.liferay.portal.kernel.xml.Element;
37  import com.liferay.portal.kernel.xml.Node;
38  import com.liferay.portal.kernel.xml.SAXReaderUtil;
39  import com.liferay.portal.kernel.xml.XPath;
40  import com.liferay.portal.model.Group;
41  import com.liferay.portal.model.Layout;
42  import com.liferay.portal.model.LayoutSet;
43  import com.liferay.portal.model.User;
44  import com.liferay.portal.service.ImageLocalServiceUtil;
45  import com.liferay.portal.service.LayoutLocalServiceUtil;
46  import com.liferay.portal.service.UserLocalServiceUtil;
47  import com.liferay.portal.theme.ThemeDisplay;
48  import com.liferay.portal.util.ContentUtil;
49  import com.liferay.portal.util.FriendlyURLNormalizer;
50  import com.liferay.portal.util.PropsUtil;
51  import com.liferay.portal.util.PropsValues;
52  import com.liferay.portal.util.WebKeys;
53  import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
54  import com.liferay.portlet.journal.TransformException;
55  import com.liferay.portlet.journal.model.JournalArticle;
56  import com.liferay.portlet.journal.model.JournalStructure;
57  import com.liferay.portlet.journal.model.JournalStructureConstants;
58  import com.liferay.portlet.journal.model.JournalTemplate;
59  import com.liferay.portlet.journal.service.JournalArticleImageLocalServiceUtil;
60  import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
61  import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
62  import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
63  import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
64  import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
65  import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
66  import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
67  import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
68  import com.liferay.util.FiniteUniqueStack;
69  import com.liferay.util.LocalizationUtil;
70  import com.liferay.util.xml.XMLFormatter;
71  
72  import java.io.IOException;
73  
74  import java.util.ArrayList;
75  import java.util.Date;
76  import java.util.HashMap;
77  import java.util.Iterator;
78  import java.util.List;
79  import java.util.Map;
80  import java.util.Stack;
81  
82  import javax.portlet.PortletPreferences;
83  import javax.portlet.PortletRequest;
84  import javax.portlet.PortletSession;
85  
86  /**
87   * <a href="JournalUtil.java.html"><b><i>View Source</i></b></a>
88   *
89   * @author Brian Wing Shun Chan
90   * @author Raymond Augé
91   * @author Wesley Gong
92   */
93  public class JournalUtil {
94  
95      public static final int MAX_STACK_SIZE = 20;
96  
97      public static final String POP_PORTLET_PREFIX = "journal.";
98  
99      public static final String XML_INDENT = "  ";
100 
101     public static void addAllReservedEls(
102         Element root, Map<String, String> tokens, JournalArticle article) {
103 
104         JournalUtil.addReservedEl(
105             root, tokens, JournalStructureConstants.RESERVED_ARTICLE_ID,
106             article.getArticleId());
107 
108         JournalUtil.addReservedEl(
109             root, tokens, JournalStructureConstants.RESERVED_ARTICLE_VERSION,
110             article.getVersion());
111 
112         JournalUtil.addReservedEl(
113             root, tokens, JournalStructureConstants.RESERVED_ARTICLE_TITLE,
114             article.getTitle());
115 
116         JournalUtil.addReservedEl(
117             root, tokens,
118             JournalStructureConstants.RESERVED_ARTICLE_URL_TITLE,
119             article.getUrlTitle());
120 
121         JournalUtil.addReservedEl(
122             root, tokens,
123             JournalStructureConstants.RESERVED_ARTICLE_DESCRIPTION,
124             article.getDescription());
125 
126         JournalUtil.addReservedEl(
127             root, tokens, JournalStructureConstants.RESERVED_ARTICLE_TYPE,
128             article.getType());
129 
130         JournalUtil.addReservedEl(
131             root, tokens,
132             JournalStructureConstants.RESERVED_ARTICLE_CREATE_DATE,
133             article.getCreateDate());
134 
135         JournalUtil.addReservedEl(
136             root, tokens,
137             JournalStructureConstants.RESERVED_ARTICLE_MODIFIED_DATE,
138             article.getModifiedDate());
139 
140         if (article.getDisplayDate() != null) {
141             JournalUtil.addReservedEl(
142                 root, tokens,
143                 JournalStructureConstants.RESERVED_ARTICLE_DISPLAY_DATE,
144                 article.getDisplayDate());
145         }
146 
147         JournalUtil.addReservedEl(
148             root, tokens,
149             JournalStructureConstants.RESERVED_ARTICLE_SMALL_IMAGE_URL,
150             article.getSmallImageURL());
151 
152         String[] assetTagNames = new String[0];
153 
154         try {
155             assetTagNames = AssetTagLocalServiceUtil.getTagNames(
156                 JournalArticle.class.getName(), article.getResourcePrimKey());
157         }
158         catch (SystemException se) {
159         }
160 
161         JournalUtil.addReservedEl(
162             root, tokens,
163             JournalStructureConstants.RESERVED_ARTICLE_ASSET_TAG_NAMES,
164             StringUtil.merge(assetTagNames));
165 
166         JournalUtil.addReservedEl(
167             root, tokens, JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_ID,
168             String.valueOf(article.getUserId()));
169 
170         String userName = StringPool.BLANK;
171         String userEmailAddress = StringPool.BLANK;
172         String userComments = StringPool.BLANK;
173         String userJobTitle = StringPool.BLANK;
174 
175         User user = null;
176 
177         try {
178             user = UserLocalServiceUtil.getUserById(article.getUserId());
179 
180             userName = user.getFullName();
181             userEmailAddress = user.getEmailAddress();
182             userComments = user.getComments();
183             userJobTitle = user.getJobTitle();
184         }
185         catch (PortalException pe) {
186         }
187         catch (SystemException se) {
188         }
189 
190         JournalUtil.addReservedEl(
191             root, tokens,
192             JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_NAME, userName);
193 
194         JournalUtil.addReservedEl(
195             root, tokens,
196             JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_EMAIL_ADDRESS,
197             userEmailAddress);
198 
199         JournalUtil.addReservedEl(
200             root, tokens,
201             JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_COMMENTS,
202             userComments);
203 
204         JournalUtil.addReservedEl(
205             root, tokens,
206             JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_JOB_TITLE,
207             userJobTitle);
208     }
209 
210     public static void addRecentArticle(
211         PortletRequest portletRequest, JournalArticle article) {
212 
213         if (article != null) {
214             Stack<JournalArticle> stack = getRecentArticles(portletRequest);
215 
216             stack.push(article);
217         }
218     }
219 
220     public static void addRecentStructure(
221         PortletRequest portletRequest, JournalStructure structure) {
222 
223         if (structure != null) {
224             Stack<JournalStructure> stack = getRecentStructures(portletRequest);
225 
226             stack.push(structure);
227         }
228     }
229 
230     public static void addRecentTemplate(
231         PortletRequest portletRequest, JournalTemplate template) {
232 
233         if (template != null) {
234             Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
235 
236             stack.push(template);
237         }
238     }
239 
240     public static void addReservedEl(
241         Element root, Map<String, String> tokens, String name, Date value) {
242 
243         addReservedEl(root, tokens, name, Time.getRFC822(value));
244     }
245 
246     public static void addReservedEl(
247         Element root, Map<String, String> tokens, String name, double value) {
248 
249         addReservedEl(root, tokens, name, String.valueOf(value));
250     }
251 
252     public static void addReservedEl(
253         Element root, Map<String, String> tokens, String name, String value) {
254 
255         // XML
256 
257         if (root != null) {
258             Element dynamicEl = SAXReaderUtil.createElement("dynamic-element");
259 
260             dynamicEl.add(
261                 SAXReaderUtil.createAttribute(dynamicEl, "name", name));
262             dynamicEl.add(
263                 SAXReaderUtil.createAttribute(dynamicEl, "type", "text"));
264 
265             Element dynamicContent = SAXReaderUtil.createElement(
266                 "dynamic-content");
267 
268             //dynamicContent.setText("<![CDATA[" + value + "]]>");
269             dynamicContent.setText(value);
270 
271             dynamicEl.add(dynamicContent);
272 
273             root.add(dynamicEl);
274         }
275 
276         // Tokens
277 
278         tokens.put(
279             StringUtil.replace(name, StringPool.DASH, StringPool.UNDERLINE),
280             value);
281     }
282 
283     public static String formatVM(String vm) {
284         return vm;
285     }
286 
287     public static String formatXML(Document doc) throws IOException {
288         return doc.formattedString(XML_INDENT);
289     }
290 
291     public static String formatXML(String xml)
292         throws org.dom4j.DocumentException, IOException {
293 
294         // This is only supposed to format your xml, however, it will also
295         // unwantingly change &#169; and other characters like it into their
296         // respective readable versions
297 
298         xml = StringUtil.replace(xml, "&#", "[$SPECIAL_CHARACTER$]");
299 
300         xml = XMLFormatter.toString(xml, XML_INDENT);
301 
302         xml = StringUtil.replace(xml, "[$SPECIAL_CHARACTER$]", "&#");
303 
304         return xml;
305     }
306 
307     public static OrderByComparator getArticleOrderByComparator(
308         String orderByCol, String orderByType) {
309 
310         boolean orderByAsc = false;
311 
312         if (orderByType.equals("asc")) {
313             orderByAsc = true;
314         }
315 
316         OrderByComparator orderByComparator = null;
317 
318         if (orderByCol.equals("create-date")) {
319             orderByComparator = new ArticleCreateDateComparator(orderByAsc);
320         }
321         else if (orderByCol.equals("display-date")) {
322             orderByComparator = new ArticleDisplayDateComparator(orderByAsc);
323         }
324         else if (orderByCol.equals("id")) {
325             orderByComparator = new ArticleIDComparator(orderByAsc);
326         }
327         else if (orderByCol.equals("modified-date")) {
328             orderByComparator = new ArticleModifiedDateComparator(orderByAsc);
329         }
330         else if (orderByCol.equals("review-date")) {
331             orderByComparator = new ArticleReviewDateComparator(orderByAsc);
332         }
333         else if (orderByCol.equals("title")) {
334             orderByComparator = new ArticleTitleComparator(orderByAsc);
335         }
336         else if (orderByCol.equals("version")) {
337             orderByComparator = new ArticleVersionComparator(orderByAsc);
338         }
339 
340         return orderByComparator;
341     }
342 
343     public static String getEmailArticleAddedBody(
344         PortletPreferences preferences) {
345 
346         String emailArticleAddedBody = preferences.getValue(
347             "email-article-added-body", StringPool.BLANK);
348 
349         if (Validator.isNotNull(emailArticleAddedBody)) {
350             return emailArticleAddedBody;
351         }
352         else {
353             return ContentUtil.get(PropsUtil.get(
354                 PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_BODY));
355         }
356     }
357 
358     public static boolean getEmailArticleAddedEnabled(
359         PortletPreferences preferences) {
360 
361         String emailArticleAddedEnabled = preferences.getValue(
362             "email-article-added-enabled", StringPool.BLANK);
363 
364         if (Validator.isNotNull(emailArticleAddedEnabled)) {
365             return GetterUtil.getBoolean(emailArticleAddedEnabled);
366         }
367         else {
368             return GetterUtil.getBoolean(PropsUtil.get(
369                 PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_ENABLED));
370         }
371     }
372 
373     public static String getEmailArticleAddedSubject(
374         PortletPreferences preferences) {
375 
376         String emailArticleAddedSubject = preferences.getValue(
377             "email-article-added-subject", StringPool.BLANK);
378 
379         if (Validator.isNotNull(emailArticleAddedSubject)) {
380             return emailArticleAddedSubject;
381         }
382         else {
383             return ContentUtil.get(PropsUtil.get(
384                 PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_SUBJECT));
385         }
386     }
387 
388     public static String getEmailArticleApprovalDeniedBody(
389         PortletPreferences preferences) {
390 
391         String emailArticleApprovalDeniedBody = preferences.getValue(
392             "email-article-approval-denied-body", StringPool.BLANK);
393 
394         if (Validator.isNotNull(emailArticleApprovalDeniedBody)) {
395             return emailArticleApprovalDeniedBody;
396         }
397         else {
398             return ContentUtil.get(PropsUtil.get(
399                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_BODY));
400         }
401     }
402 
403     public static boolean getEmailArticleApprovalDeniedEnabled(
404         PortletPreferences preferences) {
405 
406         String emailArticleApprovalDeniedEnabled = preferences.getValue(
407             "email-article-approval-denied-enabled", StringPool.BLANK);
408 
409         if (Validator.isNotNull(emailArticleApprovalDeniedEnabled)) {
410             return GetterUtil.getBoolean(emailArticleApprovalDeniedEnabled);
411         }
412         else {
413             return GetterUtil.getBoolean(PropsUtil.get(
414                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_ENABLED));
415         }
416     }
417 
418     public static String getEmailArticleApprovalDeniedSubject(
419         PortletPreferences preferences) {
420 
421         String emailArticleApprovalDeniedSubject = preferences.getValue(
422             "email-article-approval-denied-subject", StringPool.BLANK);
423 
424         if (Validator.isNotNull(emailArticleApprovalDeniedSubject)) {
425             return emailArticleApprovalDeniedSubject;
426         }
427         else {
428             return ContentUtil.get(PropsUtil.get(
429                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_SUBJECT));
430         }
431     }
432 
433     public static String getEmailArticleApprovalGrantedBody(
434         PortletPreferences preferences) {
435 
436         String emailArticleApprovalGrantedBody = preferences.getValue(
437             "email-article-approval-granted-body", StringPool.BLANK);
438 
439         if (Validator.isNotNull(emailArticleApprovalGrantedBody)) {
440             return emailArticleApprovalGrantedBody;
441         }
442         else {
443             return ContentUtil.get(PropsUtil.get(
444                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_BODY));
445         }
446     }
447 
448     public static boolean getEmailArticleApprovalGrantedEnabled(
449         PortletPreferences preferences) {
450 
451         String emailArticleApprovalGrantedEnabled = preferences.getValue(
452             "email-article-approval-granted-enabled", StringPool.BLANK);
453 
454         if (Validator.isNotNull(emailArticleApprovalGrantedEnabled)) {
455             return GetterUtil.getBoolean(emailArticleApprovalGrantedEnabled);
456         }
457         else {
458             return GetterUtil.getBoolean(PropsUtil.get(
459                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_ENABLED));
460         }
461     }
462 
463     public static String getEmailArticleApprovalGrantedSubject(
464         PortletPreferences preferences) {
465 
466         String emailArticleApprovalGrantedSubject = preferences.getValue(
467             "email-article-approval-granted-subject", StringPool.BLANK);
468 
469         if (Validator.isNotNull(emailArticleApprovalGrantedSubject)) {
470             return emailArticleApprovalGrantedSubject;
471         }
472         else {
473             return ContentUtil.get(PropsUtil.get(
474                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_SUBJECT));
475         }
476     }
477 
478     public static String getEmailArticleApprovalRequestedBody(
479         PortletPreferences preferences) {
480 
481         String emailArticleApprovalRequestedBody = preferences.getValue(
482             "email-article-approval-requested-body", StringPool.BLANK);
483 
484         if (Validator.isNotNull(emailArticleApprovalRequestedBody)) {
485             return emailArticleApprovalRequestedBody;
486         }
487         else {
488             return ContentUtil.get(PropsUtil.get(
489                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_BODY));
490         }
491     }
492 
493     public static boolean getEmailArticleApprovalRequestedEnabled(
494         PortletPreferences preferences) {
495 
496         String emailArticleApprovalRequestedEnabled = preferences.getValue(
497             "email-article-approval-requested-enabled", StringPool.BLANK);
498 
499         if (Validator.isNotNull(emailArticleApprovalRequestedEnabled)) {
500             return GetterUtil.getBoolean(emailArticleApprovalRequestedEnabled);
501         }
502         else {
503             return GetterUtil.getBoolean(PropsUtil.get(
504                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_ENABLED));
505         }
506     }
507 
508     public static String getEmailArticleApprovalRequestedSubject(
509         PortletPreferences preferences) {
510 
511         String emailArticleApprovalRequestedSubject = preferences.getValue(
512             "email-article-approval-requested-subject", StringPool.BLANK);
513 
514         if (Validator.isNotNull(emailArticleApprovalRequestedSubject)) {
515             return emailArticleApprovalRequestedSubject;
516         }
517         else {
518             return ContentUtil.get(PropsUtil.get(
519                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_SUBJECT));
520         }
521     }
522 
523     public static String getEmailArticleReviewBody(
524         PortletPreferences preferences) {
525 
526         String emailArticleReviewBody = preferences.getValue(
527             "email-article-review-body", StringPool.BLANK);
528 
529         if (Validator.isNotNull(emailArticleReviewBody)) {
530             return emailArticleReviewBody;
531         }
532         else {
533             return ContentUtil.get(PropsUtil.get(
534                 PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_BODY));
535         }
536     }
537 
538     public static boolean getEmailArticleReviewEnabled(
539         PortletPreferences preferences) {
540 
541         String emailArticleReviewEnabled = preferences.getValue(
542             "email-article-review-enabled", StringPool.BLANK);
543 
544         if (Validator.isNotNull(emailArticleReviewEnabled)) {
545             return GetterUtil.getBoolean(emailArticleReviewEnabled);
546         }
547         else {
548             return GetterUtil.getBoolean(PropsUtil.get(
549                 PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_ENABLED));
550         }
551     }
552 
553     public static String getEmailArticleReviewSubject(
554         PortletPreferences preferences) {
555 
556         String emailArticleReviewSubject = preferences.getValue(
557             "email-article-review-subject", StringPool.BLANK);
558 
559         if (Validator.isNotNull(emailArticleReviewSubject)) {
560             return emailArticleReviewSubject;
561         }
562         else {
563             return ContentUtil.get(PropsUtil.get(
564                 PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_SUBJECT));
565         }
566     }
567 
568     public static String getEmailArticleUpdatedBody(
569         PortletPreferences preferences) {
570 
571         String emailArticleUpdatedBody = preferences.getValue(
572             "email-article-updated-body", StringPool.BLANK);
573 
574         if (Validator.isNotNull(emailArticleUpdatedBody)) {
575             return emailArticleUpdatedBody;
576         }
577         else {
578             return ContentUtil.get(PropsUtil.get(
579                 PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_BODY));
580         }
581     }
582 
583     public static boolean getEmailArticleUpdatedEnabled(
584         PortletPreferences preferences) {
585 
586         String emailArticleUpdatedEnabled = preferences.getValue(
587             "email-article-updated-enabled", StringPool.BLANK);
588 
589         if (Validator.isNotNull(emailArticleUpdatedEnabled)) {
590             return GetterUtil.getBoolean(emailArticleUpdatedEnabled);
591         }
592         else {
593             return GetterUtil.getBoolean(PropsUtil.get(
594                 PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_ENABLED));
595         }
596     }
597 
598     public static String getEmailArticleUpdatedSubject(
599         PortletPreferences preferences) {
600 
601         String emailArticleUpdatedSubject = preferences.getValue(
602             "email-article-updated-subject", StringPool.BLANK);
603 
604         if (Validator.isNotNull(emailArticleUpdatedSubject)) {
605             return emailArticleUpdatedSubject;
606         }
607         else {
608             return ContentUtil.get(PropsUtil.get(
609                 PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_SUBJECT));
610         }
611     }
612 
613     public static String getEmailFromAddress(PortletPreferences preferences) {
614         String emailFromAddress = PropsUtil.get(
615             PropsKeys.JOURNAL_EMAIL_FROM_ADDRESS);
616 
617         return preferences.getValue("email-from-address", emailFromAddress);
618     }
619 
620     public static String getEmailFromName(PortletPreferences preferences) {
621         String emailFromName = PropsUtil.get(
622             PropsKeys.JOURNAL_EMAIL_FROM_NAME);
623 
624         return preferences.getValue("email-from-name", emailFromName);
625     }
626 
627     public static String getMailId(String mx, String articleId) {
628         StringBundler sb = new StringBundler(8);
629 
630         sb.append(StringPool.LESS_THAN);
631         sb.append(POP_PORTLET_PREFIX);
632         sb.append(articleId);
633         sb.append(StringPool.AT);
634         sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
635         sb.append(StringPool.PERIOD);
636         sb.append(mx);
637         sb.append(StringPool.GREATER_THAN);
638 
639         return sb.toString();
640     }
641 
642     public static Stack<JournalArticle> getRecentArticles(
643         PortletRequest portletRequest) {
644 
645         PortletSession portletSession = portletRequest.getPortletSession();
646 
647         Stack<JournalArticle> recentArticles =
648             (Stack<JournalArticle>)portletSession.getAttribute(
649                 WebKeys.JOURNAL_RECENT_ARTICLES);
650 
651         if (recentArticles == null) {
652             recentArticles = new FiniteUniqueStack<JournalArticle>(
653                 MAX_STACK_SIZE);
654 
655             portletSession.setAttribute(
656                 WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
657         }
658 
659         return recentArticles;
660     }
661 
662     public static Stack<JournalStructure> getRecentStructures(
663         PortletRequest portletRequest) {
664 
665         PortletSession portletSession = portletRequest.getPortletSession();
666 
667         Stack<JournalStructure> recentStructures =
668             (Stack<JournalStructure>)portletSession.getAttribute(
669                 WebKeys.JOURNAL_RECENT_STRUCTURES);
670 
671         if (recentStructures == null) {
672             recentStructures = new FiniteUniqueStack<JournalStructure>(
673                 MAX_STACK_SIZE);
674 
675             portletSession.setAttribute(
676                 WebKeys.JOURNAL_RECENT_STRUCTURES, recentStructures);
677         }
678 
679         return recentStructures;
680     }
681 
682     public static Stack<JournalTemplate> getRecentTemplates(
683         PortletRequest portletRequest) {
684 
685         PortletSession portletSession = portletRequest.getPortletSession();
686 
687         Stack<JournalTemplate> recentTemplates =
688             (Stack<JournalTemplate>)portletSession.getAttribute(
689                 WebKeys.JOURNAL_RECENT_TEMPLATES);
690 
691         if (recentTemplates == null) {
692             recentTemplates = new FiniteUniqueStack<JournalTemplate>(
693                 MAX_STACK_SIZE);
694 
695             portletSession.setAttribute(
696                 WebKeys.JOURNAL_RECENT_TEMPLATES, recentTemplates);
697         }
698 
699         return recentTemplates;
700     }
701 
702     public static String getTemplateScript(
703         JournalTemplate template, Map<String, String> tokens, String languageId,
704         boolean transform) {
705 
706         String script = template.getXsl();
707 
708         if (transform) {
709 
710             // Listeners
711 
712             String[] listeners =
713                 PropsUtil.getArray(PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
714 
715             for (int i = 0; i < listeners.length; i++) {
716                 TransformerListener listener = null;
717 
718                 try {
719                     listener =
720                         (TransformerListener)Class.forName(
721                             listeners[i]).newInstance();
722 
723                     listener.setTemplateDriven(true);
724                     listener.setLanguageId(languageId);
725                     listener.setTokens(tokens);
726                 }
727                 catch (Exception e) {
728                     _log.error(e, e);
729                 }
730 
731                 // Modify transform script
732 
733                 if (listener != null) {
734                     script = listener.onScript(script);
735                 }
736             }
737         }
738 
739         return script;
740     }
741 
742     public static String getTemplateScript(
743             long groupId, String templateId, Map<String, String> tokens,
744             String languageId)
745         throws PortalException, SystemException {
746 
747         return getTemplateScript(groupId, templateId, tokens, languageId, true);
748     }
749 
750     public static String getTemplateScript(
751             long groupId, String templateId, Map<String, String> tokens,
752             String languageId, boolean transform)
753         throws PortalException, SystemException {
754 
755         JournalTemplate template = JournalTemplateLocalServiceUtil.getTemplate(
756             groupId, templateId);
757 
758         return getTemplateScript(template, tokens, languageId, transform);
759     }
760 
761     public static Map<String, String> getTokens(
762         long groupId, ThemeDisplay themeDisplay) {
763 
764         return getTokens(groupId, themeDisplay, null);
765     }
766 
767     public static Map<String, String> getTokens(
768         long groupId, ThemeDisplay themeDisplay, String xmlRequest) {
769 
770         Map<String, String> tokens = new HashMap<String, String>();
771 
772         if (themeDisplay != null) {
773             _populateTokens(tokens, groupId, themeDisplay);
774         }
775         else if (Validator.isNotNull(xmlRequest)) {
776             try {
777                 _populateTokens(tokens, groupId, xmlRequest);
778             }
779             catch (Exception e) {
780                 if (_log.isWarnEnabled()) {
781                     _log.warn(e, e);
782                 }
783             }
784         }
785 
786         return tokens;
787     }
788 
789     public static String getUrlTitle(long id, String title) {
790         title = title.trim().toLowerCase();
791 
792         if (Validator.isNull(title) || Validator.isNumber(title) ||
793             title.equals("rss")) {
794 
795             return String.valueOf(id);
796         }
797         else {
798             return FriendlyURLNormalizer.normalize(
799                 title, _URL_TITLE_REPLACE_CHARS);
800         }
801     }
802 
803     public static String mergeArticleContent(
804         String curContent, String newContent) {
805 
806         try {
807             Document curDocument = SAXReaderUtil.read(curContent);
808             Document newDocument = SAXReaderUtil.read(newContent);
809 
810             Element curRoot = curDocument.getRootElement();
811             Element newRoot = newDocument.getRootElement();
812 
813             curRoot.addAttribute(
814                 "default-locale",
815                 newRoot.attributeValue("default-locale"));
816             curRoot.addAttribute(
817                 "available-locales",
818                 newRoot.attributeValue("available-locales"));
819 
820             _mergeArticleContentUpdate(
821                 curDocument, newRoot,
822                 LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
823             _mergeArticleContentDelete(curRoot, newDocument);
824 
825             curContent = JournalUtil.formatXML(curDocument);
826         }
827         catch (Exception e) {
828             _log.error(e, e);
829         }
830 
831         return curContent;
832     }
833 
834     public static void removeArticleLocale(Element el, String languageId)
835         throws PortalException, SystemException {
836 
837         for (Element dynamicEl : el.elements("dynamic-element")) {
838             for (Element dynamicContentEl :
839                     dynamicEl.elements("dynamic-content")) {
840 
841                 String curLanguageId = GetterUtil.getString(
842                     dynamicContentEl.attributeValue("language-id"));
843 
844                 if (curLanguageId.equals(languageId)) {
845                     long id = GetterUtil.getLong(
846                         dynamicContentEl.attributeValue("id"));
847 
848                     if (id > 0) {
849                         ImageLocalServiceUtil.deleteImage(id);
850                     }
851 
852                     dynamicContentEl.detach();
853                 }
854             }
855 
856             removeArticleLocale(dynamicEl, languageId);
857         }
858     }
859 
860     public static String removeArticleLocale(
861         String content, String languageId) {
862 
863         try {
864             Document doc = SAXReaderUtil.read(content);
865 
866             Element root = doc.getRootElement();
867 
868             String availableLocales = root.attributeValue("available-locales");
869 
870             if (availableLocales == null) {
871                 return content;
872             }
873 
874             availableLocales = StringUtil.remove(availableLocales, languageId);
875 
876             if (availableLocales.endsWith(",")) {
877                 availableLocales = availableLocales.substring(
878                     0, availableLocales.length() - 1);
879             }
880 
881             root.addAttribute("available-locales", availableLocales);
882 
883             removeArticleLocale(root, languageId);
884 
885             content = formatXML(doc);
886         }
887         catch (Exception e) {
888             _log.error(e, e);
889         }
890 
891         return content;
892     }
893 
894     public static String removeOldContent(String content, String xsd) {
895         try {
896             Document contentDoc = SAXReaderUtil.read(content);
897             Document xsdDoc = SAXReaderUtil.read(xsd);
898 
899             Element contentRoot = contentDoc.getRootElement();
900 
901             Stack<String> path = new Stack<String>();
902 
903             path.push(contentRoot.getName());
904 
905             _removeOldContent(path, contentRoot, xsdDoc);
906 
907             content = formatXML(contentDoc);
908         }
909         catch (Exception e) {
910             _log.error(e, e);
911         }
912 
913         return content;
914     }
915 
916     public static void removeRecentArticle(
917         PortletRequest portletRequest, String articleId) {
918 
919         Stack<JournalArticle> stack = getRecentArticles(portletRequest);
920 
921         Iterator<JournalArticle> itr = stack.iterator();
922 
923         while (itr.hasNext()) {
924             JournalArticle journalArticle = itr.next();
925 
926             if (journalArticle.getArticleId().equals(articleId)) {
927                 itr.remove();
928 
929                 break;
930             }
931         }
932     }
933 
934     public static void removeRecentStructure(
935         PortletRequest portletRequest, String structureId) {
936 
937         Stack<JournalStructure> stack = getRecentStructures(portletRequest);
938 
939         Iterator<JournalStructure> itr = stack.iterator();
940 
941         while (itr.hasNext()) {
942             JournalStructure journalStructure = itr.next();
943 
944             if (journalStructure.getStructureId().equals(structureId)) {
945                 itr.remove();
946 
947                 break;
948             }
949         }
950     }
951 
952     public static void removeRecentTemplate(
953         PortletRequest portletRequest, String templateId) {
954 
955         Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
956 
957         Iterator<JournalTemplate> itr = stack.iterator();
958 
959         while (itr.hasNext()) {
960             JournalTemplate journalTemplate = itr.next();
961 
962             if (journalTemplate.getTemplateId().equals(templateId)) {
963                 itr.remove();
964 
965                 break;
966             }
967         }
968     }
969 
970     public static String transform(
971             Map<String, String> tokens, String viewMode, String languageId,
972             String xml, String script, String langType)
973         throws Exception {
974 
975         // Setup Listeners
976 
977         if (_log.isDebugEnabled()) {
978             _log.debug("Language " + languageId);
979         }
980 
981         if (Validator.isNull(viewMode)) {
982             viewMode = Constants.VIEW;
983         }
984 
985         if (_logTokens.isDebugEnabled()) {
986             String tokensString = PropertiesUtil.list(tokens);
987 
988             _logTokens.debug(tokensString);
989         }
990 
991         if (_logTransformBefore.isDebugEnabled()) {
992             _logTransformBefore.debug(xml);
993         }
994 
995         List<TransformerListener> listenersList =
996             new ArrayList<TransformerListener>();
997 
998         String[] listeners = PropsUtil.getArray(
999             PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
1000
1001        for (int i = 0; i < listeners.length; i++) {
1002            TransformerListener listener = null;
1003
1004            try {
1005                if (_log.isDebugEnabled()) {
1006                    _log.debug("Instantiate listener " + listeners[i]);
1007                }
1008
1009                boolean templateDriven = Validator.isNotNull(langType);
1010
1011                listener = (TransformerListener)Class.forName(
1012                    listeners[i]).newInstance();
1013
1014                listener.setTemplateDriven(templateDriven);
1015                listener.setLanguageId(languageId);
1016                listener.setTokens(tokens);
1017
1018                listenersList.add(listener);
1019            }
1020            catch (Exception e) {
1021                _log.error(e, e);
1022            }
1023
1024            // Modify XML
1025
1026            if (_logXmlBeforeListener.isDebugEnabled()) {
1027                _logXmlBeforeListener.debug(xml);
1028            }
1029
1030            if (listener != null) {
1031                xml = listener.onXml(xml);
1032
1033                if (_logXmlAfterListener.isDebugEnabled()) {
1034                    _logXmlAfterListener.debug(xml);
1035                }
1036            }
1037
1038            // Modify script
1039
1040            if (_logScriptBeforeListener.isDebugEnabled()) {
1041                _logScriptBeforeListener.debug(script);
1042            }
1043
1044            if (listener != null) {
1045                script = listener.onScript(script);
1046
1047                if (_logScriptAfterListener.isDebugEnabled()) {
1048                    _logScriptAfterListener.debug(script);
1049                }
1050            }
1051        }
1052
1053        // Transform
1054
1055        String output = null;
1056
1057        if (Validator.isNull(langType)) {
1058            output = LocalizationUtil.getLocalization(xml, languageId);
1059        }
1060        else {
1061            String templateParserClassName = PropsUtil.get(
1062                PropsKeys.JOURNAL_TEMPLATE_LANGUAGE_PARSER,
1063                new Filter(langType));
1064
1065            if (_log.isDebugEnabled()) {
1066                _log.debug(
1067                    "Template parser class name " + templateParserClassName);
1068            }
1069
1070            if (Validator.isNotNull(templateParserClassName)) {
1071                TemplateParser templateParser =
1072                    (TemplateParser)InstancePool.get(templateParserClassName);
1073
1074                if (templateParser == null) {
1075                    throw new TransformException(
1076                        "No template parser found for " +
1077                            templateParserClassName);
1078                }
1079
1080                output = templateParser.transform(
1081                    tokens, viewMode, languageId, xml, script);
1082            }
1083        }
1084
1085        // Postprocess output
1086
1087        for (int i = 0; i < listenersList.size(); i++) {
1088            TransformerListener listener = listenersList.get(i);
1089
1090            // Modify output
1091
1092            if (_logOutputBeforeListener.isDebugEnabled()) {
1093                _logOutputBeforeListener.debug(output);
1094            }
1095
1096            output = listener.onOutput(output);
1097
1098            if (_logOutputAfterListener.isDebugEnabled()) {
1099                _logOutputAfterListener.debug(output);
1100            }
1101        }
1102
1103        if (_logTransfromAfter.isDebugEnabled()) {
1104            _logTransfromAfter.debug(output);
1105        }
1106
1107        return output;
1108    }
1109
1110    private static void _addElementOptions (
1111        Element curContentElement, Element newContentElement) {
1112
1113        List<Element> newElementOptions = newContentElement.elements("option");
1114
1115        for (Element newElementOption : newElementOptions) {
1116            Element curElementOption = SAXReaderUtil.createElement("option");
1117
1118            curElementOption.addCDATA(newElementOption.getText());
1119
1120            curContentElement.add(curElementOption);
1121        }
1122    }
1123
1124    private static Element _getElementByInstanceId(
1125        Document document, String instanceId) {
1126
1127        XPath xPathSelector = SAXReaderUtil.createXPath(
1128            "//dynamic-element[@instance-id='" + instanceId + "']");
1129
1130        List<Node> nodes = xPathSelector.selectNodes(document);
1131
1132        if (nodes.size() == 1) {
1133            return (Element)nodes.get(0);
1134        }
1135        else {
1136            return null;
1137        }
1138    }
1139
1140    private static void _mergeArticleContentDelete(
1141            Element curParentElement, Document newDocument)
1142        throws Exception {
1143
1144        List<Element> curElements = curParentElement.elements(
1145            "dynamic-element");
1146
1147        for (int i = 0; i < curElements.size(); i++) {
1148            Element curElement = curElements.get(i);
1149
1150            _mergeArticleContentDelete(curElement, newDocument);
1151
1152            String instanceId = curElement.attributeValue("instance-id");
1153
1154            Element newElement = _getElementByInstanceId(
1155                newDocument, instanceId);
1156
1157            if (newElement == null) {
1158                curElement.detach();
1159
1160                String type = curElement.attributeValue("type");
1161
1162                if (type.equals("image")) {
1163                    _mergeArticleContentDeleteImages(
1164                        curElement.elements("dynamic-content"));
1165                }
1166            }
1167        }
1168    }
1169
1170    private static void _mergeArticleContentDeleteImages(List<Element> elements)
1171        throws Exception {
1172
1173        for (Element element : elements) {
1174            long articleImageId = GetterUtil.getLong(
1175                element.attributeValue("id"));
1176
1177            JournalArticleImageLocalServiceUtil.deleteArticleImage(
1178                articleImageId);
1179        }
1180    }
1181
1182    private static void _mergeArticleContentUpdate(
1183            Document curDocument, Element newParentElement, Element newElement,
1184            int pos, String defaultLocale)
1185        throws Exception {
1186
1187        _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1188
1189        String instanceId = newElement.attributeValue("instance-id");
1190
1191        Element curElement = _getElementByInstanceId(curDocument, instanceId);
1192
1193        if (curElement != null) {
1194            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1195        }
1196        else {
1197            String parentInstanceId = newParentElement.attributeValue(
1198                "instance-id");
1199
1200            if (Validator.isNull(parentInstanceId)) {
1201                Element curRoot = curDocument.getRootElement();
1202
1203                List<Element> curRootElements = curRoot.elements();
1204
1205                curRootElements.add(pos, newElement.createCopy());
1206            }
1207            else {
1208                Element curParentElement = _getElementByInstanceId(
1209                    curDocument, parentInstanceId);
1210
1211                if (curParentElement != null) {
1212                    List<Element> curParentElements =
1213                        curParentElement.elements();
1214
1215                    curParentElements.add(pos, newElement.createCopy());
1216                }
1217            }
1218        }
1219    }
1220
1221    private static void _mergeArticleContentUpdate(
1222            Document curDocument, Element newParentElement,
1223            String defaultLocale)
1224        throws Exception {
1225
1226        List<Element> newElements = newParentElement.elements(
1227            "dynamic-element");
1228
1229        for (int i = 0; i < newElements.size(); i++) {
1230            Element newElement = newElements.get(i);
1231
1232            _mergeArticleContentUpdate(
1233                curDocument, newParentElement, newElement, i, defaultLocale);
1234        }
1235    }
1236
1237    private static void _mergeArticleContentUpdate(
1238        Element curElement, Element newElement, String defaultLocale) {
1239
1240        Element newContentElement = newElement.elements(
1241            "dynamic-content").get(0);
1242
1243        String newLanguageId = newContentElement.attributeValue("language-id");
1244        String newValue = newContentElement.getText();
1245
1246        List<Element> curContentElements = curElement.elements(
1247            "dynamic-content");
1248
1249        if (Validator.isNull(newLanguageId)) {
1250            for (Element curContentElement : curContentElements) {
1251                curContentElement.detach();
1252            }
1253
1254            Element curContentElement = SAXReaderUtil.createElement(
1255                "dynamic-content");
1256
1257            if (newContentElement.element("option") != null) {
1258                _addElementOptions(curContentElement, newContentElement);
1259            }
1260            else {
1261                curContentElement.addCDATA(newValue);
1262            }
1263
1264            curElement.add(curContentElement);
1265        }
1266        else {
1267            boolean alreadyExists = false;
1268
1269            for (Element curContentElement : curContentElements) {
1270                String curLanguageId = curContentElement.attributeValue(
1271                    "language-id");
1272
1273                if (newLanguageId.equals(curLanguageId)) {
1274                    alreadyExists = true;
1275
1276                    curContentElement.clearContent();
1277
1278                    if (newContentElement.element("option") != null) {
1279                        _addElementOptions(
1280                            curContentElement, newContentElement);
1281                    }
1282                    else {
1283                        curContentElement.addCDATA(newValue);
1284                    }
1285
1286                    break;
1287                }
1288            }
1289
1290            if (!alreadyExists) {
1291                Element curContentElement = curContentElements.get(0);
1292
1293                String curLanguageId = curContentElement.attributeValue(
1294                    "language-id");
1295
1296                if (Validator.isNull(curLanguageId)) {
1297                    curContentElement.detach();
1298                }
1299
1300                curElement.add(newContentElement.createCopy());
1301            }
1302        }
1303    }
1304
1305    private static void _populateTokens(
1306            Map<String, String> tokens, long groupId, String xmlRequest)
1307        throws Exception {
1308
1309        Document request = SAXReaderUtil.read(xmlRequest);
1310
1311        Element root = request.getRootElement();
1312
1313        Element themeDisplayEl = root.element("theme-display");
1314
1315        Layout layout = LayoutLocalServiceUtil.getLayout(
1316            GetterUtil.getLong(themeDisplayEl.elementText("plid")));
1317
1318        Group group = layout.getGroup();
1319
1320        LayoutSet layoutSet = layout.getLayoutSet();
1321
1322        String friendlyUrlCurrent = null;
1323
1324        if (layout.isPublicLayout()) {
1325            friendlyUrlCurrent = themeDisplayEl.elementText(
1326                "path-friendly-url-public");
1327        }
1328        else if (group.isUserGroup()) {
1329            friendlyUrlCurrent = themeDisplayEl.elementText(
1330                "path-friendly-url-private-user");
1331        }
1332        else {
1333            friendlyUrlCurrent = themeDisplayEl.elementText(
1334                "path-friendly-url-private-group");
1335        }
1336
1337        String layoutSetFriendlyUrl = StringPool.BLANK;
1338
1339        String virtualHost = layoutSet.getVirtualHost();
1340
1341        if (Validator.isNull(virtualHost) ||
1342            !virtualHost.equals(themeDisplayEl.elementText("server-name"))) {
1343
1344            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1345        }
1346
1347        tokens.put("cdn_host", themeDisplayEl.elementText("cdn-host"));
1348        tokens.put("company_id", themeDisplayEl.elementText("company-id"));
1349        tokens.put("friendly_url_current", friendlyUrlCurrent);
1350        tokens.put(
1351            "friendly_url_private_group",
1352            themeDisplayEl.elementText("path-friendly-url-private-group"));
1353        tokens.put(
1354            "friendly_url_private_user",
1355            themeDisplayEl.elementText("path-friendly-url-private-user"));
1356        tokens.put(
1357            "friendly_url_public",
1358            themeDisplayEl.elementText("path-friendly-url-public"));
1359        tokens.put("group_friendly_url", group.getFriendlyURL());
1360        tokens.put("group_id", String.valueOf(groupId));
1361        tokens.put("image_path", themeDisplayEl.elementText("path-image"));
1362        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1363        tokens.put("main_path", themeDisplayEl.elementText("path-main"));
1364        tokens.put("portal_ctx", themeDisplayEl.elementText("path-context"));
1365        tokens.put(
1366            "portal_url",
1367            HttpUtil.removeProtocol(themeDisplayEl.elementText("url-portal")));
1368        tokens.put(
1369            "protocol",
1370            HttpUtil.getProtocol(themeDisplayEl.elementText("url-portal")));
1371        tokens.put("root_path", themeDisplayEl.elementText("path-context"));
1372        tokens.put(
1373            "theme_image_path",
1374            themeDisplayEl.elementText("path-theme-images"));
1375
1376        // Deprecated tokens
1377
1378        tokens.put(
1379            "friendly_url",
1380            themeDisplayEl.elementText("path-friendly-url-public"));
1381        tokens.put(
1382            "friendly_url_private",
1383            themeDisplayEl.elementText("path-friendly-url-private-group"));
1384        tokens.put(
1385            "page_url", themeDisplayEl.elementText("path-friendly-url-public"));
1386    }
1387
1388    private static void _populateTokens(
1389        Map<String, String> tokens, long groupId, ThemeDisplay themeDisplay) {
1390
1391        Layout layout = themeDisplay.getLayout();
1392
1393        Group group = layout.getGroup();
1394
1395        LayoutSet layoutSet = layout.getLayoutSet();
1396
1397        String friendlyUrlCurrent = null;
1398
1399        if (layout.isPublicLayout()) {
1400            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1401        }
1402        else if (group.isUserGroup()) {
1403            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1404        }
1405        else {
1406            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1407        }
1408
1409        String layoutSetFriendlyUrl = StringPool.BLANK;
1410
1411        String virtualHost = layoutSet.getVirtualHost();
1412
1413        if (Validator.isNull(virtualHost) ||
1414            !virtualHost.equals(themeDisplay.getServerName())) {
1415
1416            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1417        }
1418
1419        tokens.put("cdn_host", themeDisplay.getCDNHost());
1420        tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1421        tokens.put("friendly_url_current", friendlyUrlCurrent);
1422        tokens.put(
1423            "friendly_url_private_group",
1424            themeDisplay.getPathFriendlyURLPrivateGroup());
1425        tokens.put(
1426            "friendly_url_private_user",
1427            themeDisplay.getPathFriendlyURLPrivateUser());
1428        tokens.put(
1429            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1430        tokens.put("group_friendly_url", group.getFriendlyURL());
1431        tokens.put("group_id", String.valueOf(groupId));
1432        tokens.put("image_path", themeDisplay.getPathImage());
1433        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1434        tokens.put("main_path", themeDisplay.getPathMain());
1435        tokens.put("portal_ctx", themeDisplay.getPathContext());
1436        tokens.put(
1437            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1438        tokens.put(
1439            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1440        tokens.put("root_path", themeDisplay.getPathContext());
1441        tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1442
1443        // Deprecated tokens
1444
1445        tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1446        tokens.put(
1447            "friendly_url_private",
1448            themeDisplay.getPathFriendlyURLPrivateGroup());
1449        tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1450    }
1451
1452    private static void _removeOldContent(
1453            Stack<String> path, Element contentEl, Document xsdDoc)
1454        throws SystemException {
1455
1456        String elPath = "";
1457
1458        for (int i = 0; i < path.size(); i++) {
1459            elPath += "/" + path.elementAt(i);
1460        }
1461
1462        for (int i = 0; i < contentEl.nodeCount(); i++) {
1463            Node contentNode = contentEl.node(i);
1464
1465            if (contentNode instanceof Element) {
1466                _removeOldContent(path, (Element)contentNode, xsdDoc, elPath);
1467            }
1468        }
1469    }
1470
1471    private static void _removeOldContent(
1472            Stack<String> path, Element contentEl, Document xsdDoc,
1473            String elPath)
1474        throws SystemException {
1475
1476        String name = contentEl.attributeValue("name");
1477
1478        if (Validator.isNull(name)) {
1479            return;
1480        }
1481
1482        String localPath = "dynamic-element[@name='" + name + "']";
1483
1484        String fullPath = elPath + "/" + localPath;
1485
1486        XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1487
1488        List<Node> curNodes = xPathSelector.selectNodes(xsdDoc);
1489
1490        if (curNodes.size() == 0) {
1491            contentEl.detach();
1492        }
1493
1494        path.push(localPath);
1495
1496        _removeOldContent(path, contentEl, xsdDoc);
1497
1498        path.pop();
1499    }
1500
1501    private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
1502        '.', '/'
1503    };
1504
1505    private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1506
1507    private static Log _logOutputAfterListener = LogFactoryUtil.getLog(
1508        JournalUtil.class.getName() + ".OutputAfterListener");
1509
1510    private static Log _logOutputBeforeListener = LogFactoryUtil.getLog(
1511        JournalUtil.class.getName() + ".OutputBeforeListener");
1512
1513    private static Log _logScriptAfterListener = LogFactoryUtil.getLog(
1514        JournalUtil.class.getName() + ".ScriptAfterListener");
1515
1516    private static Log _logScriptBeforeListener = LogFactoryUtil.getLog(
1517        JournalUtil.class.getName() + ".ScriptBeforeListener");
1518
1519    private static Log _logTokens = LogFactoryUtil.getLog(
1520        JournalUtil.class.getName() + ".Tokens");
1521
1522    private static Log _logTransformBefore = LogFactoryUtil.getLog(
1523        JournalUtil.class.getName() + ".BeforeTransform");
1524
1525    private static Log _logTransfromAfter = LogFactoryUtil.getLog(
1526        JournalUtil.class.getName() + ".TransformAfter");
1527
1528    private static Log _logXmlAfterListener = LogFactoryUtil.getLog(
1529        JournalUtil.class.getName() + ".XmlAfterListener");
1530
1531    private static Log _logXmlBeforeListener = LogFactoryUtil.getLog(
1532        JournalUtil.class.getName() + ".XmlBeforeListener");
1533
1534}