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