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(
553                                    document.get(Field.SCOPE_GROUP_ID));
554                            String articleId = document.get("articleId");
555    
556                            try {
557                                    JournalArticle article =
558                                            JournalArticleLocalServiceUtil.getArticle(
559                                                    groupId, articleId);
560    
561                                    articles.add(article);
562                            }
563                            catch (NoSuchArticleException nsae) {
564                                    corruptIndex = true;
565    
566                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
567                                            JournalArticle.class);
568    
569                                    long companyId = GetterUtil.getLong(
570                                            document.get(Field.COMPANY_ID));
571    
572                                    indexer.delete(companyId, document.getUID());
573                            }
574                    }
575    
576                    return new Tuple(articles, corruptIndex);
577            }
578    
579            public static String getEmailArticleAddedBody(
580                    PortletPreferences preferences) {
581    
582                    String emailArticleAddedBody = preferences.getValue(
583                            "emailArticleAddedBody", StringPool.BLANK);
584    
585                    if (Validator.isNotNull(emailArticleAddedBody)) {
586                            return emailArticleAddedBody;
587                    }
588                    else {
589                            return ContentUtil.get(
590                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_BODY));
591                    }
592            }
593    
594            public static boolean getEmailArticleAddedEnabled(
595                    PortletPreferences preferences) {
596    
597                    String emailArticleAddedEnabled = preferences.getValue(
598                            "emailArticleAddedEnabled", StringPool.BLANK);
599    
600                    if (Validator.isNotNull(emailArticleAddedEnabled)) {
601                            return GetterUtil.getBoolean(emailArticleAddedEnabled);
602                    }
603                    else {
604                            return GetterUtil.getBoolean(
605                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_ENABLED));
606                    }
607            }
608    
609            public static String getEmailArticleAddedSubject(
610                    PortletPreferences preferences) {
611    
612                    String emailArticleAddedSubject = preferences.getValue(
613                            "emailArticleAddedSubject", StringPool.BLANK);
614    
615                    if (Validator.isNotNull(emailArticleAddedSubject)) {
616                            return emailArticleAddedSubject;
617                    }
618                    else {
619                            return ContentUtil.get(
620                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_ADDED_SUBJECT));
621                    }
622            }
623    
624            public static String getEmailArticleApprovalDeniedBody(
625                    PortletPreferences preferences) {
626    
627                    String emailArticleApprovalDeniedBody = preferences.getValue(
628                            "emailArticleApprovalDeniedBody", StringPool.BLANK);
629    
630                    if (Validator.isNotNull(emailArticleApprovalDeniedBody)) {
631                            return emailArticleApprovalDeniedBody;
632                    }
633                    else {
634                            return ContentUtil.get(
635                                    PropsUtil.get(
636                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_BODY));
637                    }
638            }
639    
640            public static boolean getEmailArticleApprovalDeniedEnabled(
641                    PortletPreferences preferences) {
642    
643                    String emailArticleApprovalDeniedEnabled = preferences.getValue(
644                            "emailArticleApprovalDeniedEnabled", StringPool.BLANK);
645    
646                    if (Validator.isNotNull(emailArticleApprovalDeniedEnabled)) {
647                            return GetterUtil.getBoolean(emailArticleApprovalDeniedEnabled);
648                    }
649                    else {
650                            return GetterUtil.getBoolean(
651                                    PropsUtil.get(
652                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_ENABLED));
653                    }
654            }
655    
656            public static String getEmailArticleApprovalDeniedSubject(
657                    PortletPreferences preferences) {
658    
659                    String emailArticleApprovalDeniedSubject = preferences.getValue(
660                            "emailArticleApprovalDeniedSubject", StringPool.BLANK);
661    
662                    if (Validator.isNotNull(emailArticleApprovalDeniedSubject)) {
663                            return emailArticleApprovalDeniedSubject;
664                    }
665                    else {
666                            return ContentUtil.get(
667                                    PropsUtil.get(
668                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_DENIED_SUBJECT));
669                    }
670            }
671    
672            public static String getEmailArticleApprovalGrantedBody(
673                    PortletPreferences preferences) {
674    
675                    String emailArticleApprovalGrantedBody = preferences.getValue(
676                            "emailArticleApprovalGrantedBody", StringPool.BLANK);
677    
678                    if (Validator.isNotNull(emailArticleApprovalGrantedBody)) {
679                            return emailArticleApprovalGrantedBody;
680                    }
681                    else {
682                            return ContentUtil.get(
683                                    PropsUtil.get(
684                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_BODY));
685                    }
686            }
687    
688            public static boolean getEmailArticleApprovalGrantedEnabled(
689                    PortletPreferences preferences) {
690    
691                    String emailArticleApprovalGrantedEnabled = preferences.getValue(
692                            "emailArticleApprovalGrantedEnabled", StringPool.BLANK);
693    
694                    if (Validator.isNotNull(emailArticleApprovalGrantedEnabled)) {
695                            return GetterUtil.getBoolean(emailArticleApprovalGrantedEnabled);
696                    }
697                    else {
698                            return GetterUtil.getBoolean(
699                                    PropsUtil.get(
700                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_ENABLED));
701                    }
702            }
703    
704            public static String getEmailArticleApprovalGrantedSubject(
705                    PortletPreferences preferences) {
706    
707                    String emailArticleApprovalGrantedSubject = preferences.getValue(
708                            "emailArticleApprovalGrantedSubject", StringPool.BLANK);
709    
710                    if (Validator.isNotNull(emailArticleApprovalGrantedSubject)) {
711                            return emailArticleApprovalGrantedSubject;
712                    }
713                    else {
714                            return ContentUtil.get(
715                                    PropsUtil.get(
716                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_GRANTED_SUBJECT));
717                    }
718            }
719    
720            public static String getEmailArticleApprovalRequestedBody(
721                    PortletPreferences preferences) {
722    
723                    String emailArticleApprovalRequestedBody = preferences.getValue(
724                            "emailArticleApprovalRequestedBody", StringPool.BLANK);
725    
726                    if (Validator.isNotNull(emailArticleApprovalRequestedBody)) {
727                            return emailArticleApprovalRequestedBody;
728                    }
729                    else {
730                            return ContentUtil.get(
731                                    PropsUtil.get(
732                                            PropsKeys.JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_BODY));
733                    }
734            }
735    
736            public static boolean getEmailArticleApprovalRequestedEnabled(
737                    PortletPreferences preferences) {
738    
739                    String emailArticleApprovalRequestedEnabled = preferences.getValue(
740                            "emailArticleApprovalRequestedEnabled", StringPool.BLANK);
741    
742                    if (Validator.isNotNull(emailArticleApprovalRequestedEnabled)) {
743                            return GetterUtil.getBoolean(emailArticleApprovalRequestedEnabled);
744                    }
745                    else {
746                            return GetterUtil.getBoolean(
747                                    PropsUtil.get(
748                                            PropsKeys.
749                                                    JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_ENABLED));
750                    }
751            }
752    
753            public static String getEmailArticleApprovalRequestedSubject(
754                    PortletPreferences preferences) {
755    
756                    String emailArticleApprovalRequestedSubject = preferences.getValue(
757                            "emailArticleApprovalRequestedSubject", StringPool.BLANK);
758    
759                    if (Validator.isNotNull(emailArticleApprovalRequestedSubject)) {
760                            return emailArticleApprovalRequestedSubject;
761                    }
762                    else {
763                            return ContentUtil.get(
764                                    PropsUtil.get(
765                                            PropsKeys.
766                                                    JOURNAL_EMAIL_ARTICLE_APPROVAL_REQUESTED_SUBJECT));
767                    }
768            }
769    
770            public static String getEmailArticleReviewBody(
771                    PortletPreferences preferences) {
772    
773                    String emailArticleReviewBody = preferences.getValue(
774                            "emailArticleReviewBody", StringPool.BLANK);
775    
776                    if (Validator.isNotNull(emailArticleReviewBody)) {
777                            return emailArticleReviewBody;
778                    }
779                    else {
780                            return ContentUtil.get(
781                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_BODY));
782                    }
783            }
784    
785            public static boolean getEmailArticleReviewEnabled(
786                    PortletPreferences preferences) {
787    
788                    String emailArticleReviewEnabled = preferences.getValue(
789                            "emailArticleReviewEnabled", StringPool.BLANK);
790    
791                    if (Validator.isNotNull(emailArticleReviewEnabled)) {
792                            return GetterUtil.getBoolean(emailArticleReviewEnabled);
793                    }
794                    else {
795                            return GetterUtil.getBoolean(
796                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_ENABLED));
797                    }
798            }
799    
800            public static String getEmailArticleReviewSubject(
801                    PortletPreferences preferences) {
802    
803                    String emailArticleReviewSubject = preferences.getValue(
804                            "emailArticleReviewSubject", StringPool.BLANK);
805    
806                    if (Validator.isNotNull(emailArticleReviewSubject)) {
807                            return emailArticleReviewSubject;
808                    }
809                    else {
810                            return ContentUtil.get(
811                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_REVIEW_SUBJECT));
812                    }
813            }
814    
815            public static String getEmailArticleUpdatedBody(
816                    PortletPreferences preferences) {
817    
818                    String emailArticleUpdatedBody = preferences.getValue(
819                            "emailArticleUpdatedBody", StringPool.BLANK);
820    
821                    if (Validator.isNotNull(emailArticleUpdatedBody)) {
822                            return emailArticleUpdatedBody;
823                    }
824                    else {
825                            return ContentUtil.get(
826                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_BODY));
827                    }
828            }
829    
830            public static boolean getEmailArticleUpdatedEnabled(
831                    PortletPreferences preferences) {
832    
833                    String emailArticleUpdatedEnabled = preferences.getValue(
834                            "emailArticleUpdatedEnabled", StringPool.BLANK);
835    
836                    if (Validator.isNotNull(emailArticleUpdatedEnabled)) {
837                            return GetterUtil.getBoolean(emailArticleUpdatedEnabled);
838                    }
839                    else {
840                            return GetterUtil.getBoolean(
841                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_ENABLED));
842                    }
843            }
844    
845            public static String getEmailArticleUpdatedSubject(
846                    PortletPreferences preferences) {
847    
848                    String emailArticleUpdatedSubject = preferences.getValue(
849                            "emailArticleUpdatedSubject", StringPool.BLANK);
850    
851                    if (Validator.isNotNull(emailArticleUpdatedSubject)) {
852                            return emailArticleUpdatedSubject;
853                    }
854                    else {
855                            return ContentUtil.get(
856                                    PropsUtil.get(PropsKeys.JOURNAL_EMAIL_ARTICLE_UPDATED_SUBJECT));
857                    }
858            }
859    
860            public static String getEmailFromAddress(
861                            PortletPreferences preferences, long companyId)
862                    throws SystemException {
863    
864                    return PortalUtil.getEmailFromAddress(
865                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_ADDRESS);
866            }
867    
868            public static String getEmailFromName(
869                            PortletPreferences preferences, long companyId)
870                    throws SystemException {
871    
872                    return PortalUtil.getEmailFromName(
873                            preferences, companyId, PropsValues.JOURNAL_EMAIL_FROM_NAME);
874            }
875    
876            public static String getJournalControlPanelLink(
877                            PortletRequest portletRequest, long folderId)
878                    throws PortalException, SystemException {
879    
880                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
881                            WebKeys.THEME_DISPLAY);
882    
883                    PortletURL portletURL = PortletURLFactoryUtil.create(
884                            portletRequest, PortletKeys.JOURNAL,
885                            PortalUtil.getControlPanelPlid(themeDisplay.getCompanyId()),
886                            PortletRequest.RENDER_PHASE);
887    
888                    portletURL.setParameter("struts_action", "/journal/view");
889                    portletURL.setParameter("folderId", String.valueOf(folderId));
890    
891                    return portletURL.toString();
892            }
893    
894            public static long getPreviewPlid(
895                            JournalArticle article, ThemeDisplay themeDisplay)
896                    throws Exception {
897    
898                    if ((article != null) && Validator.isNotNull(article.getLayoutUuid())) {
899                            Layout layout =
900                                    LayoutLocalServiceUtil.getLayoutByUuidAndCompanyId(
901                                            article.getLayoutUuid(), themeDisplay.getCompanyId());
902    
903                            return layout.getPlid();
904                    }
905    
906                    Layout layout = LayoutLocalServiceUtil.fetchFirstLayout(
907                            themeDisplay.getScopeGroupId(), false,
908                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
909    
910                    if (layout == null) {
911                            layout = LayoutLocalServiceUtil.fetchFirstLayout(
912                                    themeDisplay.getScopeGroupId(), true,
913                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
914                    }
915    
916                    if (layout != null) {
917                            return layout.getPlid();
918                    }
919    
920                    return themeDisplay.getPlid();
921            }
922    
923            public static Stack<JournalArticle> getRecentArticles(
924                    PortletRequest portletRequest) {
925    
926                    PortletSession portletSession = portletRequest.getPortletSession();
927    
928                    Stack<JournalArticle> recentArticles =
929                            (Stack<JournalArticle>)portletSession.getAttribute(
930                                    WebKeys.JOURNAL_RECENT_ARTICLES);
931    
932                    if (recentArticles == null) {
933                            recentArticles = new FiniteUniqueStack<JournalArticle>(
934                                    MAX_STACK_SIZE);
935    
936                            portletSession.setAttribute(
937                                    WebKeys.JOURNAL_RECENT_ARTICLES, recentArticles);
938                    }
939    
940                    return recentArticles;
941            }
942    
943            public static Stack<DDMStructure> getRecentDDMStructures(
944                    PortletRequest portletRequest) {
945    
946                    PortletSession portletSession = portletRequest.getPortletSession();
947    
948                    Stack<DDMStructure> recentDDMStructures =
949                            (Stack<DDMStructure>)portletSession.getAttribute(
950                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_STRUCTURES);
951    
952                    if (recentDDMStructures == null) {
953                            recentDDMStructures = new FiniteUniqueStack<DDMStructure>(
954                                    MAX_STACK_SIZE);
955    
956                            portletSession.setAttribute(
957                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_STRUCTURES,
958                                    recentDDMStructures);
959                    }
960    
961                    return recentDDMStructures;
962            }
963    
964            public static Stack<DDMTemplate> getRecentDDMTemplates(
965                    PortletRequest portletRequest) {
966    
967                    PortletSession portletSession = portletRequest.getPortletSession();
968    
969                    Stack<DDMTemplate> recentDDMTemplates =
970                            (Stack<DDMTemplate>)portletSession.getAttribute(
971                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_TEMPLATES);
972    
973                    if (recentDDMTemplates == null) {
974                            recentDDMTemplates = new FiniteUniqueStack<DDMTemplate>(
975                                    MAX_STACK_SIZE);
976    
977                            portletSession.setAttribute(
978                                    WebKeys.JOURNAL_RECENT_DYNAMIC_DATA_MAPPING_TEMPLATES,
979                                    recentDDMTemplates);
980                    }
981    
982                    return recentDDMTemplates;
983            }
984    
985            public static long[] getStructureClassPKs(
986                            long[] groupIds, String structureId)
987                    throws SystemException {
988    
989                    List<Long> classPKs = new ArrayList<Long>();
990    
991                    for (long groupId : groupIds) {
992                            @SuppressWarnings("deprecation")
993                            JournalStructure structure =
994                                    com.liferay.portlet.journal.service.
995                                            JournalStructureLocalServiceUtil.fetchStructure(
996                                                    groupId, structureId);
997    
998                            if (structure != null) {
999                                    classPKs.add(structure.getId());
1000                            }
1001                    }
1002    
1003                    return ArrayUtil.toLongArray(classPKs);
1004            }
1005    
1006            public static String getTemplateScript(
1007                    DDMTemplate ddmTemplate, Map<String, String> tokens, String languageId,
1008                    boolean transform) {
1009    
1010                    String script = ddmTemplate.getScript();
1011    
1012                    if (!transform) {
1013                            return script;
1014                    }
1015    
1016                    String[] transformerListenerClassNames = PropsUtil.getArray(
1017                            PropsKeys.JOURNAL_TRANSFORMER_LISTENER);
1018    
1019                    for (String transformerListenerClassName :
1020                                    transformerListenerClassNames) {
1021    
1022                            TransformerListener transformerListener = null;
1023    
1024                            try {
1025                                    transformerListener =
1026                                            (TransformerListener)InstanceFactory.newInstance(
1027                                                    transformerListenerClassName);
1028    
1029                                    continue;
1030                            }
1031                            catch (Exception e) {
1032                                    _log.error(e, e);
1033                            }
1034    
1035                            script = transformerListener.onScript(
1036                                    script, null, languageId, tokens);
1037                    }
1038    
1039                    return script;
1040            }
1041    
1042            public static String getTemplateScript(
1043                            long groupId, String ddmTemplateKey, Map<String, String> tokens,
1044                            String languageId)
1045                    throws PortalException, SystemException {
1046    
1047                    return getTemplateScript(
1048                            groupId, ddmTemplateKey, tokens, languageId, true);
1049            }
1050    
1051            public static String getTemplateScript(
1052                            long groupId, String ddmTemplateKey, Map<String, String> tokens,
1053                            String languageId, boolean transform)
1054                    throws PortalException, SystemException {
1055    
1056                    DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
1057                            groupId, PortalUtil.getClassNameId(DDMStructure.class),
1058                            ddmTemplateKey, true);
1059    
1060                    return getTemplateScript(ddmTemplate, tokens, languageId, transform);
1061            }
1062    
1063            public static Map<String, String> getTokens(
1064                            long articleGroupId, ThemeDisplay themeDisplay)
1065                    throws PortalException, SystemException {
1066    
1067                    return getTokens(articleGroupId, themeDisplay, null);
1068            }
1069    
1070            public static Map<String, String> getTokens(
1071                            long articleGroupId, ThemeDisplay themeDisplay, String xmlRequest)
1072                    throws PortalException, SystemException {
1073    
1074                    Map<String, String> tokens = new HashMap<String, String>();
1075    
1076                    if (themeDisplay != null) {
1077                            _populateTokens(tokens, articleGroupId, themeDisplay);
1078                    }
1079                    else if (Validator.isNotNull(xmlRequest)) {
1080                            try {
1081                                    _populateTokens(tokens, articleGroupId, xmlRequest);
1082                            }
1083                            catch (Exception e) {
1084                                    if (_log.isWarnEnabled()) {
1085                                            _log.warn(e, e);
1086                                    }
1087                            }
1088                    }
1089    
1090                    return tokens;
1091            }
1092    
1093            public static String getUrlTitle(long id, String title) {
1094                    if (title == null) {
1095                            return String.valueOf(id);
1096                    }
1097    
1098                    title = StringUtil.toLowerCase(title.trim());
1099    
1100                    if (Validator.isNull(title) || Validator.isNumber(title) ||
1101                            title.equals("rss")) {
1102    
1103                            title = String.valueOf(id);
1104                    }
1105                    else {
1106                            title = FriendlyURLNormalizerUtil.normalize(
1107                                    title, _friendlyURLPattern);
1108                    }
1109    
1110                    return ModelHintsUtil.trimString(
1111                            JournalArticle.class.getName(), "urlTitle", title);
1112            }
1113    
1114            public static String mergeArticleContent(
1115                    String curContent, String newContent, boolean removeNullElements) {
1116    
1117                    try {
1118                            Document curDocument = SAXReaderUtil.read(curContent);
1119                            Document newDocument = SAXReaderUtil.read(newContent);
1120    
1121                            Element curRootElement = curDocument.getRootElement();
1122                            Element newRootElement = newDocument.getRootElement();
1123    
1124                            curRootElement.addAttribute(
1125                                    "default-locale",
1126                                    newRootElement.attributeValue("default-locale"));
1127                            curRootElement.addAttribute(
1128                                    "available-locales",
1129                                    newRootElement.attributeValue("available-locales"));
1130    
1131                            _mergeArticleContentUpdate(
1132                                    curDocument, newRootElement,
1133                                    LocaleUtil.toLanguageId(LocaleUtil.getSiteDefault()));
1134    
1135                            if (removeNullElements) {
1136                                    _mergeArticleContentDelete(curRootElement, newDocument);
1137                            }
1138    
1139                            curContent = DDMXMLUtil.formatXML(curDocument);
1140                    }
1141                    catch (Exception e) {
1142                            _log.error(e, e);
1143                    }
1144    
1145                    return curContent;
1146            }
1147    
1148            public static String prepareLocalizedContentForImport(
1149                            String content, Locale defaultImportLocale)
1150                    throws LocaleException {
1151    
1152                    try {
1153                            Document curDocument = SAXReaderUtil.read(content);
1154    
1155                            Document updatedDocument = SAXReaderUtil.read(content);
1156    
1157                            Element updatedRootElement = updatedDocument.getRootElement();
1158    
1159                            Attribute availableLocales = updatedRootElement.attribute(
1160                                    "available-locales");
1161    
1162                            if (Validator.isNull(availableLocales)) {
1163                                    updatedRootElement = updatedRootElement.addAttribute(
1164                                            "available-locales", StringPool.BLANK);
1165    
1166                                    availableLocales = updatedRootElement.attribute(
1167                                            "available-locales");
1168                            }
1169    
1170                            String defaultImportLocaleId = LocaleUtil.toLanguageId(
1171                                    defaultImportLocale);
1172    
1173                            if (!StringUtil.contains(
1174                                            availableLocales.getValue(), defaultImportLocaleId)) {
1175    
1176                                    if (Validator.isNull(availableLocales.getValue())) {
1177                                            availableLocales.setValue(defaultImportLocaleId);
1178                                    }
1179                                    else {
1180                                            StringBundler sb = new StringBundler(3);
1181    
1182                                            sb.append(availableLocales.getValue());
1183                                            sb.append(StringPool.COMMA);
1184                                            sb.append(defaultImportLocaleId);
1185    
1186                                            availableLocales.setValue(sb.toString());
1187                                    }
1188    
1189                                    _mergeArticleContentUpdate(
1190                                            curDocument, updatedRootElement,
1191                                            LocaleUtil.toLanguageId(defaultImportLocale));
1192    
1193                                    content = DDMXMLUtil.formatXML(updatedDocument);
1194                            }
1195    
1196                            Attribute defaultLocale = updatedRootElement.attribute(
1197                                    "default-locale");
1198    
1199                            if (Validator.isNull(defaultLocale)) {
1200                                    updatedRootElement = updatedRootElement.addAttribute(
1201                                            "default-locale", StringPool.BLANK);
1202    
1203                                    defaultLocale = updatedRootElement.attribute("default-locale");
1204                            }
1205    
1206                            Locale defaultContentLocale = LocaleUtil.fromLanguageId(
1207                                    defaultLocale.getValue());
1208    
1209                            if (!LocaleUtil.equals(defaultContentLocale, defaultImportLocale)) {
1210                                    defaultLocale.setValue(defaultImportLocaleId);
1211    
1212                                    content = DDMXMLUtil.formatXML(updatedDocument);
1213                            }
1214                    }
1215                    catch (Exception e) {
1216                            throw new LocaleException(
1217                                    LocaleException.TYPE_CONTENT,
1218                                    "The locale " + defaultImportLocale + " is not available");
1219                    }
1220    
1221                    return content;
1222            }
1223    
1224            public static void removeArticleLocale(Element element, String languageId)
1225                    throws PortalException, SystemException {
1226    
1227                    for (Element dynamicElementElement :
1228                                    element.elements("dynamic-element")) {
1229    
1230                            for (Element dynamicContentElement :
1231                                            dynamicElementElement.elements("dynamic-content")) {
1232    
1233                                    String curLanguageId = GetterUtil.getString(
1234                                            dynamicContentElement.attributeValue("language-id"));
1235    
1236                                    if (curLanguageId.equals(languageId)) {
1237                                            long id = GetterUtil.getLong(
1238                                                    dynamicContentElement.attributeValue("id"));
1239    
1240                                            if (id > 0) {
1241                                                    ImageLocalServiceUtil.deleteImage(id);
1242                                            }
1243    
1244                                            dynamicContentElement.detach();
1245                                    }
1246                            }
1247    
1248                            removeArticleLocale(dynamicElementElement, languageId);
1249                    }
1250            }
1251    
1252            public static String removeArticleLocale(
1253                    String content, String languageId) {
1254    
1255                    try {
1256                            Document document = SAXReaderUtil.read(content);
1257    
1258                            Element rootElement = document.getRootElement();
1259    
1260                            String availableLocales = rootElement.attributeValue(
1261                                    "available-locales");
1262    
1263                            if (availableLocales == null) {
1264                                    return content;
1265                            }
1266    
1267                            availableLocales = StringUtil.remove(availableLocales, languageId);
1268    
1269                            if (availableLocales.endsWith(",")) {
1270                                    availableLocales = availableLocales.substring(
1271                                            0, availableLocales.length() - 1);
1272                            }
1273    
1274                            rootElement.addAttribute("available-locales", availableLocales);
1275    
1276                            removeArticleLocale(rootElement, languageId);
1277    
1278                            content = DDMXMLUtil.formatXML(document);
1279                    }
1280                    catch (Exception e) {
1281                            _log.error(e, e);
1282                    }
1283    
1284                    return content;
1285            }
1286    
1287            public static String removeOldContent(String content, String xsd) {
1288                    try {
1289                            Document contentDoc = SAXReaderUtil.read(content);
1290                            Document xsdDoc = SAXReaderUtil.read(xsd);
1291    
1292                            Element contentRoot = contentDoc.getRootElement();
1293    
1294                            Stack<String> path = new Stack<String>();
1295    
1296                            path.push(contentRoot.getName());
1297    
1298                            _removeOldContent(path, contentRoot, xsdDoc);
1299    
1300                            content = DDMXMLUtil.formatXML(contentDoc);
1301                    }
1302                    catch (Exception e) {
1303                            _log.error(e, e);
1304                    }
1305    
1306                    return content;
1307            }
1308    
1309            public static void removeRecentArticle(
1310                    PortletRequest portletRequest, String articleId) {
1311    
1312                    removeRecentArticle(portletRequest, articleId, 0);
1313            }
1314    
1315            public static void removeRecentArticle(
1316                    PortletRequest portletRequest, String articleId, double version) {
1317    
1318                    Stack<JournalArticle> stack = getRecentArticles(portletRequest);
1319    
1320                    Iterator<JournalArticle> itr = stack.iterator();
1321    
1322                    while (itr.hasNext()) {
1323                            JournalArticle journalArticle = itr.next();
1324    
1325                            if (journalArticle.getArticleId().equals(articleId) &&
1326                                    ((journalArticle.getVersion() == version) ||
1327                                     (version == 0))) {
1328    
1329                                    itr.remove();
1330                            }
1331                    }
1332            }
1333    
1334            public static void removeRecentDDMStructure(
1335                    PortletRequest portletRequest, String ddmStructureKey) {
1336    
1337                    Stack<DDMStructure> stack = getRecentDDMStructures(portletRequest);
1338    
1339                    Iterator<DDMStructure> itr = stack.iterator();
1340    
1341                    while (itr.hasNext()) {
1342                            DDMStructure ddmStructure = itr.next();
1343    
1344                            if (ddmStructureKey.equals(ddmStructure.getStructureKey())) {
1345                                    itr.remove();
1346    
1347                                    break;
1348                            }
1349                    }
1350            }
1351    
1352            public static void removeRecentDDMTemplate(
1353                    PortletRequest portletRequest, String ddmTemplateKey) {
1354    
1355                    Stack<DDMTemplate> stack = getRecentDDMTemplates(portletRequest);
1356    
1357                    Iterator<DDMTemplate> itr = stack.iterator();
1358    
1359                    while (itr.hasNext()) {
1360                            DDMTemplate ddmTemplate = itr.next();
1361    
1362                            if (ddmTemplateKey.equals(ddmTemplate.getTemplateKey())) {
1363                                    itr.remove();
1364    
1365                                    break;
1366                            }
1367                    }
1368            }
1369    
1370            public static List<JournalStructure> toJournalStructures(
1371                            List<DDMStructure> ddmStructures)
1372                    throws SystemException {
1373    
1374                    List<JournalStructure> structures = new ArrayList<JournalStructure>();
1375    
1376                    for (DDMStructure ddmStructure : ddmStructures) {
1377                            JournalStructure structure = new JournalStructureAdapter(
1378                                    ddmStructure);
1379    
1380                            structures.add(structure);
1381                    }
1382    
1383                    return new UnmodifiableList<JournalStructure>(structures);
1384            }
1385    
1386            public static List<JournalTemplate> toJournalTemplates(
1387                    List<DDMTemplate> ddmTemplates) {
1388    
1389                    List<JournalTemplate> templates = new ArrayList<JournalTemplate>();
1390    
1391                    for (DDMTemplate ddmTemplate : ddmTemplates) {
1392                            JournalTemplate template = new JournalTemplateAdapter(ddmTemplate);
1393    
1394                            templates.add(template);
1395                    }
1396    
1397                    return new UnmodifiableList<JournalTemplate>(templates);
1398            }
1399    
1400            public static String transform(
1401                            ThemeDisplay themeDisplay, Map<String, String> tokens,
1402                            String viewMode, String languageId, String xml, String script,
1403                            String langType)
1404                    throws Exception {
1405    
1406                    return _transformer.transform(
1407                            themeDisplay, tokens, viewMode, languageId, xml, script, langType);
1408            }
1409    
1410            private static void _addElementOptions(
1411                    Element curContentElement, Element newContentElement) {
1412    
1413                    List<Element> newElementOptions = newContentElement.elements("option");
1414    
1415                    for (Element newElementOption : newElementOptions) {
1416                            Element curElementOption = SAXReaderUtil.createElement("option");
1417    
1418                            curElementOption.addCDATA(newElementOption.getText());
1419    
1420                            curContentElement.add(curElementOption);
1421                    }
1422            }
1423    
1424            private static Element _getElementByInstanceId(
1425                    Document document, String instanceId) {
1426    
1427                    if (Validator.isNull(instanceId)) {
1428                            return null;
1429                    }
1430    
1431                    XPath xPathSelector = SAXReaderUtil.createXPath(
1432                            "//dynamic-element[@instance-id=" +
1433                                    HtmlUtil.escapeXPathAttribute(instanceId) + "]");
1434    
1435                    List<Node> nodes = xPathSelector.selectNodes(document);
1436    
1437                    if (nodes.size() == 1) {
1438                            return (Element)nodes.get(0);
1439                    }
1440                    else {
1441                            return null;
1442                    }
1443            }
1444    
1445            private static void _mergeArticleContentDelete(
1446                            Element curParentElement, Document newDocument)
1447                    throws Exception {
1448    
1449                    List<Element> curElements = curParentElement.elements(
1450                            "dynamic-element");
1451    
1452                    for (int i = 0; i < curElements.size(); i++) {
1453                            Element curElement = curElements.get(i);
1454    
1455                            _mergeArticleContentDelete(curElement, newDocument);
1456    
1457                            String instanceId = curElement.attributeValue("instance-id");
1458    
1459                            Element newElement = _getElementByInstanceId(
1460                                    newDocument, instanceId);
1461    
1462                            if (newElement == null) {
1463                                    curElement.detach();
1464                            }
1465                    }
1466            }
1467    
1468            private static void _mergeArticleContentUpdate(
1469                            Document curDocument, Element newParentElement, Element newElement,
1470                            int pos, String defaultLocale)
1471                    throws Exception {
1472    
1473                    _mergeArticleContentUpdate(curDocument, newElement, defaultLocale);
1474    
1475                    String instanceId = newElement.attributeValue("instance-id");
1476    
1477                    Element curElement = _getElementByInstanceId(curDocument, instanceId);
1478    
1479                    if (curElement != null) {
1480                            _mergeArticleContentUpdate(curElement, newElement, defaultLocale);
1481                    }
1482                    else {
1483                            String parentInstanceId = newParentElement.attributeValue(
1484                                    "instance-id");
1485    
1486                            if (Validator.isNull(parentInstanceId)) {
1487                                    Element curRoot = curDocument.getRootElement();
1488    
1489                                    List<Element> curRootElements = curRoot.elements();
1490    
1491                                    curRootElements.add(pos, newElement.createCopy());
1492                            }
1493                            else {
1494                                    Element curParentElement = _getElementByInstanceId(
1495                                            curDocument, parentInstanceId);
1496    
1497                                    if (curParentElement != null) {
1498                                            List<Element> curParentElements =
1499                                                    curParentElement.elements();
1500    
1501                                            curParentElements.add(pos, newElement.createCopy());
1502                                    }
1503                            }
1504                    }
1505            }
1506    
1507            private static void _mergeArticleContentUpdate(
1508                            Document curDocument, Element newParentElement,
1509                            String defaultLocale)
1510                    throws Exception {
1511    
1512                    List<Element> newElements = newParentElement.elements(
1513                            "dynamic-element");
1514    
1515                    for (int i = 0; i < newElements.size(); i++) {
1516                            Element newElement = newElements.get(i);
1517    
1518                            _mergeArticleContentUpdate(
1519                                    curDocument, newParentElement, newElement, i, defaultLocale);
1520                    }
1521            }
1522    
1523            private static void _mergeArticleContentUpdate(
1524                    Element curElement, Element newElement, String defaultLocale) {
1525    
1526                    Attribute curTypeAttribute = curElement.attribute("type");
1527                    Attribute newTypeAttribute = newElement.attribute("type");
1528    
1529                    curTypeAttribute.setValue(newTypeAttribute.getValue());
1530    
1531                    Attribute curIndexTypeAttribute = curElement.attribute("index-type");
1532                    Attribute newIndexTypeAttribute = newElement.attribute("index-type");
1533    
1534                    if (newIndexTypeAttribute != null) {
1535                            if (curIndexTypeAttribute == null) {
1536                                    curElement.addAttribute(
1537                                            "index-type", newIndexTypeAttribute.getValue());
1538                            }
1539                            else {
1540                                    curIndexTypeAttribute.setValue(
1541                                            newIndexTypeAttribute.getValue());
1542                            }
1543                    }
1544    
1545                    List<Element> elements = newElement.elements("dynamic-content");
1546    
1547                    if ((elements == null) || elements.isEmpty()) {
1548                            return;
1549                    }
1550    
1551                    Element newContentElement = elements.get(0);
1552    
1553                    String newLanguageId = newContentElement.attributeValue("language-id");
1554                    String newValue = newContentElement.getText();
1555    
1556                    String indexType = newElement.attributeValue("index-type");
1557    
1558                    if (Validator.isNotNull(indexType)) {
1559                            curElement.addAttribute("index-type", indexType);
1560                    }
1561    
1562                    List<Element> curContentElements = curElement.elements(
1563                            "dynamic-content");
1564    
1565                    if (Validator.isNull(newLanguageId)) {
1566                            for (Element curContentElement : curContentElements) {
1567                                    curContentElement.detach();
1568                            }
1569    
1570                            Element curContentElement = SAXReaderUtil.createElement(
1571                                    "dynamic-content");
1572    
1573                            if (newContentElement.element("option") != null) {
1574                                    _addElementOptions(curContentElement, newContentElement);
1575                            }
1576                            else {
1577                                    curContentElement.addCDATA(newValue);
1578                            }
1579    
1580                            curElement.add(curContentElement);
1581                    }
1582                    else {
1583                            boolean alreadyExists = false;
1584    
1585                            for (Element curContentElement : curContentElements) {
1586                                    String curLanguageId = curContentElement.attributeValue(
1587                                            "language-id");
1588    
1589                                    if (newLanguageId.equals(curLanguageId)) {
1590                                            alreadyExists = true;
1591    
1592                                            curContentElement.clearContent();
1593    
1594                                            if (newContentElement.element("option") != null) {
1595                                                    _addElementOptions(
1596                                                            curContentElement, newContentElement);
1597                                            }
1598                                            else {
1599                                                    curContentElement.addCDATA(newValue);
1600                                            }
1601    
1602                                            break;
1603                                    }
1604                            }
1605    
1606                            if (!alreadyExists) {
1607                                    Element curContentElement = curContentElements.get(0);
1608    
1609                                    String curLanguageId = curContentElement.attributeValue(
1610                                            "language-id");
1611    
1612                                    if (Validator.isNull(curLanguageId)) {
1613                                            if (newLanguageId.equals(defaultLocale)) {
1614                                                    curContentElement.clearContent();
1615    
1616                                                    if (newContentElement.element("option") != null) {
1617                                                            _addElementOptions(
1618                                                                    curContentElement, newContentElement);
1619                                                    }
1620                                                    else {
1621                                                            curContentElement.addCDATA(newValue);
1622                                                    }
1623                                            }
1624                                            else {
1625                                                    curElement.add(newContentElement.createCopy());
1626                                            }
1627    
1628                                            curContentElement.addAttribute(
1629                                                    "language-id", defaultLocale);
1630                                    }
1631                                    else {
1632                                            curElement.add(newContentElement.createCopy());
1633                                    }
1634                            }
1635                    }
1636            }
1637    
1638            private static void _populateCustomTokens(Map<String, String> tokens) {
1639                    if (_customTokens == null) {
1640                            synchronized (JournalUtil.class) {
1641                                    _customTokens = new HashMap<String, String>();
1642    
1643                                    for (String customToken :
1644                                                    PropsValues.JOURNAL_ARTICLE_CUSTOM_TOKENS) {
1645    
1646                                            String value = PropsUtil.get(
1647                                                    PropsKeys.JOURNAL_ARTICLE_CUSTOM_TOKEN_VALUE,
1648                                                    new Filter(customToken));
1649    
1650                                            _customTokens.put(customToken, value);
1651                                    }
1652                            }
1653                    }
1654    
1655                    if (!_customTokens.isEmpty()) {
1656                            tokens.putAll(_customTokens);
1657                    }
1658            }
1659    
1660            private static void _populateTokens(
1661                            Map<String, String> tokens, long articleGroupId, String xmlRequest)
1662                    throws Exception {
1663    
1664                    Document requestDocument = SAXReaderUtil.read(xmlRequest);
1665    
1666                    Element rootElement = requestDocument.getRootElement();
1667    
1668                    Element themeDisplayElement = rootElement.element("theme-display");
1669    
1670                    Layout layout = LayoutLocalServiceUtil.getLayout(
1671                            GetterUtil.getLong(themeDisplayElement.elementText("plid")));
1672    
1673                    Group group = layout.getGroup();
1674    
1675                    LayoutSet layoutSet = layout.getLayoutSet();
1676    
1677                    String friendlyUrlCurrent = null;
1678    
1679                    if (layout.isPublicLayout()) {
1680                            friendlyUrlCurrent = themeDisplayElement.elementText(
1681                                    "path-friendly-url-public");
1682                    }
1683                    else if (group.isUserGroup()) {
1684                            friendlyUrlCurrent = themeDisplayElement.elementText(
1685                                    "path-friendly-url-private-user");
1686                    }
1687                    else {
1688                            friendlyUrlCurrent = themeDisplayElement.elementText(
1689                                    "path-friendly-url-private-group");
1690                    }
1691    
1692                    String layoutSetFriendlyUrl = themeDisplayElement.elementText(
1693                            "i18n-path");
1694    
1695                    String virtualHostname = layoutSet.getVirtualHostname();
1696    
1697                    if (Validator.isNull(virtualHostname) ||
1698                            !virtualHostname.equals(
1699                                    themeDisplayElement.elementText("server-name"))) {
1700    
1701                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1702                    }
1703    
1704                    tokens.put("article_group_id", String.valueOf(articleGroupId));
1705                    tokens.put("cdn_host", themeDisplayElement.elementText("cdn-host"));
1706                    tokens.put("company_id", themeDisplayElement.elementText("company-id"));
1707                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1708                    tokens.put(
1709                            "friendly_url_private_group",
1710                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1711                    tokens.put(
1712                            "friendly_url_private_user",
1713                            themeDisplayElement.elementText("path-friendly-url-private-user"));
1714                    tokens.put(
1715                            "friendly_url_public",
1716                            themeDisplayElement.elementText("path-friendly-url-public"));
1717                    tokens.put("group_friendly_url", group.getFriendlyURL());
1718                    tokens.put("image_path", themeDisplayElement.elementText("path-image"));
1719                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1720                    tokens.put("main_path", themeDisplayElement.elementText("path-main"));
1721                    tokens.put(
1722                            "portal_ctx", themeDisplayElement.elementText("path-context"));
1723                    tokens.put(
1724                            "portal_url",
1725                            HttpUtil.removeProtocol(
1726                                    themeDisplayElement.elementText("url-portal")));
1727                    tokens.put(
1728                            "protocol",
1729                            HttpUtil.getProtocol(
1730                                    themeDisplayElement.elementText("url-portal")));
1731                    tokens.put(
1732                            "root_path", themeDisplayElement.elementText("path-context"));
1733                    tokens.put(
1734                            "scope_group_id",
1735                            themeDisplayElement.elementText("scope-group-id"));
1736                    tokens.put(
1737                            "site_group_id", themeDisplayElement.elementText("site-group-id"));
1738                    tokens.put(
1739                            "theme_image_path",
1740                            themeDisplayElement.elementText("path-theme-images"));
1741    
1742                    _populateCustomTokens(tokens);
1743    
1744                    // Deprecated tokens
1745    
1746                    tokens.put(
1747                            "friendly_url",
1748                            themeDisplayElement.elementText("path-friendly-url-public"));
1749                    tokens.put(
1750                            "friendly_url_private",
1751                            themeDisplayElement.elementText("path-friendly-url-private-group"));
1752                    tokens.put("group_id", String.valueOf(articleGroupId));
1753                    tokens.put(
1754                            "page_url",
1755                            themeDisplayElement.elementText("path-friendly-url-public"));
1756            }
1757    
1758            private static void _populateTokens(
1759                            Map<String, String> tokens, long articleGroupId,
1760                            ThemeDisplay themeDisplay)
1761                    throws PortalException, SystemException {
1762    
1763                    Layout layout = themeDisplay.getLayout();
1764    
1765                    Group group = layout.getGroup();
1766    
1767                    LayoutSet layoutSet = layout.getLayoutSet();
1768    
1769                    String friendlyUrlCurrent = null;
1770    
1771                    if (layout.isPublicLayout()) {
1772                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPublic();
1773                    }
1774                    else if (group.isUserGroup()) {
1775                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateUser();
1776                    }
1777                    else {
1778                            friendlyUrlCurrent = themeDisplay.getPathFriendlyURLPrivateGroup();
1779                    }
1780    
1781                    String layoutSetFriendlyUrl = themeDisplay.getI18nPath();
1782    
1783                    String virtualHostname = layoutSet.getVirtualHostname();
1784    
1785                    if (Validator.isNull(virtualHostname) ||
1786                            !virtualHostname.equals(themeDisplay.getServerName())) {
1787    
1788                            layoutSetFriendlyUrl = friendlyUrlCurrent + group.getFriendlyURL();
1789                    }
1790    
1791                    tokens.put("article_group_id", String.valueOf(articleGroupId));
1792                    tokens.put("cdn_host", themeDisplay.getCDNHost());
1793                    tokens.put("company_id", String.valueOf(themeDisplay.getCompanyId()));
1794                    tokens.put("friendly_url_current", friendlyUrlCurrent);
1795                    tokens.put(
1796                            "friendly_url_private_group",
1797                            themeDisplay.getPathFriendlyURLPrivateGroup());
1798                    tokens.put(
1799                            "friendly_url_private_user",
1800                            themeDisplay.getPathFriendlyURLPrivateUser());
1801                    tokens.put(
1802                            "friendly_url_public", themeDisplay.getPathFriendlyURLPublic());
1803                    tokens.put("group_friendly_url", group.getFriendlyURL());
1804                    tokens.put("image_path", themeDisplay.getPathImage());
1805                    tokens.put("layout_set_friendly_url", layoutSetFriendlyUrl);
1806                    tokens.put("main_path", themeDisplay.getPathMain());
1807                    tokens.put("portal_ctx", themeDisplay.getPathContext());
1808                    tokens.put(
1809                            "portal_url", HttpUtil.removeProtocol(themeDisplay.getURLPortal()));
1810                    tokens.put(
1811                            "protocol", HttpUtil.getProtocol(themeDisplay.getURLPortal()));
1812                    tokens.put("root_path", themeDisplay.getPathContext());
1813                    tokens.put(
1814                            "site_group_id", String.valueOf(themeDisplay.getSiteGroupId()));
1815                    tokens.put(
1816                            "scope_group_id", String.valueOf(themeDisplay.getScopeGroupId()));
1817                    tokens.put("theme_image_path", themeDisplay.getPathThemeImages());
1818    
1819                    _populateCustomTokens(tokens);
1820    
1821                    // Deprecated tokens
1822    
1823                    tokens.put("friendly_url", themeDisplay.getPathFriendlyURLPublic());
1824                    tokens.put(
1825                            "friendly_url_private",
1826                            themeDisplay.getPathFriendlyURLPrivateGroup());
1827                    tokens.put("group_id", String.valueOf(articleGroupId));
1828                    tokens.put("page_url", themeDisplay.getPathFriendlyURLPublic());
1829            }
1830    
1831            private static void _removeOldContent(
1832                            Stack<String> path, Element contentElement, Document xsdDocument)
1833                    throws SystemException {
1834    
1835                    String elementPath = "";
1836    
1837                    for (int i = 0; i < path.size(); i++) {
1838                            elementPath += "/" + path.elementAt(i);
1839                    }
1840    
1841                    for (int i = 0; i < contentElement.nodeCount(); i++) {
1842                            Node contentNode = contentElement.node(i);
1843    
1844                            if (contentNode instanceof Element) {
1845                                    _removeOldContent(
1846                                            path, (Element)contentNode, xsdDocument, elementPath);
1847                            }
1848                    }
1849            }
1850    
1851            private static void _removeOldContent(
1852                            Stack<String> path, Element contentElement, Document xsdDocument,
1853                            String elementPath)
1854                    throws SystemException {
1855    
1856                    String name = contentElement.attributeValue("name");
1857    
1858                    if (Validator.isNull(name)) {
1859                            return;
1860                    }
1861    
1862                    String localPath =
1863                            "dynamic-element[@name=" + HtmlUtil.escapeXPathAttribute(name) +
1864                                    "]";
1865    
1866                    String fullPath = elementPath + "/" + localPath;
1867    
1868                    XPath xPathSelector = SAXReaderUtil.createXPath(fullPath);
1869    
1870                    List<Node> curNodes = xPathSelector.selectNodes(xsdDocument);
1871    
1872                    if (curNodes.size() == 0) {
1873                            contentElement.detach();
1874                    }
1875    
1876                    path.push(localPath);
1877    
1878                    _removeOldContent(path, contentElement, xsdDocument);
1879    
1880                    path.pop();
1881            }
1882    
1883            private static Log _log = LogFactoryUtil.getLog(JournalUtil.class);
1884    
1885            private static Map<String, String> _customTokens;
1886            private static Pattern _friendlyURLPattern = Pattern.compile("[^a-z0-9_-]");
1887            private static Transformer _transformer = new Transformer(
1888                    PropsKeys.JOURNAL_TRANSFORMER_LISTENER,
1889                    PropsKeys.JOURNAL_ERROR_TEMPLATE, true);
1890    
1891    }