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