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