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