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