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