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