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