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.LocalizationUtil;
28  import com.liferay.portal.kernel.util.OrderByComparator;
29  import com.liferay.portal.kernel.util.PropertiesUtil;
30  import com.liferay.portal.kernel.util.PropsKeys;
31  import com.liferay.portal.kernel.util.StringBundler;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.StringUtil;
34  import com.liferay.portal.kernel.util.Time;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.kernel.xml.Document;
37  import com.liferay.portal.kernel.xml.Element;
38  import com.liferay.portal.kernel.xml.Node;
39  import com.liferay.portal.kernel.xml.SAXReaderUtil;
40  import com.liferay.portal.kernel.xml.XPath;
41  import com.liferay.portal.model.Group;
42  import com.liferay.portal.model.Layout;
43  import com.liferay.portal.model.LayoutSet;
44  import com.liferay.portal.model.User;
45  import com.liferay.portal.service.ImageLocalServiceUtil;
46  import com.liferay.portal.service.LayoutLocalServiceUtil;
47  import com.liferay.portal.service.UserLocalServiceUtil;
48  import com.liferay.portal.theme.ThemeDisplay;
49  import com.liferay.portal.util.ContentUtil;
50  import com.liferay.portal.util.FriendlyURLNormalizer;
51  import com.liferay.portal.util.PropsUtil;
52  import com.liferay.portal.util.PropsValues;
53  import com.liferay.portal.util.WebKeys;
54  import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
55  import com.liferay.portlet.journal.TransformException;
56  import com.liferay.portlet.journal.model.JournalArticle;
57  import com.liferay.portlet.journal.model.JournalStructure;
58  import com.liferay.portlet.journal.model.JournalStructureConstants;
59  import com.liferay.portlet.journal.model.JournalTemplate;
60  import com.liferay.portlet.journal.service.JournalArticleImageLocalServiceUtil;
61  import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
62  import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
63  import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
64  import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
65  import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
66  import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
67  import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
68  import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
69  import com.liferay.util.FiniteUniqueStack;
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         throws PortalException, SystemException {
764 
765         return getTokens(groupId, themeDisplay, null);
766     }
767 
768     public static Map<String, String> getTokens(
769             long groupId, ThemeDisplay themeDisplay, String xmlRequest)
770         throws PortalException, SystemException {
771 
772         Map<String, String> tokens = new HashMap<String, String>();
773 
774         if (themeDisplay != null) {
775             _populateTokens(tokens, groupId, themeDisplay);
776         }
777         else if (Validator.isNotNull(xmlRequest)) {
778             try {
779                 _populateTokens(tokens, groupId, xmlRequest);
780             }
781             catch (Exception e) {
782                 if (_log.isWarnEnabled()) {
783                     _log.warn(e, e);
784                 }
785             }
786         }
787 
788         return tokens;
789     }
790 
791     public static String getUrlTitle(long id, String title) {
792         title = title.trim().toLowerCase();
793 
794         if (Validator.isNull(title) || Validator.isNumber(title) ||
795             title.equals("rss")) {
796 
797             return String.valueOf(id);
798         }
799         else {
800             return FriendlyURLNormalizer.normalize(
801                 title, _URL_TITLE_REPLACE_CHARS);
802         }
803     }
804 
805     public static String mergeArticleContent(
806         String curContent, String newContent) {
807 
808         try {
809             Document curDocument = SAXReaderUtil.read(curContent);
810             Document newDocument = SAXReaderUtil.read(newContent);
811 
812             Element curRoot = curDocument.getRootElement();
813             Element newRoot = newDocument.getRootElement();
814 
815             curRoot.addAttribute(
816                 "default-locale",
817                 newRoot.attributeValue("default-locale"));
818             curRoot.addAttribute(
819                 "available-locales",
820                 newRoot.attributeValue("available-locales"));
821 
822             _mergeArticleContentUpdate(
823                 curDocument, newRoot,
824                 LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
825             _mergeArticleContentDelete(curRoot, newDocument);
826 
827             curContent = JournalUtil.formatXML(curDocument);
828         }
829         catch (Exception e) {
830             _log.error(e, e);
831         }
832 
833         return curContent;
834     }
835 
836     public static void removeArticleLocale(Element el, String languageId)
837         throws PortalException, SystemException {
838 
839         for (Element dynamicEl : el.elements("dynamic-element")) {
840             for (Element dynamicContentEl :
841                     dynamicEl.elements("dynamic-content")) {
842 
843                 String curLanguageId = GetterUtil.getString(
844                     dynamicContentEl.attributeValue("language-id"));
845 
846                 if (curLanguageId.equals(languageId)) {
847                     long id = GetterUtil.getLong(
848                         dynamicContentEl.attributeValue("id"));
849 
850                     if (id > 0) {
851                         ImageLocalServiceUtil.deleteImage(id);
852                     }
853 
854                     dynamicContentEl.detach();
855                 }
856             }
857 
858             removeArticleLocale(dynamicEl, languageId);
859         }
860     }
861 
862     public static String removeArticleLocale(
863         String content, String languageId) {
864 
865         try {
866             Document doc = SAXReaderUtil.read(content);
867 
868             Element root = doc.getRootElement();
869 
870             String availableLocales = root.attributeValue("available-locales");
871 
872             if (availableLocales == null) {
873                 return content;
874             }
875 
876             availableLocales = StringUtil.remove(availableLocales, languageId);
877 
878             if (availableLocales.endsWith(",")) {
879                 availableLocales = availableLocales.substring(
880                     0, availableLocales.length() - 1);
881             }
882 
883             root.addAttribute("available-locales", availableLocales);
884 
885             removeArticleLocale(root, languageId);
886 
887             content = formatXML(doc);
888         }
889         catch (Exception e) {
890             _log.error(e, e);
891         }
892 
893         return content;
894     }
895 
896     public static String removeOldContent(String content, String xsd) {
897         try {
898             Document contentDoc = SAXReaderUtil.read(content);
899             Document xsdDoc = SAXReaderUtil.read(xsd);
900 
901             Element contentRoot = contentDoc.getRootElement();
902 
903             Stack<String> path = new Stack<String>();
904 
905             path.push(contentRoot.getName());
906 
907             _removeOldContent(path, contentRoot, xsdDoc);
908 
909             content = formatXML(contentDoc);
910         }
911         catch (Exception e) {
912             _log.error(e, e);
913         }
914 
915         return content;
916     }
917 
918     public static void removeRecentArticle(
919         PortletRequest portletRequest, String articleId) {
920 
921         Stack<JournalArticle> stack = getRecentArticles(portletRequest);
922 
923         Iterator<JournalArticle> itr = stack.iterator();
924 
925         while (itr.hasNext()) {
926             JournalArticle journalArticle = itr.next();
927 
928             if (journalArticle.getArticleId().equals(articleId)) {
929                 itr.remove();
930 
931                 break;
932             }
933         }
934     }
935 
936     public static void removeRecentStructure(
937         PortletRequest portletRequest, String structureId) {
938 
939         Stack<JournalStructure> stack = getRecentStructures(portletRequest);
940 
941         Iterator<JournalStructure> itr = stack.iterator();
942 
943         while (itr.hasNext()) {
944             JournalStructure journalStructure = itr.next();
945 
946             if (journalStructure.getStructureId().equals(structureId)) {
947                 itr.remove();
948 
949                 break;
950             }
951         }
952     }
953 
954     public static void removeRecentTemplate(
955         PortletRequest portletRequest, String templateId) {
956 
957         Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
958 
959         Iterator<JournalTemplate> itr = stack.iterator();
960 
961         while (itr.hasNext()) {
962             JournalTemplate journalTemplate = itr.next();
963 
964             if (journalTemplate.getTemplateId().equals(templateId)) {
965                 itr.remove();
966 
967                 break;
968             }
969         }
970     }
971 
972     public static String transform(
973             ThemeDisplay themeDisplay, Map<String, String> tokens,
974             String viewMode, String languageId, String xml, String script,
975             String langType)
976         throws Exception {
977 
978         // Setup Listeners
979 
980         if (_log.isDebugEnabled()) {
981             _log.debug("Language " + languageId);
982         }
983 
984         if (Validator.isNull(viewMode)) {
985             viewMode = Constants.VIEW;
986         }
987 
988         if (_logTokens.isDebugEnabled()) {
989             String tokensString = PropertiesUtil.list(tokens);
990 
991             _logTokens.debug(tokensString);
992         }
993 
994         if (_logTransformBefore.isDebugEnabled()) {
995             _logTransformBefore.debug(xml);
996         }
997 
998         List<TransformerListener> listenersList =
999             new ArrayList<TransformerListener>();
1000
1001        String[] listeners = PropsUtil.getArray(
1002            PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
1003
1004        for (int i = 0; i < listeners.length; i++) {
1005            TransformerListener listener = null;
1006
1007            try {
1008                if (_log.isDebugEnabled()) {
1009                    _log.debug("Instantiate listener " + listeners[i]);
1010                }
1011
1012                boolean templateDriven = Validator.isNotNull(langType);
1013
1014                listener = (TransformerListener)Class.forName(
1015                    listeners[i]).newInstance();
1016
1017                listener.setTemplateDriven(templateDriven);
1018                listener.setLanguageId(languageId);
1019                listener.setTokens(tokens);
1020
1021                listenersList.add(listener);
1022            }
1023            catch (Exception e) {
1024                _log.error(e, e);
1025            }
1026
1027            // Modify XML
1028
1029            if (_logXmlBeforeListener.isDebugEnabled()) {
1030                _logXmlBeforeListener.debug(xml);
1031            }
1032
1033            if (listener != null) {
1034                xml = listener.onXml(xml);
1035
1036                if (_logXmlAfterListener.isDebugEnabled()) {
1037                    _logXmlAfterListener.debug(xml);
1038                }
1039            }
1040
1041            // Modify script
1042
1043            if (_logScriptBeforeListener.isDebugEnabled()) {
1044                _logScriptBeforeListener.debug(script);
1045            }
1046
1047            if (listener != null) {
1048                script = listener.onScript(script);
1049
1050                if (_logScriptAfterListener.isDebugEnabled()) {
1051                    _logScriptAfterListener.debug(script);
1052                }
1053            }
1054        }
1055
1056        // Transform
1057
1058        String output = null;
1059
1060        if (Validator.isNull(langType)) {
1061            output = LocalizationUtil.getLocalization(xml, languageId);
1062        }
1063        else {
1064            String templateParserClassName = PropsUtil.get(
1065                PropsKeys.JOURNAL_TEMPLATE_LANGUAGE_PARSER,
1066                new Filter(langType));
1067
1068            if (_log.isDebugEnabled()) {
1069                _log.debug(
1070                    "Template parser class name " + templateParserClassName);
1071            }
1072
1073            if (Validator.isNotNull(templateParserClassName)) {
1074                TemplateParser templateParser =
1075                    (TemplateParser)InstancePool.get(templateParserClassName);
1076
1077                if (templateParser == null) {
1078                    throw new TransformException(
1079                        "No template parser found for " +
1080                            templateParserClassName);
1081                }
1082
1083                output = templateParser.transform(
1084                    themeDisplay, tokens, viewMode, languageId, xml, script);
1085            }
1086        }
1087
1088        // Postprocess output
1089
1090        for (int i = 0; i < listenersList.size(); i++) {
1091            TransformerListener listener = listenersList.get(i);
1092
1093            // Modify output
1094
1095            if (_logOutputBeforeListener.isDebugEnabled()) {
1096                _logOutputBeforeListener.debug(output);
1097            }
1098
1099            output = listener.onOutput(output);
1100
1101            if (_logOutputAfterListener.isDebugEnabled()) {
1102                _logOutputAfterListener.debug(output);
1103            }
1104        }
1105
1106        if (_logTransfromAfter.isDebugEnabled()) {
1107            _logTransfromAfter.debug(output);
1108        }
1109
1110        return output;
1111    }
1112
1113    private static void _addElementOptions (
1114        Element curContentElement, Element newContentElement) {
1115
1116        List<Element> newElementOptions = newContentElement.elements("option");
1117
1118        for (Element newElementOption : newElementOptions) {
1119            Element curElementOption = SAXReaderUtil.createElement("option");
1120
1121            curElementOption.addCDATA(newElementOption.getText());
1122
1123            curContentElement.add(curElementOption);
1124        }
1125    }
1126
1127    private static Element _getElementByInstanceId(
1128        Document document, String instanceId) {
1129
1130        XPath xPathSelector = SAXReaderUtil.createXPath(
1131            "//dynamic-element[@instance-id='" + instanceId + "']");
1132
1133        List<Node> nodes = xPathSelector.selectNodes(document);
1134
1135        if (nodes.size() == 1) {
1136            return (Element)nodes.get(0);
1137        }
1138        else {
1139            return null;
1140        }
1141    }
1142
1143    private static void _mergeArticleContentDelete(
1144            Element curParentElement, Document newDocument)
1145        throws Exception {
1146
1147        List<Element> curElements = curParentElement.elements(
1148            "dynamic-element");
1149
1150        for (int i = 0; i < curElements.size(); i++) {
1151            Element curElement = curElements.get(i);
1152
1153            _mergeArticleContentDelete(curElement, newDocument);
1154
1155            String instanceId = curElement.attributeValue("instance-id");
1156
1157            Element newElement = _getElementByInstanceId(
1158                newDocument, instanceId);
1159
1160            if (newElement == null) {
1161                curElement.detach();
1162
1163                String type = curElement.attributeValue("type");
1164
1165                if (type.equals("image")) {
1166                    _mergeArticleContentDeleteImages(
1167                        curElement.elements("dynamic-content"));
1168                }
1169            }
1170        }
1171    }
1172
1173    private static void _mergeArticleContentDeleteImages(List<Element> elements)
1174        throws Exception {
1175
1176        for (Element element : elements) {
1177            long articleImageId = GetterUtil.getLong(
1178                element.attributeValue("id"));
1179
1180            JournalArticleImageLocalServiceUtil.deleteArticleImage(
1181                articleImageId);
1182        }
1183    }
1184
1185    private static void _mergeArticleContentUpdate(
1186            Document curDocument, Element newParentElement, Element newElement,
1187            int pos, String defaultLocale)
1188        throws Exception {
1189
1190        _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1191
1192        String instanceId = newElement.attributeValue("instance-id");
1193
1194        Element curElement = _getElementByInstanceId(curDocument, instanceId);
1195
1196        if (curElement != null) {
1197            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1198        }
1199        else {
1200            String parentInstanceId = newParentElement.attributeValue(
1201                "instance-id");
1202
1203            if (Validator.isNull(parentInstanceId)) {
1204                Element curRoot = curDocument.getRootElement();
1205
1206                List<Element> curRootElements = curRoot.elements();
1207
1208                curRootElements.add(pos, newElement.createCopy());
1209            }
1210            else {
1211                Element curParentElement = _getElementByInstanceId(
1212                    curDocument, parentInstanceId);
1213
1214                if (curParentElement != null) {
1215                    List<Element> curParentElements =
1216                        curParentElement.elements();
1217
1218                    curParentElements.add(pos, newElement.createCopy());
1219                }
1220            }
1221        }
1222    }
1223
1224    private static void _mergeArticleContentUpdate(
1225            Document curDocument, Element newParentElement,
1226            String defaultLocale)
1227        throws Exception {
1228
1229        List<Element> newElements = newParentElement.elements(
1230            "dynamic-element");
1231
1232        for (int i = 0; i < newElements.size(); i++) {
1233            Element newElement = newElements.get(i);
1234
1235            _mergeArticleContentUpdate(
1236                curDocument, newParentElement, newElement, i, defaultLocale);
1237        }
1238    }
1239
1240    private static void _mergeArticleContentUpdate(
1241        Element curElement, Element newElement, String defaultLocale) {
1242
1243        Element newContentElement = newElement.elements(
1244            "dynamic-content").get(0);
1245
1246        String newLanguageId = newContentElement.attributeValue("language-id");
1247        String newValue = newContentElement.getText();
1248
1249        String indexType = newElement.attributeValue("index-type");
1250
1251        if (Validator.isNotNull(indexType)) {
1252            curElement.addAttribute("index-type", indexType);
1253        }
1254
1255        List<Element> curContentElements = curElement.elements(
1256            "dynamic-content");
1257
1258        if (Validator.isNull(newLanguageId)) {
1259            for (Element curContentElement : curContentElements) {
1260                curContentElement.detach();
1261            }
1262
1263            Element curContentElement = SAXReaderUtil.createElement(
1264                "dynamic-content");
1265
1266            if (newContentElement.element("option") != null) {
1267                _addElementOptions(curContentElement, newContentElement);
1268            }
1269            else {
1270                curContentElement.addCDATA(newValue);
1271            }
1272
1273            curElement.add(curContentElement);
1274        }
1275        else {
1276            boolean alreadyExists = false;
1277
1278            for (Element curContentElement : curContentElements) {
1279                String curLanguageId = curContentElement.attributeValue(
1280                    "language-id");
1281
1282                if (newLanguageId.equals(curLanguageId)) {
1283                    alreadyExists = true;
1284
1285                    curContentElement.clearContent();
1286
1287                    if (newContentElement.element("option") != null) {
1288                        _addElementOptions(
1289                            curContentElement, newContentElement);
1290                    }
1291                    else {
1292                        curContentElement.addCDATA(newValue);
1293                    }
1294
1295                    break;
1296                }
1297            }
1298
1299            if (!alreadyExists) {
1300                Element curContentElement = curContentElements.get(0);
1301
1302                String curLanguageId = curContentElement.attributeValue(
1303                    "language-id");
1304
1305                if (Validator.isNull(curLanguageId)) {
1306                    curContentElement.detach();
1307                }
1308
1309                curElement.add(newContentElement.createCopy());
1310            }
1311        }
1312    }
1313
1314    private static void _populateCustomTokens(Map<String, String> tokens) {
1315        if (_customTokens == null) {
1316            synchronized (JournalUtil.class) {
1317                _customTokens = new HashMap<String, String>();
1318
1319                for (String customToken :
1320                        PropsValues.JOURNAL_ARTICLE_CUSTOM_TOKENS) {
1321
1322                    String value = PropsUtil.get(
1323                        PropsKeys.JOURNAL_ARTICLE_CUSTOM_TOKEN_VALUE,
1324                        new Filter(customToken));
1325
1326                    _customTokens.put(customToken, value);
1327                }
1328            }
1329        }
1330
1331        if (!_customTokens.isEmpty()) {
1332            tokens.putAll(_customTokens);
1333        }
1334    }
1335
1336    private static void _populateTokens(
1337            Map<String, String> tokens, long groupId, String xmlRequest)
1338        throws Exception {
1339
1340        Document request = SAXReaderUtil.read(xmlRequest);
1341
1342        Element root = request.getRootElement();
1343
1344        Element themeDisplayEl = root.element("theme-display");
1345
1346        Layout layout = LayoutLocalServiceUtil.getLayout(
1347            GetterUtil.getLong(themeDisplayEl.elementText("plid")));
1348
1349        Group group = layout.getGroup();
1350
1351        LayoutSet layoutSet = layout.getLayoutSet();
1352
1353        String friendlyUrlCurrent = null;
1354
1355        if (layout.isPublicLayout()) {
1356            friendlyUrlCurrent = themeDisplayEl.elementText(
1357                "path-friendly-url-public");
1358        }
1359        else if (group.isUserGroup()) {
1360            friendlyUrlCurrent = themeDisplayEl.elementText(
1361                "path-friendly-url-private-user");
1362        }
1363        else {
1364            friendlyUrlCurrent = themeDisplayEl.elementText(
1365                "path-friendly-url-private-group");
1366        }
1367
1368        String layoutSetFriendlyUrl = StringPool.BLANK;
1369
1370        String virtualHost = layoutSet.getVirtualHost();
1371
1372        if (Validator.isNull(virtualHost) ||
1373            !virtualHost.equals(themeDisplayEl.elementText("server-name"))) {
1374
1375            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1376        }
1377
1378        tokens.put("cdn_host", themeDisplayEl.elementText("cdn-host"));
1379        tokens.put("company_id", themeDisplayEl.elementText("company-id"));
1380        tokens.put("friendly_url_current", friendlyUrlCurrent);
1381        tokens.put(
1382            "friendly_url_private_group",
1383            themeDisplayEl.elementText("path-friendly-url-private-group"));
1384        tokens.put(
1385            "friendly_url_private_user",
1386            themeDisplayEl.elementText("path-friendly-url-private-user"));
1387        tokens.put(
1388            "friendly_url_public",
1389            themeDisplayEl.elementText("path-friendly-url-public"));
1390        tokens.put("group_friendly_url", group.getFriendlyURL());
1391        tokens.put("group_id", String.valueOf(groupId));
1392        tokens.put("image_path", themeDisplayEl.elementText("path-image"));
1393        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1394        tokens.put("main_path", themeDisplayEl.elementText("path-main"));
1395        tokens.put("portal_ctx", themeDisplayEl.elementText("path-context"));
1396        tokens.put(
1397            "portal_url",
1398            HttpUtil.removeProtocol(themeDisplayEl.elementText("url-portal")));
1399        tokens.put(
1400            "protocol",
1401            HttpUtil.getProtocol(themeDisplayEl.elementText("url-portal")));
1402        tokens.put("root_path", themeDisplayEl.elementText("path-context"));
1403        tokens.put(
1404            "theme_image_path",
1405            themeDisplayEl.elementText("path-theme-images"));
1406
1407        _populateCustomTokens(tokens);
1408
1409        // Deprecated tokens
1410
1411        tokens.put(
1412            "friendly_url",
1413            themeDisplayEl.elementText("path-friendly-url-public"));
1414        tokens.put(
1415            "friendly_url_private",
1416            themeDisplayEl.elementText("path-friendly-url-private-group"));
1417        tokens.put(
1418            "page_url", themeDisplayEl.elementText("path-friendly-url-public"));
1419    }
1420
1421    private static void _populateTokens(
1422            Map<String, String> tokens, long groupId, ThemeDisplay themeDisplay)
1423        throws PortalException, SystemException {
1424
1425        Layout layout = themeDisplay.getLayout();
1426
1427        Group group = layout.getGroup();
1428
1429        LayoutSet layoutSet = layout.getLayoutSet();
1430
1431        String friendlyUrlCurrent = null;
1432
1433        if (layout.isPublicLayout()) {
1434            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1435        }
1436        else if (group.isUserGroup()) {
1437            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1438        }
1439        else {
1440            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1441        }
1442
1443        String layoutSetFriendlyUrl = StringPool.BLANK;
1444
1445        String virtualHost = layoutSet.getVirtualHost();
1446
1447        if (Validator.isNull(virtualHost) ||
1448            !virtualHost.equals(themeDisplay.getServerName())) {
1449
1450            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1451        }
1452
1453        tokens.put("cdn_host", themeDisplay.getCDNHost());
1454        tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1455        tokens.put("friendly_url_current", friendlyUrlCurrent);
1456        tokens.put(
1457            "friendly_url_private_group",
1458            themeDisplay.getPathFriendlyURLPrivateGroup());
1459        tokens.put(
1460            "friendly_url_private_user",
1461            themeDisplay.getPathFriendlyURLPrivateUser());
1462        tokens.put(
1463            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1464        tokens.put("group_friendly_url", group.getFriendlyURL());
1465        tokens.put("group_id", String.valueOf(groupId));
1466        tokens.put("image_path", themeDisplay.getPathImage());
1467        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1468        tokens.put("main_path", themeDisplay.getPathMain());
1469        tokens.put("portal_ctx", themeDisplay.getPathContext());
1470        tokens.put(
1471            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1472        tokens.put(
1473            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1474        tokens.put("root_path", themeDisplay.getPathContext());
1475        tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1476
1477        _populateCustomTokens(tokens);
1478
1479        // Deprecated tokens
1480
1481        tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1482        tokens.put(
1483            "friendly_url_private",
1484            themeDisplay.getPathFriendlyURLPrivateGroup());
1485        tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1486    }
1487
1488    private static void _removeOldContent(
1489            Stack<String> path, Element contentEl, Document xsdDoc)
1490        throws SystemException {
1491
1492        String elPath = "";
1493
1494        for (int i = 0; i < path.size(); i++) {
1495            elPath += "/" + path.elementAt(i);
1496        }
1497
1498        for (int i = 0; i < contentEl.nodeCount(); i++) {
1499            Node contentNode = contentEl.node(i);
1500
1501            if (contentNode instanceof Element) {
1502                _removeOldContent(path, (Element)contentNode, xsdDoc, elPath);
1503            }
1504        }
1505    }
1506
1507    private static void _removeOldContent(
1508            Stack<String> path, Element contentEl, Document xsdDoc,
1509            String elPath)
1510        throws SystemException {
1511
1512        String name = contentEl.attributeValue("name");
1513
1514        if (Validator.isNull(name)) {
1515            return;
1516        }
1517
1518        String localPath = "dynamic-element[@name='" + name + "']";
1519
1520        String fullPath = elPath + "/" + localPath;
1521
1522        XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1523
1524        List<Node> curNodes = xPathSelector.selectNodes(xsdDoc);
1525
1526        if (curNodes.size() == 0) {
1527            contentEl.detach();
1528        }
1529
1530        path.push(localPath);
1531
1532        _removeOldContent(path, contentEl, xsdDoc);
1533
1534        path.pop();
1535    }
1536
1537    private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
1538        '.', '/'
1539    };
1540
1541    private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1542
1543    private static Log _logOutputAfterListener = LogFactoryUtil.getLog(
1544        JournalUtil.class.getName() + ".OutputAfterListener");
1545
1546    private static Log _logOutputBeforeListener = LogFactoryUtil.getLog(
1547        JournalUtil.class.getName() + ".OutputBeforeListener");
1548
1549    private static Log _logScriptAfterListener = LogFactoryUtil.getLog(
1550        JournalUtil.class.getName() + ".ScriptAfterListener");
1551
1552    private static Log _logScriptBeforeListener = LogFactoryUtil.getLog(
1553        JournalUtil.class.getName() + ".ScriptBeforeListener");
1554
1555    private static Log _logTokens = LogFactoryUtil.getLog(
1556        JournalUtil.class.getName() + ".Tokens");
1557
1558    private static Log _logTransformBefore = LogFactoryUtil.getLog(
1559        JournalUtil.class.getName() + ".BeforeTransform");
1560
1561    private static Log _logTransfromAfter = LogFactoryUtil.getLog(
1562        JournalUtil.class.getName() + ".TransformAfter");
1563
1564    private static Log _logXmlAfterListener = LogFactoryUtil.getLog(
1565        JournalUtil.class.getName() + ".XmlAfterListener");
1566
1567    private static Log _logXmlBeforeListener = LogFactoryUtil.getLog(
1568        JournalUtil.class.getName() + ".XmlBeforeListener");
1569
1570    private static Map<String, String> _customTokens;
1571
1572}