001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.journal.util;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.search.Field;
023    import com.liferay.portal.kernel.search.Hits;
024    import com.liferay.portal.kernel.search.Indexer;
025    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
026    import com.liferay.portal.kernel.templateparser.Transformer;
027    import com.liferay.portal.kernel.templateparser.TransformerListener;
028    import com.liferay.portal.kernel.util.CharPool;
029    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.HttpUtil;
032    import com.liferay.portal.kernel.util.LocaleUtil;
033    import com.liferay.portal.kernel.util.OrderByComparator;
034    import com.liferay.portal.kernel.util.PropsKeys;
035    import com.liferay.portal.kernel.util.StringBundler;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.Time;
039    import com.liferay.portal.kernel.util.Tuple;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.kernel.xml.Attribute;
042    import com.liferay.portal.kernel.xml.Document;
043    import com.liferay.portal.kernel.xml.Element;
044    import com.liferay.portal.kernel.xml.Node;
045    import com.liferay.portal.kernel.xml.SAXReaderUtil;
046    import com.liferay.portal.kernel.xml.XPath;
047    import com.liferay.portal.model.Group;
048    import com.liferay.portal.model.Layout;
049    import com.liferay.portal.model.LayoutSet;
050    import com.liferay.portal.model.ModelHintsUtil;
051    import com.liferay.portal.model.User;
052    import com.liferay.portal.service.ImageLocalServiceUtil;
053    import com.liferay.portal.service.LayoutLocalServiceUtil;
054    import com.liferay.portal.service.UserLocalServiceUtil;
055    import com.liferay.portal.theme.ThemeDisplay;
056    import com.liferay.portal.util.PortalUtil;
057    import com.liferay.portal.util.PropsUtil;
058    import com.liferay.portal.util.PropsValues;
059    import com.liferay.portal.util.WebKeys;
060    import com.liferay.portal.webserver.WebServerServletTokenUtil;
061    import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
062    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
063    import com.liferay.portlet.journal.NoSuchArticleException;
064    import com.liferay.portlet.journal.StructureXsdException;
065    import com.liferay.portlet.journal.model.JournalArticle;
066    import com.liferay.portlet.journal.model.JournalStructure;
067    import com.liferay.portlet.journal.model.JournalStructureConstants;
068    import com.liferay.portlet.journal.model.JournalTemplate;
069    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
070    import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
071    import com.liferay.portlet.journal.util.comparator.ArticleCreateDateComparator;
072    import com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator;
073    import com.liferay.portlet.journal.util.comparator.ArticleIDComparator;
074    import com.liferay.portlet.journal.util.comparator.ArticleModifiedDateComparator;
075    import com.liferay.portlet.journal.util.comparator.ArticleReviewDateComparator;
076    import com.liferay.portlet.journal.util.comparator.ArticleTitleComparator;
077    import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
078    import com.liferay.util.ContentUtil;
079    import com.liferay.util.FiniteUniqueStack;
080    import com.liferay.util.JS;
081    
082    import java.util.ArrayList;
083    import java.util.Date;
084    import java.util.HashMap;
085    import java.util.Iterator;
086    import java.util.List;
087    import java.util.Map;
088    import java.util.Stack;
089    
090    import javax.portlet.PortletPreferences;
091    import javax.portlet.PortletRequest;
092    import javax.portlet.PortletSession;
093    
094    /**
095     * @author Brian Wing Shun Chan
096     * @author Raymond Aug??
097     * @author Wesley Gong
098     * @author Angelo Jefferson
099     * @author Hugo Huijser
100     */
101    public class JournalUtil {
102    
103            public static final int MAX_STACK_SIZE = 20;
104    
105            public static void addAllReservedEls(
106                    Element rootElement, Map<String, String> tokens, JournalArticle article,
107                    String languageId, ThemeDisplay themeDisplay) {
108    
109                    JournalUtil.addReservedEl(
110                            rootElement, tokens, JournalStructureConstants.RESERVED_ARTICLE_ID,
111                            article.getArticleId());
112    
113                    JournalUtil.addReservedEl(
114                            rootElement, tokens,
115                            JournalStructureConstants.RESERVED_ARTICLE_VERSION,
116                            article.getVersion());
117    
118                    JournalUtil.addReservedEl(
119                            rootElement, tokens,
120                            JournalStructureConstants.RESERVED_ARTICLE_TITLE,
121                            article.getTitle(languageId));
122    
123                    JournalUtil.addReservedEl(
124                            rootElement, tokens,
125                            JournalStructureConstants.RESERVED_ARTICLE_URL_TITLE,
126                            article.getUrlTitle());
127    
128                    JournalUtil.addReservedEl(
129                            rootElement, tokens,
130                            JournalStructureConstants.RESERVED_ARTICLE_DESCRIPTION,
131                            article.getDescription(languageId));
132    
133                    JournalUtil.addReservedEl(
134                            rootElement, tokens,
135                            JournalStructureConstants.RESERVED_ARTICLE_TYPE, article.getType());
136    
137                    JournalUtil.addReservedEl(
138                            rootElement, tokens,
139                            JournalStructureConstants.RESERVED_ARTICLE_CREATE_DATE,
140                            article.getCreateDate());
141    
142                    JournalUtil.addReservedEl(
143                            rootElement, tokens,
144                            JournalStructureConstants.RESERVED_ARTICLE_MODIFIED_DATE,
145                            article.getModifiedDate());
146    
147                    if (article.getDisplayDate() != null) {
148                            JournalUtil.addReservedEl(
149                                    rootElement, tokens,
150                                    JournalStructureConstants.RESERVED_ARTICLE_DISPLAY_DATE,
151                                    article.getDisplayDate());
152                    }
153    
154                    String smallImageURL = StringPool.BLANK;
155    
156                    if (Validator.isNotNull(article.getSmallImageURL())) {
157                            smallImageURL = article.getSmallImageURL();
158                    }
159                    else if ((themeDisplay != null) && article.isSmallImage()) {
160                            StringBundler sb = new StringBundler(5);
161    
162                            sb.append(themeDisplay.getPathImage());
163                            sb.append("/journal/article?img_id=");
164                            sb.append(article.getSmallImageId());
165                            sb.append("&t=");
166                            sb.append(
167                                    WebServerServletTokenUtil.getToken(article.getSmallImageId()));
168    
169                            smallImageURL = sb.toString();
170                    }
171    
172                    JournalUtil.addReservedEl(
173                            rootElement, tokens,
174                            JournalStructureConstants.RESERVED_ARTICLE_SMALL_IMAGE_URL,
175                            smallImageURL);
176    
177                    String[] assetTagNames = new String[0];
178    
179                    try {
180                            assetTagNames = AssetTagLocalServiceUtil.getTagNames(
181                                    JournalArticle.class.getName(), article.getResourcePrimKey());
182                    }
183                    catch (SystemException se) {
184                    }
185    
186                    JournalUtil.addReservedEl(
187                            rootElement, tokens,
188                            JournalStructureConstants.RESERVED_ARTICLE_ASSET_TAG_NAMES,
189                            StringUtil.merge(assetTagNames));
190    
191                    JournalUtil.addReservedEl(
192                            rootElement, tokens,
193                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_ID,
194                            String.valueOf(article.getUserId()));
195    
196                    String userName = StringPool.BLANK;
197                    String userEmailAddress = StringPool.BLANK;
198                    String userComments = StringPool.BLANK;
199                    String userJobTitle = StringPool.BLANK;
200    
201                    User user = null;
202    
203                    try {
204                            user = UserLocalServiceUtil.getUserById(article.getUserId());
205    
206                            userName = user.getFullName();
207                            userEmailAddress = user.getEmailAddress();
208                            userComments = user.getComments();
209                            userJobTitle = user.getJobTitle();
210                    }
211                    catch (PortalException pe) {
212                    }
213                    catch (SystemException se) {
214                    }
215    
216                    JournalUtil.addReservedEl(
217                            rootElement, tokens,
218                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_NAME, userName);
219    
220                    JournalUtil.addReservedEl(
221                            rootElement, tokens,
222                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_EMAIL_ADDRESS,
223                            userEmailAddress);
224    
225                    JournalUtil.addReservedEl(
226                            rootElement, tokens,
227                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_COMMENTS,
228                            userComments);
229    
230                    JournalUtil.addReservedEl(
231                            rootElement, tokens,
232                            JournalStructureConstants.RESERVED_ARTICLE_AUTHOR_JOB_TITLE,
233                            userJobTitle);
234            }
235    
236            public static void addRecentArticle(
237                    PortletRequest portletRequest, JournalArticle article) {
238    
239                    if (article != null) {
240                            Stack<JournalArticle> stack = getRecentArticles(portletRequest);
241    
242                            stack.push(article);
243                    }
244            }
245    
246            public static void addRecentStructure(
247                    PortletRequest portletRequest, JournalStructure structure) {
248    
249                    if (structure != null) {
250                            Stack<JournalStructure> stack = getRecentStructures(portletRequest);
251    
252                            stack.push(structure);
253                    }
254            }
255    
256            public static void addRecentTemplate(
257                    PortletRequest portletRequest, JournalTemplate template) {
258    
259                    if (template != null) {
260                            Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
261    
262                            stack.push(template);
263                    }
264            }
265    
266            public static void addReservedEl(
267                    Element rootElement, Map<String, String> tokens, String name,
268                    Date value) {
269    
270                    addReservedEl(rootElement, tokens, name, Time.getRFC822(value));
271            }
272    
273            public static void addReservedEl(
274                    Element rootElement, Map<String, String> tokens, String name,
275                    double value) {
276    
277                    addReservedEl(rootElement, tokens, name, String.valueOf(value));
278            }
279    
280            public static void addReservedEl(
281                    Element rootElement, Map<String, String> tokens, String name,
282                    String value) {
283    
284                    // XML
285    
286                    if (rootElement != null) {
287                            Element dynamicElementElement = SAXReaderUtil.createElement(
288                                    "dynamic-element");
289    
290                            Attribute nameAttribute = SAXReaderUtil.createAttribute(
291                                    dynamicElementElement, "name", name);
292    
293                            dynamicElementElement.add(nameAttribute);
294    
295                            Attribute typeAttribute = SAXReaderUtil.createAttribute(
296                                    dynamicElementElement, "type", "text");
297    
298                            dynamicElementElement.add(typeAttribute);
299    
300                            Element dynamicContentElement = SAXReaderUtil.createElement(
301                                    "dynamic-content");
302    
303                            //dynamicContentElement.setText("<![CDATA[" + value + "]]>");
304                            dynamicContentElement.setText(value);
305    
306                            dynamicElementElement.add(dynamicContentElement);
307    
308                            rootElement.add(dynamicElementElement);
309                    }
310    
311                    // Tokens
312    
313                    tokens.put(
314                            StringUtil.replace(name, CharPool.DASH, CharPool.UNDERLINE), value);
315            }
316    
317            public static String formatVM(String vm) {
318                    return vm;
319            }
320    
321            public static OrderByComparator getArticleOrderByComparator(
322                    String orderByCol, String orderByType) {
323    
324                    boolean orderByAsc = false;
325    
326                    if (orderByType.equals("asc")) {
327                            orderByAsc = true;
328                    }
329    
330                    OrderByComparator orderByComparator = null;
331    
332                    if (orderByCol.equals("create-date")) {
333                            orderByComparator = new ArticleCreateDateComparator(orderByAsc);
334                    }
335                    else if (orderByCol.equals("display-date")) {
336                            orderByComparator = new ArticleDisplayDateComparator(orderByAsc);
337                    }
338                    else if (orderByCol.equals("id")) {
339                            orderByComparator = new ArticleIDComparator(orderByAsc);
340                    }
341                    else if (orderByCol.equals("modified-date")) {
342                            orderByComparator = new ArticleModifiedDateComparator(orderByAsc);
343                    }
344                    else if (orderByCol.equals("review-date")) {
345                            orderByComparator = new ArticleReviewDateComparator(orderByAsc);
346                    }
347                    else if (orderByCol.equals("title")) {
348                            orderByComparator = new ArticleTitleComparator(orderByAsc);
349                    }
350                    else if (orderByCol.equals("version")) {
351                            orderByComparator = new ArticleVersionComparator(orderByAsc);
352                    }
353    
354                    return orderByComparator;
355            }
356    
357            public static Tuple getArticles(Hits hits)
358                    throws PortalException, SystemException {
359    
360                    List<JournalArticle> articles = new ArrayList<JournalArticle>();
361                    boolean corruptIndex = false;
362    
363                    List<com.liferay.portal.kernel.search.Document> documents =
364                            hits.toList();
365    
366                    for (com.liferay.portal.kernel.search.Document document : documents) {
367                            long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID));
368                            String articleId = document.get("articleId");
369    
370                            try {
371                                    JournalArticle article =
372                                            JournalArticleLocalServiceUtil.getArticle(
373                                                    groupId, articleId);
374    
375                                    articles.add(article);
376                            }
377                            catch (NoSuchArticleException nsae) {
378                                    corruptIndex = true;
379    
380                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
381                                            JournalArticle.class);
382    
383                                    long companyId = GetterUtil.getLong(
384                                            document.get(Field.COMPANY_ID));
385    
386                                    indexer.delete(companyId, document.getUID());
387                            }
388                    }
389    
390                    return new Tuple(articles, corruptIndex);
391            }
392    
393            public static String getEmailArticleAddedBody(
394                    PortletPreferences preferences) {
395    
396                    String emailArticleAddedBody = preferences.getValue(
397                            "emailArticleAddedBody", StringPool.BLANK);
398    
399                    if (Validator.isNotNull(emailArticleAddedBody)) {
400                            return emailArticleAddedBody;
401                    }
402                    else {
403                            return ContentUtil.get(
404                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_BODY));
405                    }
406            }
407    
408            public static boolean getEmailArticleAddedEnabled(
409                    PortletPreferences preferences) {
410    
411                    String emailArticleAddedEnabled = preferences.getValue(
412                            "emailArticleAddedEnabled", StringPool.BLANK);
413    
414                    if (Validator.isNotNull(emailArticleAddedEnabled)) {
415                            return GetterUtil.getBoolean(emailArticleAddedEnabled);
416                    }
417                    else {
418                            return GetterUtil.getBoolean(
419                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_ENABLED));
420                    }
421            }
422    
423            public static String getEmailArticleAddedSubject(
424                    PortletPreferences preferences) {
425    
426                    String emailArticleAddedSubject = preferences.getValue(
427                            "emailArticleAddedSubject", StringPool.BLANK);
428    
429                    if (Validator.isNotNull(emailArticleAddedSubject)) {
430                            return emailArticleAddedSubject;
431                    }
432                    else {
433                            return ContentUtil.get(
434                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_SUBJECT));
435                    }
436            }
437    
438            public static String getEmailArticleApprovalDeniedBody(
439                    PortletPreferences preferences) {
440    
441                    String emailArticleApprovalDeniedBody = preferences.getValue(
442                            "emailArticleApprovalDeniedBody", StringPool.BLANK);
443    
444                    if (Validator.isNotNull(emailArticleApprovalDeniedBody)) {
445                            return emailArticleApprovalDeniedBody;
446                    }
447                    else {
448                            return ContentUtil.get(
449                                    PropsUtil.get(
450                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_BODY));
451                    }
452            }
453    
454            public static boolean getEmailArticleApprovalDeniedEnabled(
455                    PortletPreferences preferences) {
456    
457                    String emailArticleApprovalDeniedEnabled = preferences.getValue(
458                            "emailArticleApprovalDeniedEnabled", StringPool.BLANK);
459    
460                    if (Validator.isNotNull(emailArticleApprovalDeniedEnabled)) {
461                            return GetterUtil.getBoolean(emailArticleApprovalDeniedEnabled);
462                    }
463                    else {
464                            return GetterUtil.getBoolean(
465                                    PropsUtil.get(
466                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_ENABLED));
467                    }
468            }
469    
470            public static String getEmailArticleApprovalDeniedSubject(
471                    PortletPreferences preferences) {
472    
473                    String emailArticleApprovalDeniedSubject = preferences.getValue(
474                            "emailArticleApprovalDeniedSubject", StringPool.BLANK);
475    
476                    if (Validator.isNotNull(emailArticleApprovalDeniedSubject)) {
477                            return emailArticleApprovalDeniedSubject;
478                    }
479                    else {
480                            return ContentUtil.get(
481                                    PropsUtil.get(
482                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_SUBJECT));
483                    }
484            }
485    
486            public static String getEmailArticleApprovalGrantedBody(
487                    PortletPreferences preferences) {
488    
489                    String emailArticleApprovalGrantedBody = preferences.getValue(
490                            "emailArticleApprovalGrantedBody", StringPool.BLANK);
491    
492                    if (Validator.isNotNull(emailArticleApprovalGrantedBody)) {
493                            return emailArticleApprovalGrantedBody;
494                    }
495                    else {
496                            return ContentUtil.get(
497                                    PropsUtil.get(
498                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_BODY));
499                    }
500            }
501    
502            public static boolean getEmailArticleApprovalGrantedEnabled(
503                    PortletPreferences preferences) {
504    
505                    String emailArticleApprovalGrantedEnabled = preferences.getValue(
506                            "emailArticleApprovalGrantedEnabled", StringPool.BLANK);
507    
508                    if (Validator.isNotNull(emailArticleApprovalGrantedEnabled)) {
509                            return GetterUtil.getBoolean(emailArticleApprovalGrantedEnabled);
510                    }
511                    else {
512                            return GetterUtil.getBoolean(
513                                    PropsUtil.get(
514                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_ENABLED));
515                    }
516            }
517    
518            public static String getEmailArticleApprovalGrantedSubject(
519                    PortletPreferences preferences) {
520    
521                    String emailArticleApprovalGrantedSubject = preferences.getValue(
522                            "emailArticleApprovalGrantedSubject", StringPool.BLANK);
523    
524                    if (Validator.isNotNull(emailArticleApprovalGrantedSubject)) {
525                            return emailArticleApprovalGrantedSubject;
526                    }
527                    else {
528                            return ContentUtil.get(
529                                    PropsUtil.get(
530                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_SUBJECT));
531                    }
532            }
533    
534            public static String getEmailArticleApprovalRequestedBody(
535                    PortletPreferences preferences) {
536    
537                    String emailArticleApprovalRequestedBody = preferences.getValue(
538                            "emailArticleApprovalRequestedBody", StringPool.BLANK);
539    
540                    if (Validator.isNotNull(emailArticleApprovalRequestedBody)) {
541                            return emailArticleApprovalRequestedBody;
542                    }
543                    else {
544                            return ContentUtil.get(
545                                    PropsUtil.get(
546                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_BODY));
547                    }
548            }
549    
550            public static boolean getEmailArticleApprovalRequestedEnabled(
551                    PortletPreferences preferences) {
552    
553                    String emailArticleApprovalRequestedEnabled = preferences.getValue(
554                            "emailArticleApprovalRequestedEnabled", StringPool.BLANK);
555    
556                    if (Validator.isNotNull(emailArticleApprovalRequestedEnabled)) {
557                            return GetterUtil.getBoolean(emailArticleApprovalRequestedEnabled);
558                    }
559                    else {
560                            return GetterUtil.getBoolean(
561                                    PropsUtil.get(
562                                            PropsKeys.
563                                                    JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_ENABLED));
564                    }
565            }
566    
567            public static String getEmailArticleApprovalRequestedSubject(
568                    PortletPreferences preferences) {
569    
570                    String emailArticleApprovalRequestedSubject = preferences.getValue(
571                            "emailArticleApprovalRequestedSubject", StringPool.BLANK);
572    
573                    if (Validator.isNotNull(emailArticleApprovalRequestedSubject)) {
574                            return emailArticleApprovalRequestedSubject;
575                    }
576                    else {
577                            return ContentUtil.get(
578                                    PropsUtil.get(
579                                            PropsKeys.
580                                                    JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_SUBJECT));
581                    }
582            }
583    
584            public static String getEmailArticleReviewBody(
585                    PortletPreferences preferences) {
586    
587                    String emailArticleReviewBody = preferences.getValue(
588                            "emailArticleReviewBody", StringPool.BLANK);
589    
590                    if (Validator.isNotNull(emailArticleReviewBody)) {
591                            return emailArticleReviewBody;
592                    }
593                    else {
594                            return ContentUtil.get(
595                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_BODY));
596                    }
597            }
598    
599            public static boolean getEmailArticleReviewEnabled(
600                    PortletPreferences preferences) {
601    
602                    String emailArticleReviewEnabled = preferences.getValue(
603                            "emailArticleReviewEnabled", StringPool.BLANK);
604    
605                    if (Validator.isNotNull(emailArticleReviewEnabled)) {
606                            return GetterUtil.getBoolean(emailArticleReviewEnabled);
607                    }
608                    else {
609                            return GetterUtil.getBoolean(
610                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_ENABLED));
611                    }
612            }
613    
614            public static String getEmailArticleReviewSubject(
615                    PortletPreferences preferences) {
616    
617                    String emailArticleReviewSubject = preferences.getValue(
618                            "emailArticleReviewSubject", StringPool.BLANK);
619    
620                    if (Validator.isNotNull(emailArticleReviewSubject)) {
621                            return emailArticleReviewSubject;
622                    }
623                    else {
624                            return ContentUtil.get(
625                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_SUBJECT));
626                    }
627            }
628    
629            public static String getEmailArticleUpdatedBody(
630                    PortletPreferences preferences) {
631    
632                    String emailArticleUpdatedBody = preferences.getValue(
633                            "emailArticleUpdatedBody", StringPool.BLANK);
634    
635                    if (Validator.isNotNull(emailArticleUpdatedBody)) {
636                            return emailArticleUpdatedBody;
637                    }
638                    else {
639                            return ContentUtil.get(
640                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_BODY));
641                    }
642            }
643    
644            public static boolean getEmailArticleUpdatedEnabled(
645                    PortletPreferences preferences) {
646    
647                    String emailArticleUpdatedEnabled = preferences.getValue(
648                            "emailArticleUpdatedEnabled", StringPool.BLANK);
649    
650                    if (Validator.isNotNull(emailArticleUpdatedEnabled)) {
651                            return GetterUtil.getBoolean(emailArticleUpdatedEnabled);
652                    }
653                    else {
654                            return GetterUtil.getBoolean(
655                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_ENABLED));
656                    }
657            }
658    
659            public static String getEmailArticleUpdatedSubject(
660                    PortletPreferences preferences) {
661    
662                    String emailArticleUpdatedSubject = preferences.getValue(
663                            "emailArticleUpdatedSubject", StringPool.BLANK);
664    
665                    if (Validator.isNotNull(emailArticleUpdatedSubject)) {
666                            return emailArticleUpdatedSubject;
667                    }
668                    else {
669                            return ContentUtil.get(
670                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_SUBJECT));
671                    }
672            }
673    
674            public static String getEmailFromAddress(
675                            PortletPreferences preferences, long companyId)
676                    throws SystemException {
677    
678                    return PortalUtil.getEmailFromAddress(
679                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_ADDRESS);
680            }
681    
682            public static String getEmailFromName(
683                            PortletPreferences preferences, long companyId)
684                    throws SystemException {
685    
686                    return PortalUtil.getEmailFromName(
687                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_NAME);
688            }
689    
690            public static Stack<JournalArticle> getRecentArticles(
691                    PortletRequest portletRequest) {
692    
693                    PortletSession portletSession = portletRequest.getPortletSession();
694    
695                    Stack<JournalArticle> recentArticles =
696                            (Stack<JournalArticle>)portletSession.getAttribute(
697                                    WebKeys.JOURNAL_RECENT_ARTICLES);
698    
699                    if (recentArticles == null) {
700                            recentArticles = new FiniteUniqueStack<JournalArticle>(
701                                    MAX_STACK_SIZE);
702    
703                            portletSession.setAttribute(
704                                    WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
705                    }
706    
707                    return recentArticles;
708            }
709    
710            public static Stack<JournalStructure> getRecentStructures(
711                    PortletRequest portletRequest) {
712    
713                    PortletSession portletSession = portletRequest.getPortletSession();
714    
715                    Stack<JournalStructure> recentStructures =
716                            (Stack<JournalStructure>)portletSession.getAttribute(
717                                    WebKeys.JOURNAL_RECENT_STRUCTURES);
718    
719                    if (recentStructures == null) {
720                            recentStructures = new FiniteUniqueStack<JournalStructure>(
721                                    MAX_STACK_SIZE);
722    
723                            portletSession.setAttribute(
724                                    WebKeys.JOURNAL_RECENT_STRUCTURES, recentStructures);
725                    }
726    
727                    return recentStructures;
728            }
729    
730            public static Stack<JournalTemplate> getRecentTemplates(
731                    PortletRequest portletRequest) {
732    
733                    PortletSession portletSession = portletRequest.getPortletSession();
734    
735                    Stack<JournalTemplate> recentTemplates =
736                            (Stack<JournalTemplate>)portletSession.getAttribute(
737                                    WebKeys.JOURNAL_RECENT_TEMPLATES);
738    
739                    if (recentTemplates == null) {
740                            recentTemplates = new FiniteUniqueStack<JournalTemplate>(
741                                    MAX_STACK_SIZE);
742    
743                            portletSession.setAttribute(
744                                    WebKeys.JOURNAL_RECENT_TEMPLATES, recentTemplates);
745                    }
746    
747                    return recentTemplates;
748            }
749    
750            public static String getTemplateScript(
751                    JournalTemplate template, Map<String, String> tokens, String languageId,
752                    boolean transform) {
753    
754                    String script = template.getXsl();
755    
756                    if (transform) {
757    
758                            // Listeners
759    
760                            String[] listeners = PropsUtil.getArray(
761                                    PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
762    
763                            for (int i = 0; i < listeners.length; i++) {
764                                    TransformerListener listener = null;
765    
766                                    try {
767                                            listener = (TransformerListener)Class.forName(
768                                                    listeners[i]).newInstance();
769    
770                                            listener.setTemplateDriven(true);
771                                            listener.setLanguageId(languageId);
772                                            listener.setTokens(tokens);
773                                    }
774                                    catch (Exception e) {
775                                            _log.error(e, e);
776                                    }
777    
778                                    // Modify transform script
779    
780                                    if (listener != null) {
781                                            script = listener.onScript(script);
782                                    }
783                            }
784                    }
785    
786                    return script;
787            }
788    
789            public static String getTemplateScript(
790                            long groupId, String templateId, Map<String, String> tokens,
791                            String languageId)
792                    throws PortalException, SystemException {
793    
794                    return getTemplateScript(groupId, templateId, tokens, languageId, true);
795            }
796    
797            public static String getTemplateScript(
798                            long groupId, String templateId, Map<String, String> tokens,
799                            String languageId, boolean transform)
800                    throws PortalException, SystemException {
801    
802                    JournalTemplate template = JournalTemplateLocalServiceUtil.getTemplate(
803                            groupId, templateId);
804    
805                    return getTemplateScript(template, tokens, languageId, transform);
806            }
807    
808            public static Map<String, String> getTokens(
809                            long groupId, ThemeDisplay themeDisplay)
810                    throws PortalException, SystemException {
811    
812                    return getTokens(groupId, themeDisplay, null);
813            }
814    
815            public static Map<String, String> getTokens(
816                            long groupId, ThemeDisplay themeDisplay, String xmlRequest)
817                    throws PortalException, SystemException {
818    
819                    Map<String, String> tokens = new HashMap<String, String>();
820    
821                    if (themeDisplay != null) {
822                            _populateTokens(tokens, groupId, themeDisplay);
823                    }
824                    else if (Validator.isNotNull(xmlRequest)) {
825                            try {
826                                    _populateTokens(tokens, groupId, xmlRequest);
827                            }
828                            catch (Exception e) {
829                                    if (_log.isWarnEnabled()) {
830                                            _log.warn(e, e);
831                                    }
832                            }
833                    }
834    
835                    return tokens;
836            }
837    
838            public static String getUrlTitle(long id, String title) {
839                    if (title == null) {
840                            return String.valueOf(id);
841                    }
842    
843                    title = title.trim().toLowerCase();
844    
845                    if (Validator.isNull(title) || Validator.isNumber(title) ||
846                            title.equals("rss")) {
847    
848                            title = String.valueOf(id);
849                    }
850                    else {
851                            title = FriendlyURLNormalizerUtil.normalize(
852                                    title, _URL_TITLE_REPLACE_CHARS);
853                    }
854    
855                    return ModelHintsUtil.trimString(
856                            JournalArticle.class.getName(), "urlTitle", title);
857            }
858    
859            public static String mergeArticleContent(
860                    String curContent, String newContent, boolean removeNullElements) {
861    
862                    try {
863                            Document curDocument = SAXReaderUtil.read(curContent);
864                            Document newDocument = SAXReaderUtil.read(newContent);
865    
866                            Element curRootElement = curDocument.getRootElement();
867                            Element newRootElement = newDocument.getRootElement();
868    
869                            curRootElement.addAttribute(
870                                    "default-locale",
871                                    newRootElement.attributeValue("default-locale"));
872                            curRootElement.addAttribute(
873                                    "available-locales",
874                                    newRootElement.attributeValue("available-locales"));
875    
876                            _mergeArticleContentUpdate(
877                                    curDocument, newRootElement,
878                                    LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
879    
880                            if (removeNullElements) {
881                                    _mergeArticleContentDelete(curRootElement, newDocument);
882                            }
883    
884                            curContent = DDMXMLUtil.formatXML(curDocument);
885                    }
886                    catch (Exception e) {
887                            _log.error(e, e);
888                    }
889    
890                    return curContent;
891            }
892    
893            public static String processXMLAttributes(String xsd)
894                    throws PortalException {
895    
896                    try {
897                            Document document = SAXReaderUtil.read(xsd);
898    
899                            Element rootElement = document.getRootElement();
900    
901                            List<Element> elements = new ArrayList<Element>();
902    
903                            elements.addAll(rootElement.elements());
904    
905                            _decodeXMLAttributes(elements);
906    
907                            return document.asXML();
908                    }
909                    catch (Exception e) {
910                            throw new StructureXsdException();
911                    }
912            }
913    
914            public static void removeArticleLocale(Element element, String languageId)
915                    throws PortalException, SystemException {
916    
917                    for (Element dynamicElementElement :
918                                    element.elements("dynamic-element")) {
919    
920                            for (Element dynamicContentElement :
921                                            dynamicElementElement.elements("dynamic-content")) {
922    
923                                    String curLanguageId = GetterUtil.getString(
924                                            dynamicContentElement.attributeValue("language-id"));
925    
926                                    if (curLanguageId.equals(languageId)) {
927                                            long id = GetterUtil.getLong(
928                                                    dynamicContentElement.attributeValue("id"));
929    
930                                            if (id > 0) {
931                                                    ImageLocalServiceUtil.deleteImage(id);
932                                            }
933    
934                                            dynamicContentElement.detach();
935                                    }
936                            }
937    
938                            removeArticleLocale(dynamicElementElement, languageId);
939                    }
940            }
941    
942            public static String removeArticleLocale(
943                    String content, String languageId) {
944    
945                    try {
946                            Document document = SAXReaderUtil.read(content);
947    
948                            Element rootElement = document.getRootElement();
949    
950                            String availableLocales = rootElement.attributeValue(
951                                    "available-locales");
952    
953                            if (availableLocales == null) {
954                                    return content;
955                            }
956    
957                            availableLocales = StringUtil.remove(availableLocales, languageId);
958    
959                            if (availableLocales.endsWith(",")) {
960                                    availableLocales = availableLocales.substring(
961                                            0, availableLocales.length() - 1);
962                            }
963    
964                            rootElement.addAttribute("available-locales", availableLocales);
965    
966                            removeArticleLocale(rootElement, languageId);
967    
968                            content = DDMXMLUtil.formatXML(document);
969                    }
970                    catch (Exception e) {
971                            _log.error(e, e);
972                    }
973    
974                    return content;
975            }
976    
977            public static String removeOldContent(String content, String xsd) {
978                    try {
979                            Document contentDoc = SAXReaderUtil.read(content);
980                            Document xsdDoc = SAXReaderUtil.read(xsd);
981    
982                            Element contentRoot = contentDoc.getRootElement();
983    
984                            Stack<String> path = new Stack<String>();
985    
986                            path.push(contentRoot.getName());
987    
988                            _removeOldContent(path, contentRoot, xsdDoc);
989    
990                            content = DDMXMLUtil.formatXML(contentDoc);
991                    }
992                    catch (Exception e) {
993                            _log.error(e, e);
994                    }
995    
996                    return content;
997            }
998    
999            public static void removeRecentArticle(
1000                    PortletRequest portletRequest, String articleId) {
1001    
1002                    removeRecentArticle(portletRequest, articleId, 0);
1003            }
1004    
1005            public static void removeRecentArticle(
1006                    PortletRequest portletRequest, String articleId, double version) {
1007    
1008                    Stack<JournalArticle> stack = getRecentArticles(portletRequest);
1009    
1010                    Iterator<JournalArticle> itr = stack.iterator();
1011    
1012                    while (itr.hasNext()) {
1013                            JournalArticle journalArticle = itr.next();
1014    
1015                            if (journalArticle.getArticleId().equals(articleId) &&
1016                                    ((journalArticle.getVersion() == version) ||
1017                                     (version == 0))) {
1018    
1019                                    itr.remove();
1020                            }
1021                    }
1022            }
1023    
1024            public static void removeRecentStructure(
1025                    PortletRequest portletRequest, String structureId) {
1026    
1027                    Stack<JournalStructure> stack = getRecentStructures(portletRequest);
1028    
1029                    Iterator<JournalStructure> itr = stack.iterator();
1030    
1031                    while (itr.hasNext()) {
1032                            JournalStructure journalStructure = itr.next();
1033    
1034                            if (journalStructure.getStructureId().equals(structureId)) {
1035                                    itr.remove();
1036    
1037                                    break;
1038                            }
1039                    }
1040            }
1041    
1042            public static void removeRecentTemplate(
1043                    PortletRequest portletRequest, String templateId) {
1044    
1045                    Stack<JournalTemplate> stack = getRecentTemplates(portletRequest);
1046    
1047                    Iterator<JournalTemplate> itr = stack.iterator();
1048    
1049                    while (itr.hasNext()) {
1050                            JournalTemplate journalTemplate = itr.next();
1051    
1052                            if (journalTemplate.getTemplateId().equals(templateId)) {
1053                                    itr.remove();
1054    
1055                                    break;
1056                            }
1057                    }
1058            }
1059    
1060            public static String transform(
1061                            ThemeDisplay themeDisplay, Map<String, String> tokens,
1062                            String viewMode, String languageId, String xml, String script,
1063                            String langType)
1064                    throws Exception {
1065    
1066                    return _transformer.transform(
1067                            themeDisplay, tokens, viewMode, languageId, xml, script, langType);
1068            }
1069    
1070            private static void _addElementOptions(
1071                    Element curContentElement, Element newContentElement) {
1072    
1073                    List<Element> newElementOptions = newContentElement.elements("option");
1074    
1075                    for (Element newElementOption : newElementOptions) {
1076                            Element curElementOption = SAXReaderUtil.createElement("option");
1077    
1078                            curElementOption.addCDATA(newElementOption.getText());
1079    
1080                            curContentElement.add(curElementOption);
1081                    }
1082            }
1083    
1084            private static void _decodeXMLAttributes(List<Element> elements) {
1085                    for (Element element : elements) {
1086                            String elName = element.attributeValue("name", StringPool.BLANK);
1087                            String elType = element.attributeValue("type", StringPool.BLANK);
1088    
1089                            if (Validator.isNotNull(elName)) {
1090                                    elName = JS.decodeURIComponent(elName);
1091    
1092                                    element.addAttribute("name", elName);
1093                            }
1094    
1095                            if (Validator.isNotNull(elType)) {
1096                                    elType = JS.decodeURIComponent(elType);
1097    
1098                                    element.addAttribute("type", elType);
1099                            }
1100    
1101                            _decodeXMLAttributes(element.elements());
1102                    }
1103            }
1104    
1105            private static Element _getElementByInstanceId(
1106                    Document document, String instanceId) {
1107    
1108                    XPath xPathSelector = SAXReaderUtil.createXPath(
1109                            "//dynamic-element[@instance-id='" + instanceId + "']");
1110    
1111                    List<Node> nodes = xPathSelector.selectNodes(document);
1112    
1113                    if (nodes.size() == 1) {
1114                            return (Element)nodes.get(0);
1115                    }
1116                    else {
1117                            return null;
1118                    }
1119            }
1120    
1121            private static void _mergeArticleContentDelete(
1122                            Element curParentElement, Document newDocument)
1123                    throws Exception {
1124    
1125                    List<Element> curElements = curParentElement.elements(
1126                            "dynamic-element");
1127    
1128                    for (int i = 0; i < curElements.size(); i++) {
1129                            Element curElement = curElements.get(i);
1130    
1131                            _mergeArticleContentDelete(curElement, newDocument);
1132    
1133                            String instanceId = curElement.attributeValue("instance-id");
1134    
1135                            Element newElement = _getElementByInstanceId(
1136                                    newDocument, instanceId);
1137    
1138                            if (newElement == null) {
1139                                    curElement.detach();
1140                            }
1141                    }
1142            }
1143    
1144            private static void _mergeArticleContentUpdate(
1145                            Document curDocument, Element newParentElement, Element newElement,
1146                            int pos, String defaultLocale)
1147                    throws Exception {
1148    
1149                    _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1150    
1151                    String instanceId = newElement.attributeValue("instance-id");
1152    
1153                    Element curElement = _getElementByInstanceId(curDocument, instanceId);
1154    
1155                    if (curElement != null) {
1156                            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1157                    }
1158                    else {
1159                            String parentInstanceId = newParentElement.attributeValue(
1160                                    "instance-id");
1161    
1162                            if (Validator.isNull(parentInstanceId)) {
1163                                    Element curRoot = curDocument.getRootElement();
1164    
1165                                    List<Element> curRootElements = curRoot.elements();
1166    
1167                                    curRootElements.add(pos, newElement.createCopy());
1168                            }
1169                            else {
1170                                    Element curParentElement = _getElementByInstanceId(
1171                                            curDocument, parentInstanceId);
1172    
1173                                    if (curParentElement != null) {
1174                                            List<Element> curParentElements =
1175                                                    curParentElement.elements();
1176    
1177                                            curParentElements.add(pos, newElement.createCopy());
1178                                    }
1179                            }
1180                    }
1181            }
1182    
1183            private static void _mergeArticleContentUpdate(
1184                            Document curDocument, Element newParentElement,
1185                            String defaultLocale)
1186                    throws Exception {
1187    
1188                    List<Element> newElements = newParentElement.elements(
1189                            "dynamic-element");
1190    
1191                    for (int i = 0; i < newElements.size(); i++) {
1192                            Element newElement = newElements.get(i);
1193    
1194                            _mergeArticleContentUpdate(
1195                                    curDocument, newParentElement, newElement, i, defaultLocale);
1196                    }
1197            }
1198    
1199            private static void _mergeArticleContentUpdate(
1200                    Element curElement, Element newElement, String defaultLocale) {
1201    
1202                    Attribute curTypeAttribute = curElement.attribute("type");
1203                    Attribute newTypeAttribute = newElement.attribute("type");
1204    
1205                    curTypeAttribute.setValue(newTypeAttribute.getValue());
1206    
1207                    Attribute curIndexTypeAttribute = curElement.attribute("index-type");
1208                    Attribute newIndexTypeAttribute = newElement.attribute("index-type");
1209    
1210                    if (newIndexTypeAttribute != null) {
1211                            if (curIndexTypeAttribute == null) {
1212                                    curElement.addAttribute(
1213                                            "index-type", newIndexTypeAttribute.getValue());
1214                            }
1215                            else {
1216                                    curIndexTypeAttribute.setValue(
1217                                            newIndexTypeAttribute.getValue());
1218                            }
1219                    }
1220    
1221                    Element newContentElement = newElement.elements(
1222                            "dynamic-content").get(0);
1223    
1224                    String newLanguageId = newContentElement.attributeValue("language-id");
1225                    String newValue = newContentElement.getText();
1226    
1227                    String indexType = newElement.attributeValue("index-type");
1228    
1229                    if (Validator.isNotNull(indexType)) {
1230                            curElement.addAttribute("index-type", indexType);
1231                    }
1232    
1233                    List<Element> curContentElements = curElement.elements(
1234                            "dynamic-content");
1235    
1236                    if (Validator.isNull(newLanguageId)) {
1237                            for (Element curContentElement : curContentElements) {
1238                                    curContentElement.detach();
1239                            }
1240    
1241                            Element curContentElement = SAXReaderUtil.createElement(
1242                                    "dynamic-content");
1243    
1244                            if (newContentElement.element("option") != null) {
1245                                    _addElementOptions(curContentElement, newContentElement);
1246                            }
1247                            else {
1248                                    curContentElement.addCDATA(newValue);
1249                            }
1250    
1251                            curElement.add(curContentElement);
1252                    }
1253                    else {
1254                            boolean alreadyExists = false;
1255    
1256                            for (Element curContentElement : curContentElements) {
1257                                    String curLanguageId = curContentElement.attributeValue(
1258                                            "language-id");
1259    
1260                                    if (newLanguageId.equals(curLanguageId)) {
1261                                            alreadyExists = true;
1262    
1263                                            curContentElement.clearContent();
1264    
1265                                            if (newContentElement.element("option") != null) {
1266                                                    _addElementOptions(
1267                                                            curContentElement, newContentElement);
1268                                            }
1269                                            else {
1270                                                    curContentElement.addCDATA(newValue);
1271                                            }
1272    
1273                                            break;
1274                                    }
1275                            }
1276    
1277                            if (!alreadyExists) {
1278                                    Element curContentElement = curContentElements.get(0);
1279    
1280                                    String curLanguageId = curContentElement.attributeValue(
1281                                            "language-id");
1282    
1283                                    if (Validator.isNull(curLanguageId)) {
1284                                            if (newLanguageId.equals(defaultLocale)) {
1285                                                    curContentElement.clearContent();
1286    
1287                                                    if (newContentElement.element("option") != null) {
1288                                                            _addElementOptions(
1289                                                                    curContentElement, newContentElement);
1290                                                    }
1291                                                    else {
1292                                                            curContentElement.addCDATA(newValue);
1293                                                    }
1294                                            }
1295                                            else {
1296                                                    curElement.add(newContentElement.createCopy());
1297                                            }
1298    
1299                                            curContentElement.addAttribute(
1300                                                    "language-id", defaultLocale);
1301                                    }
1302                                    else {
1303                                            curElement.add(newContentElement.createCopy());
1304                                    }
1305                            }
1306                    }
1307            }
1308    
1309            private static void _populateCustomTokens(Map<String, String> tokens) {
1310                    if (_customTokens == null) {
1311                            synchronized (JournalUtil.class) {
1312                                    _customTokens = new HashMap<String, String>();
1313    
1314                                    for (String customToken :
1315                                                    PropsValues.JOURNAL_ARTICLE_CUSTOM_TOKENS) {
1316    
1317                                            String value = PropsUtil.get(
1318                                                    PropsKeys.JOURNAL_ARTICLE_CUSTOM_TOKEN_VALUE,
1319                                                    new Filter(customToken));
1320    
1321                                            _customTokens.put(customToken, value);
1322                                    }
1323                            }
1324                    }
1325    
1326                    if (!_customTokens.isEmpty()) {
1327                            tokens.putAll(_customTokens);
1328                    }
1329            }
1330    
1331            private static void _populateTokens(
1332                            Map<String, String> tokens, long groupId, String xmlRequest)
1333                    throws Exception {
1334    
1335                    Document requestDocument = SAXReaderUtil.read(xmlRequest);
1336    
1337                    Element rootElement = requestDocument.getRootElement();
1338    
1339                    Element themeDisplayElement = rootElement.element("theme-display");
1340    
1341                    Layout layout = LayoutLocalServiceUtil.getLayout(
1342                            GetterUtil.getLong(themeDisplayElement.elementText("plid")));
1343    
1344                    Group group = layout.getGroup();
1345    
1346                    LayoutSet layoutSet = layout.getLayoutSet();
1347    
1348                    String friendlyUrlCurrent = null;
1349    
1350                    if (layout.isPublicLayout()) {
1351                            friendlyUrlCurrent = themeDisplayElement.elementText(
1352                                    "path-friendly-url-public");
1353                    }
1354                    else if (group.isUserGroup()) {
1355                            friendlyUrlCurrent = themeDisplayElement.elementText(
1356                                    "path-friendly-url-private-user");
1357                    }
1358                    else {
1359                            friendlyUrlCurrent = themeDisplayElement.elementText(
1360                                    "path-friendly-url-private-group");
1361                    }
1362    
1363                    String layoutSetFriendlyUrl = themeDisplayElement.elementText(
1364                            "i18n-path");
1365    
1366                    String virtualHostname = layoutSet.getVirtualHostname();
1367    
1368                    if (Validator.isNull(virtualHostname) ||
1369                            !virtualHostname.equals(
1370                                    themeDisplayElement.elementText("server-name"))) {
1371    
1372                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1373                    }
1374    
1375                    tokens.put("cdn_host", themeDisplayElement.elementText("cdn-host"));
1376                    tokens.put("company_id", themeDisplayElement.elementText("company-id"));
1377                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1378                    tokens.put(
1379                            "friendly_url_private_group",
1380                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1381                    tokens.put(
1382                            "friendly_url_private_user",
1383                            themeDisplayElement.elementText("path-friendly-url-private-user"));
1384                    tokens.put(
1385                            "friendly_url_public",
1386                            themeDisplayElement.elementText("path-friendly-url-public"));
1387                    tokens.put("group_friendly_url", group.getFriendlyURL());
1388                    tokens.put("group_id", String.valueOf(groupId));
1389                    tokens.put("image_path", themeDisplayElement.elementText("path-image"));
1390                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1391                    tokens.put("main_path", themeDisplayElement.elementText("path-main"));
1392                    tokens.put(
1393                            "portal_ctx", themeDisplayElement.elementText("path-context"));
1394                    tokens.put(
1395                            "portal_url",
1396                            HttpUtil.removeProtocol(
1397                                    themeDisplayElement.elementText("url-portal")));
1398                    tokens.put(
1399                            "protocol",
1400                            HttpUtil.getProtocol(
1401                                    themeDisplayElement.elementText("url-portal")));
1402                    tokens.put(
1403                            "root_path", themeDisplayElement.elementText("path-context"));
1404                    tokens.put(
1405                            "scope_group_id",
1406                            themeDisplayElement.elementText("scope-group-id"));
1407                    tokens.put(
1408                            "theme_image_path",
1409                            themeDisplayElement.elementText("path-theme-images"));
1410    
1411                    _populateCustomTokens(tokens);
1412    
1413                    // Deprecated tokens
1414    
1415                    tokens.put(
1416                            "friendly_url",
1417                            themeDisplayElement.elementText("path-friendly-url-public"));
1418                    tokens.put(
1419                            "friendly_url_private",
1420                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1421                    tokens.put(
1422                            "page_url",
1423                            themeDisplayElement.elementText("path-friendly-url-public"));
1424            }
1425    
1426            private static void _populateTokens(
1427                            Map<String, String> tokens, long groupId, ThemeDisplay themeDisplay)
1428                    throws PortalException, SystemException {
1429    
1430                    Layout layout = themeDisplay.getLayout();
1431    
1432                    Group group = layout.getGroup();
1433    
1434                    LayoutSet layoutSet = layout.getLayoutSet();
1435    
1436                    String friendlyUrlCurrent = null;
1437    
1438                    if (layout.isPublicLayout()) {
1439                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1440                    }
1441                    else if (group.isUserGroup()) {
1442                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1443                    }
1444                    else {
1445                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1446                    }
1447    
1448                    String layoutSetFriendlyUrl = themeDisplay.getI18nPath();
1449    
1450                    String virtualHostname = layoutSet.getVirtualHostname();
1451    
1452                    if (Validator.isNull(virtualHostname) ||
1453                            !virtualHostname.equals(themeDisplay.getServerName())) {
1454    
1455                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1456                    }
1457    
1458                    tokens.put("cdn_host", themeDisplay.getCDNHost());
1459                    tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1460                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1461                    tokens.put(
1462                            "friendly_url_private_group",
1463                            themeDisplay.getPathFriendlyURLPrivateGroup());
1464                    tokens.put(
1465                            "friendly_url_private_user",
1466                            themeDisplay.getPathFriendlyURLPrivateUser());
1467                    tokens.put(
1468                            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1469                    tokens.put("group_friendly_url", group.getFriendlyURL());
1470                    tokens.put("group_id", String.valueOf(groupId));
1471                    tokens.put("image_path", themeDisplay.getPathImage());
1472                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1473                    tokens.put("main_path", themeDisplay.getPathMain());
1474                    tokens.put("portal_ctx", themeDisplay.getPathContext());
1475                    tokens.put(
1476                            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1477                    tokens.put(
1478                            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1479                    tokens.put("root_path", themeDisplay.getPathContext());
1480                    tokens.put(
1481                            "scope_group_id", String.valueOf(themeDisplay.getScopeGroupId()));
1482                    tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1483    
1484                    _populateCustomTokens(tokens);
1485    
1486                    // Deprecated tokens
1487    
1488                    tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1489                    tokens.put(
1490                            "friendly_url_private",
1491                            themeDisplay.getPathFriendlyURLPrivateGroup());
1492                    tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1493            }
1494    
1495            private static void _removeOldContent(
1496                            Stack<String> path, Element contentElement, Document xsdDocument)
1497                    throws SystemException {
1498    
1499                    String elementPath = "";
1500    
1501                    for (int i = 0; i < path.size(); i++) {
1502                            elementPath += "/" + path.elementAt(i);
1503                    }
1504    
1505                    for (int i = 0; i < contentElement.nodeCount(); i++) {
1506                            Node contentNode = contentElement.node(i);
1507    
1508                            if (contentNode instanceof Element) {
1509                                    _removeOldContent(
1510                                            path, (Element)contentNode, xsdDocument, elementPath);
1511                            }
1512                    }
1513            }
1514    
1515            private static void _removeOldContent(
1516                            Stack<String> path, Element contentElement, Document xsdDocument,
1517                            String elementPath)
1518                    throws SystemException {
1519    
1520                    String name = contentElement.attributeValue("name");
1521    
1522                    if (Validator.isNull(name)) {
1523                            return;
1524                    }
1525    
1526                    String localPath = "dynamic-element[@name='" + name + "']";
1527    
1528                    String fullPath = elementPath + "/" + localPath;
1529    
1530                    XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1531    
1532                    List<Node> curNodes = xPathSelector.selectNodes(xsdDocument);
1533    
1534                    if (curNodes.size() == 0) {
1535                            contentElement.detach();
1536                    }
1537    
1538                    path.push(localPath);
1539    
1540                    _removeOldContent(path, contentElement, xsdDocument);
1541    
1542                    path.pop();
1543            }
1544    
1545            private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
1546                    '.', '/'
1547            };
1548    
1549            private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1550    
1551            private static Map<String, String> _customTokens;
1552            private static Transformer _transformer = new JournalTransformer();
1553    
1554    }