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