1   /**
2    * Copyright (c) 2000-2008 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.util.GetterUtil;
28  import com.liferay.portal.kernel.util.HttpUtil;
29  import com.liferay.portal.kernel.util.LocaleUtil;
30  import com.liferay.portal.kernel.util.OrderByComparator;
31  import com.liferay.portal.kernel.util.PropertiesUtil;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.StringUtil;
34  import com.liferay.portal.kernel.util.Time;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.model.Contact;
37  import com.liferay.portal.model.User;
38  import com.liferay.portal.service.ImageLocalServiceUtil;
39  import com.liferay.portal.service.UserLocalServiceUtil;
40  import com.liferay.portal.theme.ThemeDisplay;
41  import com.liferay.portal.util.ContentUtil;
42  import com.liferay.portal.util.PropsKeys;
43  import com.liferay.portal.util.PropsUtil;
44  import com.liferay.portal.util.WebKeys;
45  import com.liferay.portlet.journal.model.JournalArticle;
46  import com.liferay.portlet.journal.model.JournalStructure;
47  import com.liferay.portlet.journal.model.JournalTemplate;
48  import com.liferay.portlet.journal.model.impl.JournalStructureImpl;
49  import com.liferay.portlet.journal.model.impl.JournalTemplateImpl;
50  import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
51  import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
52  import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
53  import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
54  import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
55  import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
56  import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
57  import com.liferay.util.FiniteUniqueStack;
58  import com.liferay.util.LocalizationUtil;
59  import com.liferay.util.xml.XMLFormatter;
60  
61  import java.io.IOException;
62  import java.io.StringReader;
63  
64  import java.util.ArrayList;
65  import java.util.Date;
66  import java.util.HashMap;
67  import java.util.Iterator;
68  import java.util.List;
69  import java.util.Map;
70  import java.util.Stack;
71  
72  import javax.portlet.PortletPreferences;
73  import javax.portlet.PortletRequest;
74  import javax.portlet.PortletSession;
75  
76  import org.apache.commons.logging.Log;
77  import org.apache.commons.logging.LogFactory;
78  
79  import org.dom4j.Document;
80  import org.dom4j.DocumentException;
81  import org.dom4j.DocumentFactory;
82  import org.dom4j.DocumentHelper;
83  import org.dom4j.Element;
84  import org.dom4j.Node;
85  import org.dom4j.XPath;
86  import org.dom4j.io.SAXReader;
87  
88  /**
89   * <a href="JournalUtil.java.html"><b><i>View Source</i></b></a>
90   *
91   * @author Brian Wing Shun Chan
92   * @author Raymond Augé
93   *
94   */
95  public class JournalUtil {
96  
97      public static final int MAX_STACK_SIZE = 20;
98  
99      public static final String XML_INDENT = "  ";
100 
101     public static void addRecentArticle(
102         PortletRequest portletRequest, JournalArticle article) {
103 
104         if (article != null) {
105             Stack<JournalArticle> stack = getRecentArticles(portletRequest);
106 
107             stack.push(article);
108         }
109     }
110 
111     public static void addRecentStructure(
112         PortletRequest portletRequest, JournalStructure structure) {
113 
114         if (structure != null) {
115             Stack<JournalStructure> stack = getRecentStructures(portletRequest);
116 
117             stack.push(structure);
118         }
119     }
120 
121     public static void addRecentTemplate(
122         PortletRequest portletRequest, JournalTemplate template) {
123 
124         if (template != null) {
125             Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
126 
127             stack.push(template);
128         }
129     }
130 
131     public static void addReservedEl(
132         Element root, Map<String, String> tokens, String name, double value) {
133 
134         addReservedEl(root, tokens, name, String.valueOf(value));
135     }
136 
137     public static void addReservedEl(
138         Element root, Map<String, String> tokens, String name, Date value) {
139 
140         addReservedEl(root, tokens, name, Time.getRFC822(value));
141     }
142 
143     public static void addReservedEl(
144         Element root, Map<String, String> tokens, String name, String value) {
145 
146         // XML
147 
148         if (root != null) {
149             DocumentFactory docFactory = DocumentFactory.getInstance();
150 
151             Element dynamicEl = docFactory.createElement("dynamic-element");
152 
153             dynamicEl.add(docFactory.createAttribute(dynamicEl, "name", name));
154             dynamicEl.add(
155                 docFactory.createAttribute(dynamicEl, "type", "text"));
156 
157             Element dynamicContent =
158                 docFactory.createElement("dynamic-content");
159 
160             //dynamicContent.setText("<![CDATA[" + value + "]]>");
161             dynamicContent.setText(value);
162 
163             dynamicEl.add(dynamicContent);
164 
165             root.add(dynamicEl);
166         }
167 
168         // Tokens
169 
170         tokens.put(
171             StringUtil.replace(name, StringPool.DASH, StringPool.UNDERLINE),
172             value);
173     }
174 
175     public static void addAllReservedEls(
176         Element root, Map<String, String> tokens, JournalArticle article) {
177 
178         JournalUtil.addReservedEl(
179             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_ID,
180             article.getArticleId());
181 
182         JournalUtil.addReservedEl(
183             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_VERSION,
184             article.getVersion());
185 
186         JournalUtil.addReservedEl(
187             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_TITLE,
188             article.getTitle());
189 
190         JournalUtil.addReservedEl(
191             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_DESCRIPTION,
192             article.getDescription());
193 
194         JournalUtil.addReservedEl(
195             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_TYPE,
196             article.getType());
197 
198         JournalUtil.addReservedEl(
199             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_CREATE_DATE,
200             article.getCreateDate());
201 
202         JournalUtil.addReservedEl(
203             root, tokens,
204             JournalStructureImpl.RESERVED_ARTICLE_MODIFIED_DATE,
205             article.getModifiedDate());
206 
207         if (article.getDisplayDate() != null) {
208             JournalUtil.addReservedEl(
209                 root, tokens,
210                 JournalStructureImpl.RESERVED_ARTICLE_DISPLAY_DATE,
211                 article.getDisplayDate());
212         }
213 
214         JournalUtil.addReservedEl(
215             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_SMALL_IMAGE_URL,
216             article.getSmallImageURL());
217 
218         JournalUtil.addReservedEl(
219             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_AUTHOR_ID,
220             String.valueOf(article.getUserId()));
221 
222         String userName = StringPool.BLANK;
223         String userEmailAddress = StringPool.BLANK;
224         String userComments = StringPool.BLANK;
225         String userJobTitle = StringPool.BLANK;
226 
227         User user = null;
228 
229         try {
230             user = UserLocalServiceUtil.getUserById(article.getUserId());
231 
232             userName = user.getFullName();
233             userEmailAddress = user.getEmailAddress();
234             userComments = user.getComments();
235 
236             Contact contact = user.getContact();
237 
238             if (contact != null) {
239                 userJobTitle = contact.getJobTitle();
240             }
241         }
242         catch (PortalException pe) {
243         }
244         catch (SystemException se) {
245         }
246 
247         JournalUtil.addReservedEl(
248             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_AUTHOR_NAME,
249             userName);
250 
251         JournalUtil.addReservedEl(
252             root, tokens,
253             JournalStructureImpl.RESERVED_ARTICLE_AUTHOR_EMAIL_ADDRESS,
254             userEmailAddress);
255 
256         JournalUtil.addReservedEl(
257             root, tokens,
258             JournalStructureImpl.RESERVED_ARTICLE_AUTHOR_COMMENTS,
259             userComments);
260 
261         JournalUtil.addReservedEl(
262             root, tokens,
263             JournalStructureImpl.RESERVED_ARTICLE_AUTHOR_JOB_TITLE,
264             userJobTitle);
265     }
266 
267     public static String formatVM(String vm) {
268         return vm;
269     }
270 
271     public static String formatXML(String xml)
272         throws DocumentException, IOException {
273 
274         // This is only supposed to format your xml, however, it will also
275         // unwantingly change &#169; and other characters like it into their
276         // respective readable versions
277 
278         xml = StringUtil.replace(xml, "&#", "[$SPECIAL_CHARACTER$]");
279 
280         xml = XMLFormatter.toString(xml, XML_INDENT);
281 
282         xml = StringUtil.replace(xml, "[$SPECIAL_CHARACTER$]", "&#");
283 
284         return xml;
285     }
286 
287     public static String formatXML(Document doc) throws IOException {
288         return XMLFormatter.toString(doc, XML_INDENT);
289     }
290 
291     public static OrderByComparator getArticleOrderByComparator(
292         String orderByCol, String orderByType) {
293 
294         boolean orderByAsc = false;
295 
296         if (orderByType.equals("asc")) {
297             orderByAsc = true;
298         }
299 
300         OrderByComparator orderByComparator = null;
301 
302         if (orderByCol.equals("create-date")) {
303             orderByComparator = new ArticleCreateDateComparator(orderByAsc);
304         }
305         else if (orderByCol.equals("display-date")) {
306             orderByComparator = new ArticleDisplayDateComparator(orderByAsc);
307         }
308         else if (orderByCol.equals("id")) {
309             orderByComparator = new ArticleIDComparator(orderByAsc);
310         }
311         else if (orderByCol.equals("modified-date")) {
312             orderByComparator = new ArticleModifiedDateComparator(orderByAsc);
313         }
314         else if (orderByCol.equals("review-date")) {
315             orderByComparator = new ArticleReviewDateComparator(orderByAsc);
316         }
317         else if (orderByCol.equals("title")) {
318             orderByComparator = new ArticleTitleComparator(orderByAsc);
319         }
320         else if (orderByCol.equals("version")) {
321             orderByComparator = new ArticleModifiedDateComparator(orderByAsc);
322         }
323 
324         return orderByComparator;
325     }
326 
327     public static String getEmailFromAddress(PortletPreferences prefs) {
328         String emailFromAddress = PropsUtil.get(
329             PropsKeys.JOURNAL_EMAIL_FROM_ADDRESS);
330 
331         return prefs.getValue("email-from-address", emailFromAddress);
332     }
333 
334     public static String getEmailFromName(PortletPreferences prefs) {
335         String emailFromName = PropsUtil.get(
336             PropsKeys.JOURNAL_EMAIL_FROM_NAME);
337 
338         return prefs.getValue("email-from-name", emailFromName);
339     }
340 
341     public static boolean getEmailArticleApprovalDeniedEnabled(
342         PortletPreferences prefs) {
343 
344         String emailArticleApprovalDeniedEnabled = prefs.getValue(
345             "email-article-approval-denied-enabled", StringPool.BLANK);
346 
347         if (Validator.isNotNull(emailArticleApprovalDeniedEnabled)) {
348             return GetterUtil.getBoolean(emailArticleApprovalDeniedEnabled);
349         }
350         else {
351             return GetterUtil.getBoolean(PropsUtil.get(
352                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_ENABLED));
353         }
354     }
355 
356     public static String getEmailArticleApprovalDeniedBody(
357         PortletPreferences prefs) {
358 
359         String emailArticleApprovalDeniedBody = prefs.getValue(
360             "email-article-approval-denied-body", StringPool.BLANK);
361 
362         if (Validator.isNotNull(emailArticleApprovalDeniedBody)) {
363             return emailArticleApprovalDeniedBody;
364         }
365         else {
366             return ContentUtil.get(PropsUtil.get(
367                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_BODY));
368         }
369     }
370 
371     public static String getEmailArticleApprovalDeniedSubject(
372         PortletPreferences prefs) {
373 
374         String emailArticleApprovalDeniedSubject = prefs.getValue(
375             "email-article-approval-denied-subject", StringPool.BLANK);
376 
377         if (Validator.isNotNull(emailArticleApprovalDeniedSubject)) {
378             return emailArticleApprovalDeniedSubject;
379         }
380         else {
381             return ContentUtil.get(PropsUtil.get(
382                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_SUBJECT));
383         }
384     }
385 
386     public static boolean getEmailArticleApprovalGrantedEnabled(
387         PortletPreferences prefs) {
388 
389         String emailArticleApprovalGrantedEnabled = prefs.getValue(
390             "email-article-approval-granted-enabled", StringPool.BLANK);
391 
392         if (Validator.isNotNull(emailArticleApprovalGrantedEnabled)) {
393             return GetterUtil.getBoolean(emailArticleApprovalGrantedEnabled);
394         }
395         else {
396             return GetterUtil.getBoolean(PropsUtil.get(
397                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_ENABLED));
398         }
399     }
400 
401     public static String getEmailArticleApprovalGrantedBody(
402         PortletPreferences prefs) {
403 
404         String emailArticleApprovalGrantedBody = prefs.getValue(
405             "email-article-approval-granted-body", StringPool.BLANK);
406 
407         if (Validator.isNotNull(emailArticleApprovalGrantedBody)) {
408             return emailArticleApprovalGrantedBody;
409         }
410         else {
411             return ContentUtil.get(PropsUtil.get(
412                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_BODY));
413         }
414     }
415 
416     public static String getEmailArticleApprovalGrantedSubject(
417         PortletPreferences prefs) {
418 
419         String emailArticleApprovalGrantedSubject = prefs.getValue(
420             "email-article-approval-granted-subject", StringPool.BLANK);
421 
422         if (Validator.isNotNull(emailArticleApprovalGrantedSubject)) {
423             return emailArticleApprovalGrantedSubject;
424         }
425         else {
426             return ContentUtil.get(PropsUtil.get(
427                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_SUBJECT));
428         }
429     }
430 
431     public static boolean getEmailArticleApprovalRequestedEnabled(
432         PortletPreferences prefs) {
433 
434         String emailArticleApprovalRequestedEnabled = prefs.getValue(
435             "email-article-approval-requested-enabled", StringPool.BLANK);
436 
437         if (Validator.isNotNull(emailArticleApprovalRequestedEnabled)) {
438             return GetterUtil.getBoolean(emailArticleApprovalRequestedEnabled);
439         }
440         else {
441             return GetterUtil.getBoolean(PropsUtil.get(
442                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_ENABLED));
443         }
444     }
445 
446     public static String getEmailArticleApprovalRequestedBody(
447         PortletPreferences prefs) {
448 
449         String emailArticleApprovalRequestedBody = prefs.getValue(
450             "email-article-approval-requested-body", StringPool.BLANK);
451 
452         if (Validator.isNotNull(emailArticleApprovalRequestedBody)) {
453             return emailArticleApprovalRequestedBody;
454         }
455         else {
456             return ContentUtil.get(PropsUtil.get(
457                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_BODY));
458         }
459     }
460 
461     public static String getEmailArticleApprovalRequestedSubject(
462         PortletPreferences prefs) {
463 
464         String emailArticleApprovalRequestedSubject = prefs.getValue(
465             "email-article-approval-requested-subject", StringPool.BLANK);
466 
467         if (Validator.isNotNull(emailArticleApprovalRequestedSubject)) {
468             return emailArticleApprovalRequestedSubject;
469         }
470         else {
471             return ContentUtil.get(PropsUtil.get(
472                 PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_SUBJECT));
473         }
474     }
475 
476     public static boolean getEmailArticleReviewEnabled(
477         PortletPreferences prefs) {
478 
479         String emailArticleReviewEnabled = prefs.getValue(
480             "email-article-review-enabled", StringPool.BLANK);
481 
482         if (Validator.isNotNull(emailArticleReviewEnabled)) {
483             return GetterUtil.getBoolean(emailArticleReviewEnabled);
484         }
485         else {
486             return GetterUtil.getBoolean(PropsUtil.get(
487                 PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_ENABLED));
488         }
489     }
490 
491     public static String getEmailArticleReviewBody(PortletPreferences prefs) {
492         String emailArticleReviewBody = prefs.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 prefs) {
506 
507         String emailArticleReviewSubject = prefs.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         Map<String, String> tokens = new HashMap<String, String>();
642 
643         if (themeDisplay == null) {
644             return tokens;
645         }
646 
647         tokens.put("cdn_host", themeDisplay.getCDNHost());
648         tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
649         tokens.put("group_id", String.valueOf(groupId));
650         tokens.put("cms_url", themeDisplay.getPathContext() + "/cms/servlet");
651         tokens.put("image_path", themeDisplay.getPathImage());
652         tokens.put(
653             "friendly_url_private_group",
654             themeDisplay.getPathFriendlyURLPrivateGroup());
655         tokens.put(
656             "friendly_url_private_user",
657             themeDisplay.getPathFriendlyURLPrivateUser());
658         tokens.put(
659             "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
660         tokens.put("main_path", themeDisplay.getPathMain());
661         tokens.put("portal_ctx", themeDisplay.getPathContext());
662         tokens.put(
663             "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
664         tokens.put("root_path", themeDisplay.getPathContext());
665         tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
666 
667         // Deprecated tokens
668 
669         tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
670         tokens.put(
671             "friendly_url_private",
672             themeDisplay.getPathFriendlyURLPrivateGroup());
673         tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
674 
675         return tokens;
676     }
677 
678     public static String mergeLocaleContent(
679         String curContent, String newContent, String xsd) {
680 
681         try {
682             SAXReader reader = new SAXReader();
683 
684             Document curContentDoc = reader.read(new StringReader(curContent));
685             Document newContentDoc = reader.read(new StringReader(newContent));
686             Document xsdDoc = reader.read(new StringReader(xsd));
687 
688             Element curContentRoot = curContentDoc.getRootElement();
689             Element newContentRoot = newContentDoc.getRootElement();
690             Element xsdRoot = xsdDoc.getRootElement();
691 
692             curContentRoot.addAttribute(
693                 "default-locale",
694                 newContentRoot.attributeValue("default-locale"));
695             curContentRoot.addAttribute(
696                 "available-locales",
697                 newContentRoot.attributeValue("available-locales"));
698 
699             Stack<String> path = new Stack<String>();
700 
701             path.push(xsdRoot.getName());
702 
703             _mergeLocaleContent(
704                 path, curContentDoc, newContentDoc, xsdRoot,
705                 LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
706 
707             curContent = formatXML(curContentDoc);
708         }
709         catch (Exception e) {
710             _log.error(e);
711         }
712 
713         return curContent;
714     }
715 
716     public static String removeArticleLocale(
717         String content, String languageId) {
718 
719         try {
720             SAXReader reader = new SAXReader();
721 
722             Document doc = reader.read(new StringReader(content));
723 
724             Element root = doc.getRootElement();
725 
726             String availableLocales = root.attributeValue("available-locales");
727 
728             if (availableLocales == null) {
729                 return content;
730             }
731 
732             availableLocales = StringUtil.remove(availableLocales, languageId);
733 
734             if (availableLocales.endsWith(",")) {
735                 availableLocales = availableLocales.substring(
736                     0, availableLocales.length() - 1);
737             }
738 
739             root.addAttribute("available-locales", availableLocales);
740 
741             removeArticleLocale(root, languageId);
742 
743             content = formatXML(doc);
744         }
745         catch (Exception e) {
746             _log.error(e);
747         }
748 
749         return content;
750     }
751 
752     public static void removeArticleLocale(Element el, String languageId)
753         throws PortalException, SystemException {
754 
755         for (Element dynamicEl :
756                 (List<Element>)el.elements("dynamic-element")) {
757 
758             for (Element dynamicContentEl :
759                     (List<Element>)dynamicEl.elements("dynamic-content")) {
760 
761                 String curLanguageId = GetterUtil.getString(
762                     dynamicContentEl.attributeValue("language-id"));
763 
764                 if (curLanguageId.equals(languageId)) {
765                     long id = GetterUtil.getLong(
766                         dynamicContentEl.attributeValue("id"));
767 
768                     if (id > 0) {
769                         ImageLocalServiceUtil.deleteImage(id);
770                     }
771 
772                     dynamicContentEl.detach();
773                 }
774             }
775 
776             removeArticleLocale(dynamicEl, languageId);
777         }
778     }
779 
780     public static String removeOldContent(String content, String xsd) {
781         try {
782             SAXReader reader = new SAXReader();
783 
784             Document contentDoc = reader.read(new StringReader(content));
785             Document xsdDoc = reader.read(new StringReader(xsd));
786 
787             Element contentRoot = contentDoc.getRootElement();
788 
789             Stack<String> path = new Stack<String>();
790 
791             path.push(contentRoot.getName());
792 
793             _removeOldContent(path, contentRoot, xsdDoc);
794 
795             content = formatXML(contentDoc);
796         }
797         catch (Exception e) {
798             _log.error(e);
799         }
800 
801         return content;
802     }
803 
804     public static void removeRecentArticle(
805         PortletRequest portletRequest, String articleId) {
806 
807         Stack<JournalArticle> stack = getRecentArticles(portletRequest);
808 
809         Iterator<JournalArticle> itr = stack.iterator();
810 
811         while (itr.hasNext()) {
812             JournalArticle journalArticle = itr.next();
813 
814             if (journalArticle.getArticleId().equals(articleId)) {
815                 itr.remove();
816 
817                 break;
818             }
819         }
820     }
821 
822     public static void removeRecentStructure(
823         PortletRequest portletRequest, String structureId) {
824 
825         Stack<JournalStructure> stack = getRecentStructures(portletRequest);
826 
827         Iterator<JournalStructure> itr = stack.iterator();
828 
829         while (itr.hasNext()) {
830             JournalStructure journalStructure = itr.next();
831 
832             if (journalStructure.getStructureId().equals(structureId)) {
833                 itr.remove();
834 
835                 break;
836             }
837         }
838     }
839 
840     public static void removeRecentTemplate(
841         PortletRequest portletRequest, String templateId) {
842 
843         Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
844 
845         Iterator<JournalTemplate> itr = stack.iterator();
846 
847         while (itr.hasNext()) {
848             JournalTemplate journalTemplate = itr.next();
849 
850             if (journalTemplate.getTemplateId().equals(templateId)) {
851                 itr.remove();
852 
853                 break;
854             }
855         }
856     }
857 
858     public static String transform(
859             Map<String, String> tokens, String languageId, String xml,
860             String script, String langType)
861         throws Exception {
862 
863         // Setup Listeners
864 
865         if (_log.isDebugEnabled()) {
866             _log.debug("Language " + languageId);
867         }
868 
869         if (_logTokens.isDebugEnabled()) {
870             String tokensString = PropertiesUtil.list(tokens);
871 
872             _logTokens.debug(tokensString);
873         }
874 
875         if (_logTransformBefore.isDebugEnabled()) {
876             _logTransformBefore.debug(xml);
877         }
878 
879         List<TransformerListener> listenersList =
880             new ArrayList<TransformerListener>();
881 
882         String[] listeners = PropsUtil.getArray(
883             PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
884 
885         for (int i = 0; i < listeners.length; i++) {
886             TransformerListener listener = null;
887 
888             try {
889                 if (_log.isDebugEnabled()) {
890                     _log.debug("Instantiate listener " + listeners[i]);
891                 }
892 
893                 boolean templateDriven = Validator.isNotNull(langType);
894 
895                 listener = (TransformerListener)Class.forName(
896                     listeners[i]).newInstance();
897 
898                 listener.setTemplateDriven(templateDriven);
899                 listener.setLanguageId(languageId);
900                 listener.setTokens(tokens);
901 
902                 listenersList.add(listener);
903             }
904             catch (Exception e) {
905                 _log.error(e, e);
906             }
907 
908             // Modify XML
909 
910             if (_logXmlBeforeListener.isDebugEnabled()) {
911                 _logXmlBeforeListener.debug(xml);
912             }
913 
914             if (listener != null) {
915                 xml = listener.onXml(xml);
916 
917                 if (_logXmlAfterListener.isDebugEnabled()) {
918                     _logXmlAfterListener.debug(xml);
919                 }
920             }
921 
922             // Modify script
923 
924             if (_logScriptBeforeListener.isDebugEnabled()) {
925                 _logScriptBeforeListener.debug(script);
926             }
927 
928             if (listener != null) {
929                 script = listener.onScript(script);
930 
931                 if (_logScriptAfterListener.isDebugEnabled()) {
932                     _logScriptAfterListener.debug(script);
933                 }
934             }
935         }
936 
937         // Transform
938 
939         String output = null;
940 
941         if (Validator.isNull(langType)) {
942             output = LocalizationUtil.getLocalization(xml, languageId);
943         }
944         else if (langType.equals(JournalTemplateImpl.LANG_TYPE_VM)) {
945             output = JournalVmUtil.transform(tokens, languageId, xml, script);
946         }
947         else if (langType.equals(JournalTemplateImpl.LANG_TYPE_XSL)) {
948             output = JournalXslUtil.transform(tokens, languageId, xml, script);
949         }
950 
951         // Postprocess output
952 
953         for (int i = 0; i < listenersList.size(); i++) {
954             TransformerListener listener = listenersList.get(i);
955 
956             // Modify output
957 
958             if (_logOutputBeforeListener.isDebugEnabled()) {
959                 _logOutputBeforeListener.debug(output);
960             }
961 
962             output = listener.onOutput(output);
963 
964             if (_logOutputAfterListener.isDebugEnabled()) {
965                 _logOutputAfterListener.debug(output);
966             }
967         }
968 
969         if (_logTransfromAfter.isDebugEnabled()) {
970             _logTransfromAfter.debug(output);
971         }
972 
973         return output;
974     }
975 
976     private static void _mergeLocaleContent(
977             Stack<String> path, Document curDoc, Document newDoc, Element xsdEl,
978             String defaultLocale)
979         throws PortalException, SystemException {
980 
981         String elPath = "";
982 
983         for (int i = 0; i < path.size(); i++) {
984             elPath += "/" + path.elementAt(i);
985         }
986 
987         for (int i = 0; i < xsdEl.nodeCount(); i++) {
988             Node xsdNode = xsdEl.node(i);
989 
990             if ((xsdNode instanceof Element) &&
991                 (xsdNode.getName().equals("dynamic-element"))) {
992 
993                 _mergeLocaleContent(
994                     path, curDoc, newDoc, (Element)xsdNode, defaultLocale,
995                     elPath);
996             }
997         }
998     }
999 
1000    private static void _mergeLocaleContent(
1001            Stack<String> path, Document curDoc, Document newDoc, Element xsdEl,
1002            String defaultLocale, String elPath)
1003        throws PortalException, SystemException {
1004
1005        String name = xsdEl.attributeValue("name");
1006
1007        String localPath = "dynamic-element[@name='" + name + "']";
1008
1009        String fullPath = elPath + "/" + localPath;
1010
1011        XPath xPathSelector = DocumentHelper.createXPath(fullPath);
1012
1013        List<Element> curElements = xPathSelector.selectNodes(curDoc);
1014
1015        Element newEl = (Element)xPathSelector.selectNodes(newDoc).get(0);
1016
1017        if (curElements.size() > 0) {
1018            Element curEl = curElements.get(0);
1019
1020            List<Element> curDynamicContents = curEl.elements(
1021                "dynamic-content");
1022
1023            Element newContentEl = newEl.element("dynamic-content");
1024
1025            String newContentLanguageId = newContentEl.attributeValue(
1026                "language-id", StringPool.BLANK);
1027
1028            if (newContentLanguageId.equals(StringPool.BLANK)) {
1029                for (int k = curDynamicContents.size() - 1; k >= 0 ; k--) {
1030                    Element curContentEl = curDynamicContents.get(k);
1031
1032                    String curContentLanguageId = curContentEl.attributeValue(
1033                        "language-id", StringPool.BLANK);
1034
1035                    if ((curEl.attributeValue("type").equals("image")) &&
1036                        (!curContentLanguageId.equals(defaultLocale) &&
1037                         !curContentLanguageId.equals(StringPool.BLANK))) {
1038
1039                        long id = GetterUtil.getLong(
1040                            curContentEl.attributeValue("id"));
1041
1042                        ImageLocalServiceUtil.deleteImage(id);
1043                    }
1044
1045                    curContentEl.detach();
1046                }
1047
1048                curEl.content().add(newContentEl.createCopy());
1049            }
1050            else {
1051                boolean match = false;
1052
1053                for (int k = curDynamicContents.size() - 1; k >= 0 ; k--) {
1054                    Element curContentEl = curDynamicContents.get(k);
1055
1056                    String curContentLanguageId = curContentEl.attributeValue(
1057                        "language-id", StringPool.BLANK);
1058
1059                    if ((newContentLanguageId.equals(curContentLanguageId)) ||
1060                        (newContentLanguageId.equals(defaultLocale) &&
1061                         curContentLanguageId.equals(StringPool.BLANK))) {
1062
1063                        curContentEl.detach();
1064
1065                        curEl.content().add(k, newContentEl.createCopy());
1066
1067                        match = true;
1068                    }
1069
1070                    if (curContentLanguageId.equals(StringPool.BLANK)) {
1071                        curContentEl.addAttribute("language-id", defaultLocale);
1072                    }
1073                }
1074
1075                if (!match) {
1076                    curEl.content().add(newContentEl.createCopy());
1077                }
1078            }
1079        }
1080        else {
1081            xPathSelector = DocumentHelper.createXPath(elPath);
1082
1083            Element parentEl =
1084                (Element)xPathSelector.selectNodes(curDoc).get(0);
1085
1086            parentEl.content().add(newEl.createCopy());
1087        }
1088
1089        String type = xsdEl.attributeValue("type", StringPool.BLANK);
1090
1091        if (!type.equals("list") && !type.equals("multi-list")) {
1092            path.push(localPath);
1093
1094            _mergeLocaleContent(path, curDoc, newDoc, xsdEl, defaultLocale);
1095
1096            path.pop();
1097        }
1098    }
1099
1100    private static void _removeOldContent(
1101            Stack<String> path, Element contentEl, Document xsdDoc)
1102        throws SystemException {
1103
1104        String elPath = "";
1105
1106        for (int i = 0; i < path.size(); i++) {
1107            elPath += "/" + path.elementAt(i);
1108        }
1109
1110        for (int i = 0; i < contentEl.nodeCount(); i++) {
1111            Node contentNode = contentEl.node(i);
1112
1113            if (contentNode instanceof Element) {
1114                _removeOldContent(path, (Element)contentNode, xsdDoc, elPath);
1115            }
1116        }
1117    }
1118
1119    private static void _removeOldContent(
1120            Stack<String> path, Element contentEl, Document xsdDoc,
1121            String elPath)
1122        throws SystemException {
1123
1124        String name = contentEl.attributeValue("name");
1125
1126        if (Validator.isNull(name)) {
1127            return;
1128        }
1129
1130        String localPath = "dynamic-element[@name='" + name + "']";
1131
1132        String fullPath = elPath + "/" + localPath;
1133
1134        XPath xPathSelector = DocumentHelper.createXPath(fullPath);
1135
1136        List<Element> curElements = xPathSelector.selectNodes(xsdDoc);
1137
1138        if (curElements.size() == 0) {
1139            contentEl.detach();
1140        }
1141
1142        path.push(localPath);
1143
1144        _removeOldContent(path, contentEl, xsdDoc);
1145
1146        path.pop();
1147    }
1148
1149    private static Log _log = LogFactory.getLog(JournalUtil.class);
1150
1151    private static Log _logOutputAfterListener = LogFactory.getLog(
1152        JournalUtil.class.getName() + ".OutputAfterListener");
1153
1154    private static Log _logOutputBeforeListener = LogFactory.getLog(
1155        JournalUtil.class.getName() + ".OutputBeforeListener");
1156
1157    private static Log _logScriptAfterListener = LogFactory.getLog(
1158        JournalUtil.class.getName() + ".ScriptAfterListener");
1159
1160    private static Log _logScriptBeforeListener = LogFactory.getLog(
1161        JournalUtil.class.getName() + ".ScriptBeforeListener");
1162
1163    private static Log _logTransfromAfter = LogFactory.getLog(
1164        JournalUtil.class.getName() + ".TransformAfter");
1165
1166    private static Log _logTransformBefore = LogFactory.getLog(
1167        JournalUtil.class.getName() + ".BeforeTransform");
1168
1169    private static Log _logTokens = LogFactory.getLog(
1170        JournalUtil.class.getName() + ".Tokens");
1171
1172    private static Log _logXmlAfterListener = LogFactory.getLog(
1173        JournalUtil.class.getName() + ".XmlAfterListener");
1174
1175    private static Log _logXmlBeforeListener = LogFactory.getLog(
1176        JournalUtil.class.getName() + ".XmlBeforeListener");
1177
1178}