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