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