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.Constants;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.HttpUtil;
32  import com.liferay.portal.kernel.util.LocaleUtil;
33  import com.liferay.portal.kernel.util.OrderByComparator;
34  import com.liferay.portal.kernel.util.PropertiesUtil;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.StringUtil;
37  import com.liferay.portal.kernel.util.Time;
38  import com.liferay.portal.kernel.util.Validator;
39  import com.liferay.portal.kernel.xml.Document;
40  import com.liferay.portal.kernel.xml.Element;
41  import com.liferay.portal.kernel.xml.Node;
42  import com.liferay.portal.kernel.xml.SAXReaderUtil;
43  import com.liferay.portal.kernel.xml.XPath;
44  import com.liferay.portal.model.Group;
45  import com.liferay.portal.model.Layout;
46  import com.liferay.portal.model.LayoutSet;
47  import com.liferay.portal.model.User;
48  import com.liferay.portal.service.ImageLocalServiceUtil;
49  import com.liferay.portal.service.LayoutLocalServiceUtil;
50  import com.liferay.portal.service.UserLocalServiceUtil;
51  import com.liferay.portal.theme.ThemeDisplay;
52  import com.liferay.portal.util.ContentUtil;
53  import com.liferay.portal.util.PropsKeys;
54  import com.liferay.portal.util.PropsUtil;
55  import com.liferay.portal.util.WebKeys;
56  import com.liferay.portlet.journal.model.JournalArticle;
57  import com.liferay.portlet.journal.model.JournalStructure;
58  import com.liferay.portlet.journal.model.JournalTemplate;
59  import com.liferay.portlet.journal.model.impl.JournalStructureImpl;
60  import com.liferay.portlet.journal.model.impl.JournalTemplateImpl;
61  import com.liferay.portlet.journal.service.JournalArticleImageLocalServiceUtil;
62  import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
63  import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
64  import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
65  import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
66  import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
67  import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
68  import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
69  import com.liferay.util.FiniteUniqueStack;
70  import com.liferay.util.LocalizationUtil;
71  import com.liferay.util.xml.XMLFormatter;
72  
73  import java.io.IOException;
74  
75  import java.util.ArrayList;
76  import java.util.Date;
77  import java.util.HashMap;
78  import java.util.Iterator;
79  import java.util.List;
80  import java.util.Map;
81  import java.util.Stack;
82  
83  import javax.portlet.PortletPreferences;
84  import javax.portlet.PortletRequest;
85  import javax.portlet.PortletSession;
86  
87  /**
88   * <a href="JournalUtil.java.html"><b><i>View Source</i></b></a>
89   *
90   * @author Brian Wing Shun Chan
91   * @author Raymond Augé
92   *
93   */
94  public class JournalUtil {
95  
96      public static final int MAX_STACK_SIZE = 20;
97  
98      public static final String XML_INDENT = "  ";
99  
100     public static void addRecentArticle(
101         PortletRequest portletRequest, JournalArticle article) {
102 
103         if (article != null) {
104             Stack<JournalArticle> stack = getRecentArticles(portletRequest);
105 
106             stack.push(article);
107         }
108     }
109 
110     public static void addRecentStructure(
111         PortletRequest portletRequest, JournalStructure structure) {
112 
113         if (structure != null) {
114             Stack<JournalStructure> stack = getRecentStructures(portletRequest);
115 
116             stack.push(structure);
117         }
118     }
119 
120     public static void addRecentTemplate(
121         PortletRequest portletRequest, JournalTemplate template) {
122 
123         if (template != null) {
124             Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
125 
126             stack.push(template);
127         }
128     }
129 
130     public static void addReservedEl(
131         Element root, Map<String, String> tokens, String name, double value) {
132 
133         addReservedEl(root, tokens, name, String.valueOf(value));
134     }
135 
136     public static void addReservedEl(
137         Element root, Map<String, String> tokens, String name, Date value) {
138 
139         addReservedEl(root, tokens, name, Time.getRFC822(value));
140     }
141 
142     public static void addReservedEl(
143         Element root, Map<String, String> tokens, String name, String value) {
144 
145         // XML
146 
147         if (root != null) {
148             Element dynamicEl = SAXReaderUtil.createElement("dynamic-element");
149 
150             dynamicEl.add(
151                 SAXReaderUtil.createAttribute(dynamicEl, "name", name));
152             dynamicEl.add(
153                 SAXReaderUtil.createAttribute(dynamicEl, "type", "text"));
154 
155             Element dynamicContent = SAXReaderUtil.createElement(
156                 "dynamic-content");
157 
158             //dynamicContent.setText("<![CDATA[" + value + "]]>");
159             dynamicContent.setText(value);
160 
161             dynamicEl.add(dynamicContent);
162 
163             root.add(dynamicEl);
164         }
165 
166         // Tokens
167 
168         tokens.put(
169             StringUtil.replace(name, StringPool.DASH, StringPool.UNDERLINE),
170             value);
171     }
172 
173     public static void addAllReservedEls(
174         Element root, Map<String, String> tokens, JournalArticle article) {
175 
176         JournalUtil.addReservedEl(
177             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_ID,
178             article.getArticleId());
179 
180         JournalUtil.addReservedEl(
181             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_VERSION,
182             article.getVersion());
183 
184         JournalUtil.addReservedEl(
185             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_TITLE,
186             article.getTitle());
187 
188         JournalUtil.addReservedEl(
189             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_DESCRIPTION,
190             article.getDescription());
191 
192         JournalUtil.addReservedEl(
193             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_TYPE,
194             article.getType());
195 
196         JournalUtil.addReservedEl(
197             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_CREATE_DATE,
198             article.getCreateDate());
199 
200         JournalUtil.addReservedEl(
201             root, tokens,
202             JournalStructureImpl.RESERVED_ARTICLE_MODIFIED_DATE,
203             article.getModifiedDate());
204 
205         if (article.getDisplayDate() != null) {
206             JournalUtil.addReservedEl(
207                 root, tokens,
208                 JournalStructureImpl.RESERVED_ARTICLE_DISPLAY_DATE,
209                 article.getDisplayDate());
210         }
211 
212         JournalUtil.addReservedEl(
213             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_SMALL_IMAGE_URL,
214             article.getSmallImageURL());
215 
216         JournalUtil.addReservedEl(
217             root, tokens, JournalStructureImpl.RESERVED_ARTICLE_AUTHOR_ID,
218             String.valueOf(article.getUserId()));
219 
220         String userName = StringPool.BLANK;
221         String userEmailAddress = StringPool.BLANK;
222         String userComments = StringPool.BLANK;
223         String userJobTitle = StringPool.BLANK;
224 
225         User user = null;
226 
227         try {
228             user = UserLocalServiceUtil.getUserById(article.getUserId());
229 
230             userName = user.getFullName();
231             userEmailAddress = user.getEmailAddress();
232             userComments = user.getComments();
233             userJobTitle = user.getJobTitle();
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 preferences) {
321         String emailFromAddress = PropsUtil.get(
322             PropsKeys.JOURNAL_EMAIL_FROM_ADDRESS);
323 
324         return preferences.getValue("email-from-address", emailFromAddress);
325     }
326 
327     public static String getEmailFromName(PortletPreferences preferences) {
328         String emailFromName = PropsUtil.get(
329             PropsKeys.JOURNAL_EMAIL_FROM_NAME);
330 
331         return preferences.getValue("email-from-name", emailFromName);
332     }
333 
334     public static boolean getEmailArticleApprovalDeniedEnabled(
335         PortletPreferences preferences) {
336 
337         String emailArticleApprovalDeniedEnabled = preferences.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 preferences) {
351 
352         String emailArticleApprovalDeniedBody = preferences.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 preferences) {
366 
367         String emailArticleApprovalDeniedSubject = preferences.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 preferences) {
381 
382         String emailArticleApprovalGrantedEnabled = preferences.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 preferences) {
396 
397         String emailArticleApprovalGrantedBody = preferences.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 preferences) {
411 
412         String emailArticleApprovalGrantedSubject = preferences.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 preferences) {
426 
427         String emailArticleApprovalRequestedEnabled = preferences.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 preferences) {
441 
442         String emailArticleApprovalRequestedBody = preferences.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 preferences) {
456 
457         String emailArticleApprovalRequestedSubject = preferences.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 preferences) {
471 
472         String emailArticleReviewEnabled = preferences.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(
485         PortletPreferences preferences) {
486 
487         String emailArticleReviewBody = preferences.getValue(
488             "email-article-review-body", StringPool.BLANK);
489 
490         if (Validator.isNotNull(emailArticleReviewBody)) {
491             return emailArticleReviewBody;
492         }
493         else {
494             return ContentUtil.get(PropsUtil.get(
495                 PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_BODY));
496         }
497     }
498 
499     public static String getEmailArticleReviewSubject(
500         PortletPreferences preferences) {
501 
502         String emailArticleReviewSubject = preferences.getValue(
503             "email-article-review-subject", StringPool.BLANK);
504 
505         if (Validator.isNotNull(emailArticleReviewSubject)) {
506             return emailArticleReviewSubject;
507         }
508         else {
509             return ContentUtil.get(PropsUtil.get(
510                 PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_SUBJECT));
511         }
512     }
513 
514     public static Stack<JournalArticle> getRecentArticles(
515         PortletRequest portletRequest) {
516 
517         PortletSession portletSession = portletRequest.getPortletSession();
518 
519         Stack<JournalArticle> recentArticles =
520             (Stack<JournalArticle>)portletSession.getAttribute(
521                 WebKeys.JOURNAL_RECENT_ARTICLES);
522 
523         if (recentArticles == null) {
524             recentArticles = new FiniteUniqueStack<JournalArticle>(
525                 MAX_STACK_SIZE);
526 
527             portletSession.setAttribute(
528                 WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
529         }
530 
531         return recentArticles;
532     }
533 
534     public static Stack<JournalStructure> getRecentStructures(
535         PortletRequest portletRequest) {
536 
537         PortletSession portletSession = portletRequest.getPortletSession();
538 
539         Stack<JournalStructure> recentStructures =
540             (Stack<JournalStructure>)portletSession.getAttribute(
541                 WebKeys.JOURNAL_RECENT_STRUCTURES);
542 
543         if (recentStructures == null) {
544             recentStructures = new FiniteUniqueStack<JournalStructure>(
545                 MAX_STACK_SIZE);
546 
547             portletSession.setAttribute(
548                 WebKeys.JOURNAL_RECENT_STRUCTURES, recentStructures);
549         }
550 
551         return recentStructures;
552     }
553 
554     public static Stack<JournalTemplate> getRecentTemplates(
555         PortletRequest portletRequest) {
556 
557         PortletSession portletSession = portletRequest.getPortletSession();
558 
559         Stack<JournalTemplate> recentTemplates =
560             (Stack<JournalTemplate>)portletSession.getAttribute(
561                 WebKeys.JOURNAL_RECENT_TEMPLATES);
562 
563         if (recentTemplates == null) {
564             recentTemplates = new FiniteUniqueStack<JournalTemplate>(
565                 MAX_STACK_SIZE);
566 
567             portletSession.setAttribute(
568                 WebKeys.JOURNAL_RECENT_TEMPLATES, recentTemplates);
569         }
570 
571         return recentTemplates;
572     }
573 
574     public static String getTemplateScript(
575             long groupId, String templateId, Map<String, String> tokens,
576             String languageId)
577         throws PortalException, SystemException {
578 
579         return getTemplateScript(groupId, templateId, tokens, languageId, true);
580     }
581 
582     public static String getTemplateScript(
583             long groupId, String templateId, Map<String, String> tokens,
584             String languageId, boolean transform)
585         throws PortalException, SystemException {
586 
587         JournalTemplate template = JournalTemplateLocalServiceUtil.getTemplate(
588             groupId, templateId);
589 
590         return getTemplateScript(template, tokens, languageId, transform);
591     }
592 
593     public static String getTemplateScript(
594         JournalTemplate template, Map<String, String> tokens, String languageId,
595         boolean transform) {
596 
597         String script = template.getXsl();
598 
599         if (transform) {
600 
601             // Listeners
602 
603             String[] listeners =
604                 PropsUtil.getArray(PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
605 
606             for (int i = 0; i < listeners.length; i++) {
607                 TransformerListener listener = null;
608 
609                 try {
610                     listener =
611                         (TransformerListener)Class.forName(
612                             listeners[i]).newInstance();
613 
614                     listener.setTemplateDriven(true);
615                     listener.setLanguageId(languageId);
616                     listener.setTokens(tokens);
617                 }
618                 catch (Exception e) {
619                     _log.error(e, e);
620                 }
621 
622                 // Modify transform script
623 
624                 if (listener != null) {
625                     script = listener.onScript(script);
626                 }
627             }
628         }
629 
630         return script;
631     }
632 
633     public static Map<String, String> getTokens(
634         long groupId, ThemeDisplay themeDisplay) {
635 
636         return getTokens(groupId, themeDisplay, null);
637     }
638 
639     public static Map<String, String> getTokens(
640         long groupId, ThemeDisplay themeDisplay, String xmlRequest) {
641 
642         Map<String, String> tokens = new HashMap<String, String>();
643 
644         if (themeDisplay != null) {
645             _populateTokens(tokens, groupId, themeDisplay);
646         }
647         else if (Validator.isNotNull(xmlRequest)) {
648             try {
649                 _populateTokens(tokens, groupId, xmlRequest);
650             }
651             catch (Exception e) {
652                 if (_log.isWarnEnabled()) {
653                     _log.warn(e, e);
654                 }
655             }
656         }
657 
658         return tokens;
659     }
660 
661     public static String mergeArticleContent(
662         String curContent, String newContent) {
663 
664         try {
665             Document curDocument = SAXReaderUtil.read(curContent);
666             Document newDocument = SAXReaderUtil.read(newContent);
667 
668             Element curRoot = curDocument.getRootElement();
669             Element newRoot = newDocument.getRootElement();
670 
671             curRoot.addAttribute(
672                 "default-locale",
673                 newRoot.attributeValue("default-locale"));
674             curRoot.addAttribute(
675                 "available-locales",
676                 newRoot.attributeValue("available-locales"));
677 
678             _mergeArticleContentUpdate(
679                 curDocument, newRoot,
680                 LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
681             _mergeArticleContentDelete(curRoot, newDocument);
682 
683             curContent = JournalUtil.formatXML(curDocument);
684         }
685         catch (Exception e) {
686             _log.error(e, 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, 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, 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 viewMode, String languageId,
830             String xml, 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 (Validator.isNull(viewMode)) {
840             viewMode = Constants.VIEW;
841         }
842 
843         if (_logTokens.isDebugEnabled()) {
844             String tokensString = PropertiesUtil.list(tokens);
845 
846             _logTokens.debug(tokensString);
847         }
848 
849         if (_logTransformBefore.isDebugEnabled()) {
850             _logTransformBefore.debug(xml);
851         }
852 
853         List<TransformerListener> listenersList =
854             new ArrayList<TransformerListener>();
855 
856         String[] listeners = PropsUtil.getArray(
857             PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
858 
859         for (int i = 0; i < listeners.length; i++) {
860             TransformerListener listener = null;
861 
862             try {
863                 if (_log.isDebugEnabled()) {
864                     _log.debug("Instantiate listener " + listeners[i]);
865                 }
866 
867                 boolean templateDriven = Validator.isNotNull(langType);
868 
869                 listener = (TransformerListener)Class.forName(
870                     listeners[i]).newInstance();
871 
872                 listener.setTemplateDriven(templateDriven);
873                 listener.setLanguageId(languageId);
874                 listener.setTokens(tokens);
875 
876                 listenersList.add(listener);
877             }
878             catch (Exception e) {
879                 _log.error(e, e);
880             }
881 
882             // Modify XML
883 
884             if (_logXmlBeforeListener.isDebugEnabled()) {
885                 _logXmlBeforeListener.debug(xml);
886             }
887 
888             if (listener != null) {
889                 xml = listener.onXml(xml);
890 
891                 if (_logXmlAfterListener.isDebugEnabled()) {
892                     _logXmlAfterListener.debug(xml);
893                 }
894             }
895 
896             // Modify script
897 
898             if (_logScriptBeforeListener.isDebugEnabled()) {
899                 _logScriptBeforeListener.debug(script);
900             }
901 
902             if (listener != null) {
903                 script = listener.onScript(script);
904 
905                 if (_logScriptAfterListener.isDebugEnabled()) {
906                     _logScriptAfterListener.debug(script);
907                 }
908             }
909         }
910 
911         // Transform
912 
913         String output = null;
914 
915         if (Validator.isNull(langType)) {
916             output = LocalizationUtil.getLocalization(xml, languageId);
917         }
918         else if (langType.equals(JournalTemplateImpl.LANG_TYPE_VM)) {
919             output = JournalVmUtil.transform(
920                 tokens, viewMode, languageId, xml, script);
921         }
922         else if (langType.equals(JournalTemplateImpl.LANG_TYPE_XSL)) {
923             output = JournalXslUtil.transform(
924                 tokens, viewMode, languageId, xml, script);
925         }
926 
927         // Postprocess output
928 
929         for (int i = 0; i < listenersList.size(); i++) {
930             TransformerListener listener = listenersList.get(i);
931 
932             // Modify output
933 
934             if (_logOutputBeforeListener.isDebugEnabled()) {
935                 _logOutputBeforeListener.debug(output);
936             }
937 
938             output = listener.onOutput(output);
939 
940             if (_logOutputAfterListener.isDebugEnabled()) {
941                 _logOutputAfterListener.debug(output);
942             }
943         }
944 
945         if (_logTransfromAfter.isDebugEnabled()) {
946             _logTransfromAfter.debug(output);
947         }
948 
949         return output;
950     }
951 
952     private static Element _getElementByInstanceId(
953         Document document, String instanceId) {
954 
955         XPath xPathSelector = SAXReaderUtil.createXPath(
956             "//dynamic-element[@instance-id='" + instanceId + "']");
957 
958         List<Node> nodes = xPathSelector.selectNodes(document);
959 
960         if (nodes.size() == 1) {
961             return (Element)nodes.get(0);
962         }
963         else {
964             return null;
965         }
966     }
967 
968     private static void _mergeArticleContentDelete(
969             Element curParentElement, Document newDocument)
970         throws Exception {
971 
972         List<Element> curElements = curParentElement.elements(
973             "dynamic-element");
974 
975         for (int i = 0; i < curElements.size(); i++) {
976             Element curElement = curElements.get(i);
977 
978             _mergeArticleContentDelete(curElement, newDocument);
979 
980             String instanceId = curElement.attributeValue("instance-id");
981 
982             Element newElement = _getElementByInstanceId(
983                 newDocument, instanceId);
984 
985             if (newElement == null) {
986                 curElement.detach();
987 
988                 String type = curElement.attributeValue("type");
989 
990                 if (type.equals("image")) {
991                     _mergeArticleContentDeleteImages(
992                         curElement.elements("dynamic-content"));
993                 }
994             }
995         }
996     }
997 
998     private static void _mergeArticleContentDeleteImages(List<Element> elements)
999         throws Exception {
1000
1001        for (Element element : elements) {
1002            long articleImageId = GetterUtil.getLong(
1003                element.attributeValue("id"));
1004
1005            JournalArticleImageLocalServiceUtil.deleteArticleImage(
1006                articleImageId);
1007        }
1008    }
1009
1010    private static void _mergeArticleContentUpdate(
1011            Document curDocument, Element newParentElement,
1012            String defaultLocale)
1013        throws Exception {
1014
1015        List<Element> newElements = newParentElement.elements(
1016            "dynamic-element");
1017
1018        for (int i = 0; i < newElements.size(); i++) {
1019            Element newElement = newElements.get(i);
1020
1021            _mergeArticleContentUpdate(
1022                curDocument, newParentElement, newElement, i, defaultLocale);
1023        }
1024    }
1025
1026    private static void _mergeArticleContentUpdate(
1027            Document curDocument, Element newParentElement, Element newElement,
1028            int pos, String defaultLocale)
1029        throws Exception {
1030
1031        _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1032
1033        String instanceId = newElement.attributeValue("instance-id");
1034
1035        Element curElement = _getElementByInstanceId(curDocument, instanceId);
1036
1037        if (curElement != null) {
1038            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1039        }
1040        else {
1041            String parentInstanceId = newParentElement.attributeValue(
1042                "instance-id");
1043
1044            if (Validator.isNull(parentInstanceId)) {
1045                Element curRoot = curDocument.getRootElement();
1046
1047                List<Element> curRootElements = curRoot.elements();
1048
1049                curRootElements.add(pos, newElement.createCopy());
1050            }
1051            else {
1052                Element curParentElement = _getElementByInstanceId(
1053                    curDocument, parentInstanceId);
1054
1055                if (curParentElement != null) {
1056                    List<Element> curParentElements =
1057                        curParentElement.elements();
1058
1059                    curParentElements.add(pos, newElement.createCopy());
1060                }
1061            }
1062        }
1063    }
1064
1065    private static void _mergeArticleContentUpdate(
1066        Element curElement, Element newElement, String defaultLocale) {
1067
1068        Element newContentElement = newElement.elements(
1069            "dynamic-content").get(0);
1070
1071        String newLanguageId = newContentElement.attributeValue("language-id");
1072        String newValue = newContentElement.getText();
1073
1074        List<Element> curContentElements = curElement.elements(
1075            "dynamic-content");
1076
1077        if (Validator.isNull(newLanguageId)) {
1078            for (Element curContentElement : curContentElements) {
1079                curContentElement.detach();
1080            }
1081
1082            Element curContentElement = SAXReaderUtil.createElement(
1083                "dynamic-content");
1084
1085            curContentElement.addCDATA(newValue);
1086
1087            curElement.add(curContentElement);
1088        }
1089        else {
1090            boolean alreadyExists = false;
1091
1092            for (Element curContentElement : curContentElements) {
1093                String curLanguageId = curContentElement.attributeValue(
1094                    "language-id");
1095
1096                if (newLanguageId.equals(curLanguageId)) {
1097                    alreadyExists = true;
1098
1099                    curContentElement.clearContent();
1100                    curContentElement.addCDATA(newValue);
1101
1102                    break;
1103                }
1104            }
1105
1106            if (!alreadyExists) {
1107                Element curContentElement = curContentElements.get(0);
1108
1109                String curLanguageId = curContentElement.attributeValue(
1110                    "language-id");
1111
1112                if (Validator.isNull(curLanguageId)) {
1113                    curContentElement.detach();
1114                }
1115
1116                curElement.add(newContentElement.createCopy());
1117            }
1118        }
1119    }
1120
1121    private static void _populateTokens(
1122            Map<String, String> tokens, long groupId, String xmlRequest)
1123        throws Exception {
1124
1125        Document request = SAXReaderUtil.read(xmlRequest);
1126
1127        Element root = request.getRootElement();
1128
1129        Element themeDisplayEl = root.element("theme-display");
1130
1131        Layout layout = LayoutLocalServiceUtil.getLayout(
1132            GetterUtil.getLong(themeDisplayEl.elementText("plid")));
1133
1134        Group group = layout.getGroup();
1135
1136        LayoutSet layoutSet = layout.getLayoutSet();
1137
1138        String friendlyUrlCurrent = null;
1139
1140        if (layout.isPublicLayout()) {
1141            friendlyUrlCurrent = themeDisplayEl.elementText(
1142                "path-friendly-url-public");
1143        }
1144        else if (group.isUserGroup()) {
1145            friendlyUrlCurrent = themeDisplayEl.elementText(
1146                "path-friendly-url-private-user");
1147        }
1148        else {
1149            friendlyUrlCurrent = themeDisplayEl.elementText(
1150                "path-friendly-url-private-group");
1151        }
1152
1153        String layoutSetFriendlyUrl = StringPool.BLANK;
1154
1155        String virtualHost = layoutSet.getVirtualHost();
1156
1157        if (Validator.isNull(virtualHost) ||
1158            !virtualHost.equals(themeDisplayEl.elementText("server-name"))) {
1159
1160            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1161        }
1162
1163        tokens.put("cdn_host", themeDisplayEl.elementText("cdn-host"));
1164        tokens.put("company_id", themeDisplayEl.elementText("company-id"));
1165        tokens.put("friendly_url_current", friendlyUrlCurrent);
1166        tokens.put(
1167            "friendly_url_private_group",
1168            themeDisplayEl.elementText("path-friendly-url-private-group"));
1169        tokens.put(
1170            "friendly_url_private_user",
1171            themeDisplayEl.elementText("path-friendly-url-private-user"));
1172        tokens.put(
1173            "friendly_url_public",
1174            themeDisplayEl.elementText("path-friendly-url-public"));
1175        tokens.put("group_friendly_url", group.getFriendlyURL());
1176        tokens.put("group_id", String.valueOf(groupId));
1177        tokens.put("image_path", themeDisplayEl.elementText("path-image"));
1178        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1179        tokens.put("main_path", themeDisplayEl.elementText("path-main"));
1180        tokens.put("portal_ctx", themeDisplayEl.elementText("path-context"));
1181        tokens.put(
1182            "portal_url",
1183            HttpUtil.removeProtocol(themeDisplayEl.elementText("url-portal")));
1184        tokens.put("root_path", themeDisplayEl.elementText("path-context"));
1185        tokens.put(
1186            "theme_image_path",
1187            themeDisplayEl.elementText("path-theme-images"));
1188
1189        // Deprecated tokens
1190
1191        tokens.put(
1192            "friendly_url",
1193            themeDisplayEl.elementText("path-friendly-url-public"));
1194        tokens.put(
1195            "friendly_url_private",
1196            themeDisplayEl.elementText("path-friendly-url-private-group"));
1197        tokens.put(
1198            "page_url", themeDisplayEl.elementText("path-friendly-url-public"));
1199    }
1200
1201    private static void _populateTokens(
1202        Map<String, String> tokens, long groupId, ThemeDisplay themeDisplay) {
1203
1204        Layout layout = themeDisplay.getLayout();
1205
1206        Group group = layout.getGroup();
1207
1208        LayoutSet layoutSet = layout.getLayoutSet();
1209
1210        String friendlyUrlCurrent = null;
1211
1212        if (layout.isPublicLayout()) {
1213            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1214        }
1215        else if (group.isUserGroup()) {
1216            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1217        }
1218        else {
1219            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1220        }
1221
1222        String layoutSetFriendlyUrl = StringPool.BLANK;
1223
1224        String virtualHost = layoutSet.getVirtualHost();
1225
1226        if (Validator.isNull(virtualHost) ||
1227            !virtualHost.equals(themeDisplay.getServerName())) {
1228
1229            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1230        }
1231
1232        tokens.put("cdn_host", themeDisplay.getCDNHost());
1233        tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1234        tokens.put("friendly_url_current", friendlyUrlCurrent);
1235        tokens.put(
1236            "friendly_url_private_group",
1237            themeDisplay.getPathFriendlyURLPrivateGroup());
1238        tokens.put(
1239            "friendly_url_private_user",
1240            themeDisplay.getPathFriendlyURLPrivateUser());
1241        tokens.put(
1242            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1243        tokens.put("group_friendly_url", group.getFriendlyURL());
1244        tokens.put("group_id", String.valueOf(groupId));
1245        tokens.put("image_path", themeDisplay.getPathImage());
1246        tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1247        tokens.put("main_path", themeDisplay.getPathMain());
1248        tokens.put("portal_ctx", themeDisplay.getPathContext());
1249        tokens.put(
1250            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1251        tokens.put("root_path", themeDisplay.getPathContext());
1252        tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1253
1254        // Deprecated tokens
1255
1256        tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1257        tokens.put(
1258            "friendly_url_private",
1259            themeDisplay.getPathFriendlyURLPrivateGroup());
1260        tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1261    }
1262
1263    private static void _removeOldContent(
1264            Stack<String> path, Element contentEl, Document xsdDoc)
1265        throws SystemException {
1266
1267        String elPath = "";
1268
1269        for (int i = 0; i < path.size(); i++) {
1270            elPath += "/" + path.elementAt(i);
1271        }
1272
1273        for (int i = 0; i < contentEl.nodeCount(); i++) {
1274            Node contentNode = contentEl.node(i);
1275
1276            if (contentNode instanceof Element) {
1277                _removeOldContent(path, (Element)contentNode, xsdDoc, elPath);
1278            }
1279        }
1280    }
1281
1282    private static void _removeOldContent(
1283            Stack<String> path, Element contentEl, Document xsdDoc,
1284            String elPath)
1285        throws SystemException {
1286
1287        String name = contentEl.attributeValue("name");
1288
1289        if (Validator.isNull(name)) {
1290            return;
1291        }
1292
1293        String localPath = "dynamic-element[@name='" + name + "']";
1294
1295        String fullPath = elPath + "/" + localPath;
1296
1297        XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1298
1299        List<Node> curNodes = xPathSelector.selectNodes(xsdDoc);
1300
1301        if (curNodes.size() == 0) {
1302            contentEl.detach();
1303        }
1304
1305        path.push(localPath);
1306
1307        _removeOldContent(path, contentEl, xsdDoc);
1308
1309        path.pop();
1310    }
1311
1312    private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1313
1314    private static Log _logOutputAfterListener = LogFactoryUtil.getLog(
1315        JournalUtil.class.getName() + ".OutputAfterListener");
1316
1317    private static Log _logOutputBeforeListener = LogFactoryUtil.getLog(
1318        JournalUtil.class.getName() + ".OutputBeforeListener");
1319
1320    private static Log _logScriptAfterListener = LogFactoryUtil.getLog(
1321        JournalUtil.class.getName() + ".ScriptAfterListener");
1322
1323    private static Log _logScriptBeforeListener = LogFactoryUtil.getLog(
1324        JournalUtil.class.getName() + ".ScriptBeforeListener");
1325
1326    private static Log _logTransfromAfter = LogFactoryUtil.getLog(
1327        JournalUtil.class.getName() + ".TransformAfter");
1328
1329    private static Log _logTransformBefore = LogFactoryUtil.getLog(
1330        JournalUtil.class.getName() + ".BeforeTransform");
1331
1332    private static Log _logTokens = LogFactoryUtil.getLog(
1333        JournalUtil.class.getName() + ".Tokens");
1334
1335    private static Log _logXmlAfterListener = LogFactoryUtil.getLog(
1336        JournalUtil.class.getName() + ".XmlAfterListener");
1337
1338    private static Log _logXmlBeforeListener = LogFactoryUtil.getLog(
1339        JournalUtil.class.getName() + ".XmlBeforeListener");
1340
1341}