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                            if (Validator.isNull(availableLocales)) {
1162                                    updatedRootElement = updatedRootElement.addAttribute(
1163                                            "available-locales", StringPool.BLANK);
1164    
1165                                    availableLocales = updatedRootElement.attribute(
1166                                            "available-locales");
1167                            }
1168    
1169                            String defaultImportLocaleId = LocaleUtil.toLanguageId(
1170                                    defaultImportLocale);
1171    
1172                            if (!StringUtil.contains(
1173                                            availableLocales.getValue(), defaultImportLocaleId)) {
1174    
1175                                    if (Validator.isNull(availableLocales.getValue())) {
1176                                            availableLocales.setValue(defaultImportLocaleId);
1177                                    }
1178                                    else {
1179                                            StringBundler sb = new StringBundler(3);
1180    
1181                                            sb.append(availableLocales.getValue());
1182                                            sb.append(StringPool.COMMA);
1183                                            sb.append(defaultImportLocaleId);
1184    
1185                                            availableLocales.setValue(sb.toString());
1186                                    }
1187    
1188                                    _mergeArticleContentUpdate(
1189                                            curDocument, updatedRootElement,
1190                                            LocaleUtil.toLanguageId(defaultImportLocale));
1191    
1192                                    content = DDMXMLUtil.formatXML(updatedDocument);
1193                            }
1194    
1195                            Attribute defaultLocale = updatedRootElement.attribute(
1196                                    "default-locale");
1197    
1198                            if (Validator.isNull(defaultLocale)) {
1199                                    updatedRootElement = updatedRootElement.addAttribute(
1200                                            "default-locale", StringPool.BLANK);
1201    
1202                                    defaultLocale = updatedRootElement.attribute("default-locale");
1203                            }
1204    
1205                            Locale defaultContentLocale = LocaleUtil.fromLanguageId(
1206                                    defaultLocale.getValue());
1207    
1208                            if (!LocaleUtil.equals(defaultContentLocale, defaultImportLocale)) {
1209                                    defaultLocale.setValue(defaultImportLocaleId);
1210    
1211                                    content = DDMXMLUtil.formatXML(updatedDocument);
1212                            }
1213                    }
1214                    catch (Exception e) {
1215                            throw new LocaleException(
1216                                    LocaleException.TYPE_CONTENT,
1217                                    "The locale " + defaultImportLocale + " is not available");
1218                    }
1219    
1220                    return content;
1221            }
1222    
1223            public static void removeArticleLocale(Element element, String languageId)
1224                    throws PortalException, SystemException {
1225    
1226                    for (Element dynamicElementElement :
1227                                    element.elements("dynamic-element")) {
1228    
1229                            for (Element dynamicContentElement :
1230                                            dynamicElementElement.elements("dynamic-content")) {
1231    
1232                                    String curLanguageId = GetterUtil.getString(
1233                                            dynamicContentElement.attributeValue("language-id"));
1234    
1235                                    if (curLanguageId.equals(languageId)) {
1236                                            long id = GetterUtil.getLong(
1237                                                    dynamicContentElement.attributeValue("id"));
1238    
1239                                            if (id > 0) {
1240                                                    ImageLocalServiceUtil.deleteImage(id);
1241                                            }
1242    
1243                                            dynamicContentElement.detach();
1244                                    }
1245                            }
1246    
1247                            removeArticleLocale(dynamicElementElement, languageId);
1248                    }
1249            }
1250    
1251            public static String removeArticleLocale(
1252                    String content, String languageId) {
1253    
1254                    try {
1255                            Document document = SAXReaderUtil.read(content);
1256    
1257                            Element rootElement = document.getRootElement();
1258    
1259                            String availableLocales = rootElement.attributeValue(
1260                                    "available-locales");
1261    
1262                            if (availableLocales == null) {
1263                                    return content;
1264                            }
1265    
1266                            availableLocales = StringUtil.remove(availableLocales, languageId);
1267    
1268                            if (availableLocales.endsWith(",")) {
1269                                    availableLocales = availableLocales.substring(
1270                                            0, availableLocales.length() - 1);
1271                            }
1272    
1273                            rootElement.addAttribute("available-locales", availableLocales);
1274    
1275                            removeArticleLocale(rootElement, languageId);
1276    
1277                            content = DDMXMLUtil.formatXML(document);
1278                    }
1279                    catch (Exception e) {
1280                            _log.error(e, e);
1281                    }
1282    
1283                    return content;
1284            }
1285    
1286            public static String removeOldContent(String content, String xsd) {
1287                    try {
1288                            Document contentDoc = SAXReaderUtil.read(content);
1289                            Document xsdDoc = SAXReaderUtil.read(xsd);
1290    
1291                            Element contentRoot = contentDoc.getRootElement();
1292    
1293                            Stack<String> path = new Stack<String>();
1294    
1295                            path.push(contentRoot.getName());
1296    
1297                            _removeOldContent(path, contentRoot, xsdDoc);
1298    
1299                            content = DDMXMLUtil.formatXML(contentDoc);
1300                    }
1301                    catch (Exception e) {
1302                            _log.error(e, e);
1303                    }
1304    
1305                    return content;
1306            }
1307    
1308            public static void removeRecentArticle(
1309                    PortletRequest portletRequest, String articleId) {
1310    
1311                    removeRecentArticle(portletRequest, articleId, 0);
1312            }
1313    
1314            public static void removeRecentArticle(
1315                    PortletRequest portletRequest, String articleId, double version) {
1316    
1317                    Stack<JournalArticle> stack = getRecentArticles(portletRequest);
1318    
1319                    Iterator<JournalArticle> itr = stack.iterator();
1320    
1321                    while (itr.hasNext()) {
1322                            JournalArticle journalArticle = itr.next();
1323    
1324                            if (journalArticle.getArticleId().equals(articleId) &&
1325                                    ((journalArticle.getVersion() == version) ||
1326                                     (version == 0))) {
1327    
1328                                    itr.remove();
1329                            }
1330                    }
1331            }
1332    
1333            public static void removeRecentDDMStructure(
1334                    PortletRequest portletRequest, String ddmStructureKey) {
1335    
1336                    Stack<DDMStructure> stack = getRecentDDMStructures(portletRequest);
1337    
1338                    Iterator<DDMStructure> itr = stack.iterator();
1339    
1340                    while (itr.hasNext()) {
1341                            DDMStructure ddmStructure = itr.next();
1342    
1343                            if (ddmStructureKey.equals(ddmStructure.getStructureKey())) {
1344                                    itr.remove();
1345    
1346                                    break;
1347                            }
1348                    }
1349            }
1350    
1351            public static void removeRecentDDMTemplate(
1352                    PortletRequest portletRequest, String ddmTemplateKey) {
1353    
1354                    Stack<DDMTemplate> stack = getRecentDDMTemplates(portletRequest);
1355    
1356                    Iterator<DDMTemplate> itr = stack.iterator();
1357    
1358                    while (itr.hasNext()) {
1359                            DDMTemplate ddmTemplate = itr.next();
1360    
1361                            if (ddmTemplateKey.equals(ddmTemplate.getTemplateKey())) {
1362                                    itr.remove();
1363    
1364                                    break;
1365                            }
1366                    }
1367            }
1368    
1369            public static List<JournalStructure> toJournalStructures(
1370                            List<DDMStructure> ddmStructures)
1371                    throws SystemException {
1372    
1373                    List<JournalStructure> structures = new ArrayList<JournalStructure>();
1374    
1375                    for (DDMStructure ddmStructure : ddmStructures) {
1376                            JournalStructure structure = new JournalStructureAdapter(
1377                                    ddmStructure);
1378    
1379                            structures.add(structure);
1380                    }
1381    
1382                    return new UnmodifiableList<JournalStructure>(structures);
1383            }
1384    
1385            public static List<JournalTemplate> toJournalTemplates(
1386                    List<DDMTemplate> ddmTemplates) {
1387    
1388                    List<JournalTemplate> templates = new ArrayList<JournalTemplate>();
1389    
1390                    for (DDMTemplate ddmTemplate : ddmTemplates) {
1391                            JournalTemplate template = new JournalTemplateAdapter(ddmTemplate);
1392    
1393                            templates.add(template);
1394                    }
1395    
1396                    return new UnmodifiableList<JournalTemplate>(templates);
1397            }
1398    
1399            public static String transform(
1400                            ThemeDisplay themeDisplay, Map<String, String> tokens,
1401                            String viewMode, String languageId, String xml, String script,
1402                            String langType)
1403                    throws Exception {
1404    
1405                    return _transformer.transform(
1406                            themeDisplay, tokens, viewMode, languageId, xml, script, langType);
1407            }
1408    
1409            private static void _addElementOptions(
1410                    Element curContentElement, Element newContentElement) {
1411    
1412                    List<Element> newElementOptions = newContentElement.elements("option");
1413    
1414                    for (Element newElementOption : newElementOptions) {
1415                            Element curElementOption = SAXReaderUtil.createElement("option");
1416    
1417                            curElementOption.addCDATA(newElementOption.getText());
1418    
1419                            curContentElement.add(curElementOption);
1420                    }
1421            }
1422    
1423            private static Element _getElementByInstanceId(
1424                    Document document, String instanceId) {
1425    
1426                    if (Validator.isNull(instanceId)) {
1427                            return null;
1428                    }
1429    
1430                    XPath xPathSelector = SAXReaderUtil.createXPath(
1431                            "//dynamic-element[@instance-id=" +
1432                                    HtmlUtil.escapeXPathAttribute(instanceId) + "]");
1433    
1434                    List<Node> nodes = xPathSelector.selectNodes(document);
1435    
1436                    if (nodes.size() == 1) {
1437                            return (Element)nodes.get(0);
1438                    }
1439                    else {
1440                            return null;
1441                    }
1442            }
1443    
1444            private static void _mergeArticleContentDelete(
1445                            Element curParentElement, Document newDocument)
1446                    throws Exception {
1447    
1448                    List<Element> curElements = curParentElement.elements(
1449                            "dynamic-element");
1450    
1451                    for (int i = 0; i < curElements.size(); i++) {
1452                            Element curElement = curElements.get(i);
1453    
1454                            _mergeArticleContentDelete(curElement, newDocument);
1455    
1456                            String instanceId = curElement.attributeValue("instance-id");
1457    
1458                            Element newElement = _getElementByInstanceId(
1459                                    newDocument, instanceId);
1460    
1461                            if (newElement == null) {
1462                                    curElement.detach();
1463                            }
1464                    }
1465            }
1466    
1467            private static void _mergeArticleContentUpdate(
1468                            Document curDocument, Element newParentElement, Element newElement,
1469                            int pos, String defaultLocale)
1470                    throws Exception {
1471    
1472                    _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1473    
1474                    String instanceId = newElement.attributeValue("instance-id");
1475    
1476                    Element curElement = _getElementByInstanceId(curDocument, instanceId);
1477    
1478                    if (curElement != null) {
1479                            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1480                    }
1481                    else {
1482                            String parentInstanceId = newParentElement.attributeValue(
1483                                    "instance-id");
1484    
1485                            if (Validator.isNull(parentInstanceId)) {
1486                                    Element curRoot = curDocument.getRootElement();
1487    
1488                                    List<Element> curRootElements = curRoot.elements();
1489    
1490                                    curRootElements.add(pos, newElement.createCopy());
1491                            }
1492                            else {
1493                                    Element curParentElement = _getElementByInstanceId(
1494                                            curDocument, parentInstanceId);
1495    
1496                                    if (curParentElement != null) {
1497                                            List<Element> curParentElements =
1498                                                    curParentElement.elements();
1499    
1500                                            curParentElements.add(pos, newElement.createCopy());
1501                                    }
1502                            }
1503                    }
1504            }
1505    
1506            private static void _mergeArticleContentUpdate(
1507                            Document curDocument, Element newParentElement,
1508                            String defaultLocale)
1509                    throws Exception {
1510    
1511                    List<Element> newElements = newParentElement.elements(
1512                            "dynamic-element");
1513    
1514                    for (int i = 0; i < newElements.size(); i++) {
1515                            Element newElement = newElements.get(i);
1516    
1517                            _mergeArticleContentUpdate(
1518                                    curDocument, newParentElement, newElement, i, defaultLocale);
1519                    }
1520            }
1521    
1522            private static void _mergeArticleContentUpdate(
1523                    Element curElement, Element newElement, String defaultLocale) {
1524    
1525                    Attribute curTypeAttribute = curElement.attribute("type");
1526                    Attribute newTypeAttribute = newElement.attribute("type");
1527    
1528                    curTypeAttribute.setValue(newTypeAttribute.getValue());
1529    
1530                    Attribute curIndexTypeAttribute = curElement.attribute("index-type");
1531                    Attribute newIndexTypeAttribute = newElement.attribute("index-type");
1532    
1533                    if (newIndexTypeAttribute != null) {
1534                            if (curIndexTypeAttribute == null) {
1535                                    curElement.addAttribute(
1536                                            "index-type", newIndexTypeAttribute.getValue());
1537                            }
1538                            else {
1539                                    curIndexTypeAttribute.setValue(
1540                                            newIndexTypeAttribute.getValue());
1541                            }
1542                    }
1543    
1544                    List<Element> elements = newElement.elements("dynamic-content");
1545    
1546                    Element newContentElement = elements.get(0);
1547    
1548                    String newLanguageId = newContentElement.attributeValue("language-id");
1549                    String newValue = newContentElement.getText();
1550    
1551                    String indexType = newElement.attributeValue("index-type");
1552    
1553                    if (Validator.isNotNull(indexType)) {
1554                            curElement.addAttribute("index-type", indexType);
1555                    }
1556    
1557                    List<Element> curContentElements = curElement.elements(
1558                            "dynamic-content");
1559    
1560                    if (Validator.isNull(newLanguageId)) {
1561                            for (Element curContentElement : curContentElements) {
1562                                    curContentElement.detach();
1563                            }
1564    
1565                            Element curContentElement = SAXReaderUtil.createElement(
1566                                    "dynamic-content");
1567    
1568                            if (newContentElement.element("option") != null) {
1569                                    _addElementOptions(curContentElement, newContentElement);
1570                            }
1571                            else {
1572                                    curContentElement.addCDATA(newValue);
1573                            }
1574    
1575                            curElement.add(curContentElement);
1576                    }
1577                    else {
1578                            boolean alreadyExists = false;
1579    
1580                            for (Element curContentElement : curContentElements) {
1581                                    String curLanguageId = curContentElement.attributeValue(
1582                                            "language-id");
1583    
1584                                    if (newLanguageId.equals(curLanguageId)) {
1585                                            alreadyExists = true;
1586    
1587                                            curContentElement.clearContent();
1588    
1589                                            if (newContentElement.element("option") != null) {
1590                                                    _addElementOptions(
1591                                                            curContentElement, newContentElement);
1592                                            }
1593                                            else {
1594                                                    curContentElement.addCDATA(newValue);
1595                                            }
1596    
1597                                            break;
1598                                    }
1599                            }
1600    
1601                            if (!alreadyExists) {
1602                                    Element curContentElement = curContentElements.get(0);
1603    
1604                                    String curLanguageId = curContentElement.attributeValue(
1605                                            "language-id");
1606    
1607                                    if (Validator.isNull(curLanguageId)) {
1608                                            if (newLanguageId.equals(defaultLocale)) {
1609                                                    curContentElement.clearContent();
1610    
1611                                                    if (newContentElement.element("option") != null) {
1612                                                            _addElementOptions(
1613                                                                    curContentElement, newContentElement);
1614                                                    }
1615                                                    else {
1616                                                            curContentElement.addCDATA(newValue);
1617                                                    }
1618                                            }
1619                                            else {
1620                                                    curElement.add(newContentElement.createCopy());
1621                                            }
1622    
1623                                            curContentElement.addAttribute(
1624                                                    "language-id", defaultLocale);
1625                                    }
1626                                    else {
1627                                            curElement.add(newContentElement.createCopy());
1628                                    }
1629                            }
1630                    }
1631            }
1632    
1633            private static void _populateCustomTokens(Map<String, String> tokens) {
1634                    if (_customTokens == null) {
1635                            synchronized (JournalUtil.class) {
1636                                    _customTokens = new HashMap<String, String>();
1637    
1638                                    for (String customToken :
1639                                                    PropsValues.JOURNAL_ARTICLE_CUSTOM_TOKENS) {
1640    
1641                                            String value = PropsUtil.get(
1642                                                    PropsKeys.JOURNAL_ARTICLE_CUSTOM_TOKEN_VALUE,
1643                                                    new Filter(customToken));
1644    
1645                                            _customTokens.put(customToken, value);
1646                                    }
1647                            }
1648                    }
1649    
1650                    if (!_customTokens.isEmpty()) {
1651                            tokens.putAll(_customTokens);
1652                    }
1653            }
1654    
1655            private static void _populateTokens(
1656                            Map<String, String> tokens, long articleGroupId, String xmlRequest)
1657                    throws Exception {
1658    
1659                    Document requestDocument = SAXReaderUtil.read(xmlRequest);
1660    
1661                    Element rootElement = requestDocument.getRootElement();
1662    
1663                    Element themeDisplayElement = rootElement.element("theme-display");
1664    
1665                    Layout layout = LayoutLocalServiceUtil.getLayout(
1666                            GetterUtil.getLong(themeDisplayElement.elementText("plid")));
1667    
1668                    Group group = layout.getGroup();
1669    
1670                    LayoutSet layoutSet = layout.getLayoutSet();
1671    
1672                    String friendlyUrlCurrent = null;
1673    
1674                    if (layout.isPublicLayout()) {
1675                            friendlyUrlCurrent = themeDisplayElement.elementText(
1676                                    "path-friendly-url-public");
1677                    }
1678                    else if (group.isUserGroup()) {
1679                            friendlyUrlCurrent = themeDisplayElement.elementText(
1680                                    "path-friendly-url-private-user");
1681                    }
1682                    else {
1683                            friendlyUrlCurrent = themeDisplayElement.elementText(
1684                                    "path-friendly-url-private-group");
1685                    }
1686    
1687                    String layoutSetFriendlyUrl = themeDisplayElement.elementText(
1688                            "i18n-path");
1689    
1690                    String virtualHostname = layoutSet.getVirtualHostname();
1691    
1692                    if (Validator.isNull(virtualHostname) ||
1693                            !virtualHostname.equals(
1694                                    themeDisplayElement.elementText("server-name"))) {
1695    
1696                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1697                    }
1698    
1699                    tokens.put("article_group_id", String.valueOf(articleGroupId));
1700                    tokens.put("cdn_host", themeDisplayElement.elementText("cdn-host"));
1701                    tokens.put("company_id", themeDisplayElement.elementText("company-id"));
1702                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1703                    tokens.put(
1704                            "friendly_url_private_group",
1705                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1706                    tokens.put(
1707                            "friendly_url_private_user",
1708                            themeDisplayElement.elementText("path-friendly-url-private-user"));
1709                    tokens.put(
1710                            "friendly_url_public",
1711                            themeDisplayElement.elementText("path-friendly-url-public"));
1712                    tokens.put("group_friendly_url", group.getFriendlyURL());
1713                    tokens.put("image_path", themeDisplayElement.elementText("path-image"));
1714                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1715                    tokens.put("main_path", themeDisplayElement.elementText("path-main"));
1716                    tokens.put(
1717                            "portal_ctx", themeDisplayElement.elementText("path-context"));
1718                    tokens.put(
1719                            "portal_url",
1720                            HttpUtil.removeProtocol(
1721                                    themeDisplayElement.elementText("url-portal")));
1722                    tokens.put(
1723                            "protocol",
1724                            HttpUtil.getProtocol(
1725                                    themeDisplayElement.elementText("url-portal")));
1726                    tokens.put(
1727                            "root_path", themeDisplayElement.elementText("path-context"));
1728                    tokens.put(
1729                            "scope_group_id",
1730                            themeDisplayElement.elementText("scope-group-id"));
1731                    tokens.put(
1732                            "site_group_id", themeDisplayElement.elementText("site-group-id"));
1733                    tokens.put(
1734                            "theme_image_path",
1735                            themeDisplayElement.elementText("path-theme-images"));
1736    
1737                    _populateCustomTokens(tokens);
1738    
1739                    // Deprecated tokens
1740    
1741                    tokens.put(
1742                            "friendly_url",
1743                            themeDisplayElement.elementText("path-friendly-url-public"));
1744                    tokens.put(
1745                            "friendly_url_private",
1746                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1747                    tokens.put("group_id", String.valueOf(articleGroupId));
1748                    tokens.put(
1749                            "page_url",
1750                            themeDisplayElement.elementText("path-friendly-url-public"));
1751            }
1752    
1753            private static void _populateTokens(
1754                            Map<String, String> tokens, long articleGroupId,
1755                            ThemeDisplay themeDisplay)
1756                    throws PortalException, SystemException {
1757    
1758                    Layout layout = themeDisplay.getLayout();
1759    
1760                    Group group = layout.getGroup();
1761    
1762                    LayoutSet layoutSet = layout.getLayoutSet();
1763    
1764                    String friendlyUrlCurrent = null;
1765    
1766                    if (layout.isPublicLayout()) {
1767                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1768                    }
1769                    else if (group.isUserGroup()) {
1770                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1771                    }
1772                    else {
1773                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1774                    }
1775    
1776                    String layoutSetFriendlyUrl = themeDisplay.getI18nPath();
1777    
1778                    String virtualHostname = layoutSet.getVirtualHostname();
1779    
1780                    if (Validator.isNull(virtualHostname) ||
1781                            !virtualHostname.equals(themeDisplay.getServerName())) {
1782    
1783                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1784                    }
1785    
1786                    tokens.put("article_group_id", String.valueOf(articleGroupId));
1787                    tokens.put("cdn_host", themeDisplay.getCDNHost());
1788                    tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1789                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1790                    tokens.put(
1791                            "friendly_url_private_group",
1792                            themeDisplay.getPathFriendlyURLPrivateGroup());
1793                    tokens.put(
1794                            "friendly_url_private_user",
1795                            themeDisplay.getPathFriendlyURLPrivateUser());
1796                    tokens.put(
1797                            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1798                    tokens.put("group_friendly_url", group.getFriendlyURL());
1799                    tokens.put("image_path", themeDisplay.getPathImage());
1800                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1801                    tokens.put("main_path", themeDisplay.getPathMain());
1802                    tokens.put("portal_ctx", themeDisplay.getPathContext());
1803                    tokens.put(
1804                            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1805                    tokens.put(
1806                            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1807                    tokens.put("root_path", themeDisplay.getPathContext());
1808                    tokens.put(
1809                            "site_group_id", String.valueOf(themeDisplay.getSiteGroupId()));
1810                    tokens.put(
1811                            "scope_group_id", String.valueOf(themeDisplay.getScopeGroupId()));
1812                    tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1813    
1814                    _populateCustomTokens(tokens);
1815    
1816                    // Deprecated tokens
1817    
1818                    tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1819                    tokens.put(
1820                            "friendly_url_private",
1821                            themeDisplay.getPathFriendlyURLPrivateGroup());
1822                    tokens.put("group_id", String.valueOf(articleGroupId));
1823                    tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1824            }
1825    
1826            private static void _removeOldContent(
1827                            Stack<String> path, Element contentElement, Document xsdDocument)
1828                    throws SystemException {
1829    
1830                    String elementPath = "";
1831    
1832                    for (int i = 0; i < path.size(); i++) {
1833                            elementPath += "/" + path.elementAt(i);
1834                    }
1835    
1836                    for (int i = 0; i < contentElement.nodeCount(); i++) {
1837                            Node contentNode = contentElement.node(i);
1838    
1839                            if (contentNode instanceof Element) {
1840                                    _removeOldContent(
1841                                            path, (Element)contentNode, xsdDocument, elementPath);
1842                            }
1843                    }
1844            }
1845    
1846            private static void _removeOldContent(
1847                            Stack<String> path, Element contentElement, Document xsdDocument,
1848                            String elementPath)
1849                    throws SystemException {
1850    
1851                    String name = contentElement.attributeValue("name");
1852    
1853                    if (Validator.isNull(name)) {
1854                            return;
1855                    }
1856    
1857                    String localPath =
1858                            "dynamic-element[@name=" + HtmlUtil.escapeXPathAttribute(name) +
1859                                    "]";
1860    
1861                    String fullPath = elementPath + "/" + localPath;
1862    
1863                    XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1864    
1865                    List<Node> curNodes = xPathSelector.selectNodes(xsdDocument);
1866    
1867                    if (curNodes.size() == 0) {
1868                            contentElement.detach();
1869                    }
1870    
1871                    path.push(localPath);
1872    
1873                    _removeOldContent(path, contentElement, xsdDocument);
1874    
1875                    path.pop();
1876            }
1877    
1878            private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1879    
1880            private static Map<String, String> _customTokens;
1881            private static Pattern _friendlyURLPattern = Pattern.compile("[^a-z0-9_-]");
1882            private static Transformer _transformer = new Transformer(
1883                    PropsKeys.JOURNAL_TRANSFORMER_LISTENER,
1884                    PropsKeys.JOURNAL_ERROR_TEMPLATE, true);
1885    
1886    }