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