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