001
014
015 package com.liferay.portlet.wiki.util;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.exception.PortalException;
019 import com.liferay.portal.kernel.exception.SystemException;
020 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
021 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
022 import com.liferay.portal.kernel.util.CharPool;
023 import com.liferay.portal.kernel.util.DiffHtmlUtil;
024 import com.liferay.portal.kernel.util.GetterUtil;
025 import com.liferay.portal.kernel.util.HttpUtil;
026 import com.liferay.portal.kernel.util.InstancePool;
027 import com.liferay.portal.kernel.util.ListUtil;
028 import com.liferay.portal.kernel.util.OrderByComparator;
029 import com.liferay.portal.kernel.util.PropsKeys;
030 import com.liferay.portal.kernel.util.StringBundler;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.kernel.util.StringUtil;
033 import com.liferay.portal.kernel.util.Validator;
034 import com.liferay.portal.security.permission.ActionKeys;
035 import com.liferay.portal.security.permission.PermissionChecker;
036 import com.liferay.portal.theme.ThemeDisplay;
037 import com.liferay.portal.util.ContentUtil;
038 import com.liferay.portal.util.PropsUtil;
039 import com.liferay.portal.util.PropsValues;
040 import com.liferay.portal.util.WebKeys;
041 import com.liferay.portlet.wiki.PageContentException;
042 import com.liferay.portlet.wiki.WikiFormatException;
043 import com.liferay.portlet.wiki.engines.WikiEngine;
044 import com.liferay.portlet.wiki.model.WikiNode;
045 import com.liferay.portlet.wiki.model.WikiPage;
046 import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
047 import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
048 import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
049 import com.liferay.portlet.wiki.util.comparator.PageTitleComparator;
050 import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
051
052 import java.io.IOException;
053
054 import java.util.ArrayList;
055 import java.util.Arrays;
056 import java.util.Collections;
057 import java.util.HashMap;
058 import java.util.Iterator;
059 import java.util.List;
060 import java.util.Map;
061 import java.util.regex.Matcher;
062 import java.util.regex.Pattern;
063
064 import javax.portlet.PortletPreferences;
065 import javax.portlet.PortletRequest;
066 import javax.portlet.PortletURL;
067
068
072 public class WikiUtil {
073
074 public static final String POP_PORTLET_PREFIX = "wiki.";
075
076 public static String convert(
077 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
078 String attachmentURLPrefix)
079 throws PageContentException, WikiFormatException {
080
081 return _instance._convert(
082 page, viewPageURL, editPageURL, attachmentURLPrefix);
083 }
084
085 public static String decodeJSPWikiName(String jspWikiName) {
086 return StringUtil.replace(
087 jspWikiName, _JSP_WIKI_NAME_2, _JSP_WIKI_NAME_1);
088 }
089
090 public static String diffHtml (
091 WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
092 PortletURL editPageURL, String attachmentURLPrefix)
093 throws Exception {
094
095 String sourceContent = StringPool.BLANK;
096 String targetContent = StringPool.BLANK;
097
098 if (sourcePage != null) {
099 sourceContent = WikiUtil.convert(
100 sourcePage, viewPageURL, editPageURL,attachmentURLPrefix);
101 }
102
103 if (targetPage != null) {
104 targetContent = WikiUtil.convert(
105 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
106 }
107
108 return DiffHtmlUtil.diff(
109 new UnsyncStringReader(sourceContent),
110 new UnsyncStringReader(targetContent));
111 }
112
113 public static String encodeJSPWikiContent(String content) {
114 String newContent = content;
115
116 Matcher matcher = _wikiLinkPattern.matcher(content);
117
118 while (matcher.find()) {
119 String link = matcher.group();
120 String linkValues = matcher.group(1);
121
122 int index = linkValues.indexOf(CharPool.PIPE);
123
124 String name = linkValues;
125 String url = linkValues;
126
127 if (index != -1) {
128 name = linkValues.substring(index + 1, linkValues.length());
129 url = linkValues.substring(0, index);
130 }
131
132 String newLink = "[[" + encodeJSPWikiName(url) + "|" + name + "]]";
133
134 newContent = StringUtil.replace(newContent, link, newLink);
135 }
136
137 return newContent;
138 }
139
140 public static String encodeJSPWikiName(String name) {
141 if (name == null) {
142 return StringPool.BLANK;
143 }
144
145 return StringUtil.replace(name, _JSP_WIKI_NAME_1, _JSP_WIKI_NAME_2);
146 }
147
148 public static String getEditPage(String format) {
149 return _instance._getEditPage(format);
150 }
151
152 public static String getEmailFromAddress(PortletPreferences preferences) {
153 String emailFromAddress = PropsUtil.get(
154 PropsKeys.WIKI_EMAIL_FROM_ADDRESS);
155
156 return preferences.getValue("email-from-address", emailFromAddress);
157 }
158
159 public static String getEmailFromName(PortletPreferences preferences) {
160 String emailFromName = PropsUtil.get(PropsKeys.WIKI_EMAIL_FROM_NAME);
161
162 return preferences.getValue("email-from-name", emailFromName);
163 }
164
165 public static boolean getEmailPageAddedEnabled(
166 PortletPreferences preferences) {
167
168 String emailPageAddedEnabled = preferences.getValue(
169 "email-page-added-enabled", StringPool.BLANK);
170
171 if (Validator.isNotNull(emailPageAddedEnabled)) {
172 return GetterUtil.getBoolean(emailPageAddedEnabled);
173 }
174 else {
175 return GetterUtil.getBoolean(PropsUtil.get(
176 PropsKeys.WIKI_EMAIL_PAGE_ADDED_ENABLED));
177 }
178 }
179
180 public static String getEmailPageAddedBody(PortletPreferences preferences) {
181 String emailPageAddedBody = preferences.getValue(
182 "email-page-added-body", StringPool.BLANK);
183
184 if (Validator.isNotNull(emailPageAddedBody)) {
185 return emailPageAddedBody;
186 }
187 else {
188 return ContentUtil.get(PropsUtil.get(
189 PropsKeys.WIKI_EMAIL_PAGE_ADDED_BODY));
190 }
191 }
192
193 public static String getEmailPageAddedSignature(
194 PortletPreferences preferences) {
195
196 String emailPageAddedSignature = preferences.getValue(
197 "email-page-added-signature", StringPool.BLANK);
198
199 if (Validator.isNotNull(emailPageAddedSignature)) {
200 return emailPageAddedSignature;
201 }
202 else {
203 return ContentUtil.get(PropsUtil.get(
204 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
205 }
206 }
207
208 public static String getEmailPageAddedSubjectPrefix(
209 PortletPreferences preferences) {
210
211 String emailPageAddedSubjectPrefix = preferences.getValue(
212 "email-page-added-subject-prefix", StringPool.BLANK);
213
214 if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
215 return emailPageAddedSubjectPrefix;
216 }
217 else {
218 return ContentUtil.get(PropsUtil.get(
219 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
220 }
221 }
222
223 public static boolean getEmailPageUpdatedEnabled(
224 PortletPreferences preferences) {
225
226 String emailPageUpdatedEnabled = preferences.getValue(
227 "email-page-updated-enabled", StringPool.BLANK);
228
229 if (Validator.isNotNull(emailPageUpdatedEnabled)) {
230 return GetterUtil.getBoolean(emailPageUpdatedEnabled);
231 }
232 else {
233 return GetterUtil.getBoolean(PropsUtil.get(
234 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
235 }
236 }
237
238 public static String getEmailPageUpdatedBody(
239 PortletPreferences preferences) {
240
241 String emailPageUpdatedBody = preferences.getValue(
242 "email-page-updated-body", StringPool.BLANK);
243
244 if (Validator.isNotNull(emailPageUpdatedBody)) {
245 return emailPageUpdatedBody;
246 }
247 else {
248 return ContentUtil.get(PropsUtil.get(
249 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
250 }
251 }
252
253 public static String getEmailPageUpdatedSignature(
254 PortletPreferences preferences) {
255
256 String emailPageUpdatedSignature = preferences.getValue(
257 "email-page-updated-signature", StringPool.BLANK);
258
259 if (Validator.isNotNull(emailPageUpdatedSignature)) {
260 return emailPageUpdatedSignature;
261 }
262 else {
263 return ContentUtil.get(PropsUtil.get(
264 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
265 }
266 }
267
268 public static String getEmailPageUpdatedSubjectPrefix(
269 PortletPreferences preferences) {
270
271 String emailPageUpdatedSubject = preferences.getValue(
272 "email-page-updated-subject-prefix", StringPool.BLANK);
273
274 if (Validator.isNotNull(emailPageUpdatedSubject)) {
275 return emailPageUpdatedSubject;
276 }
277 else {
278 return ContentUtil.get(PropsUtil.get(
279 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
280 }
281 }
282
283 public static WikiNode getFirstNode(PortletRequest portletRequest)
284 throws PortalException, SystemException {
285
286 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
287 WebKeys.THEME_DISPLAY);
288 long groupId = themeDisplay.getScopeGroupId();
289 PermissionChecker permissionChecker =
290 themeDisplay.getPermissionChecker();
291
292 List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
293
294 PortletPreferences preferences = portletRequest.getPreferences();
295 String[] visibleNodeNames =
296 StringUtil.split(preferences.getValue("visible-nodes", null));
297 nodes = orderNodes(nodes, visibleNodeNames);
298
299 String[] hiddenNodes = StringUtil.split(
300 preferences.getValue("hidden-nodes", StringPool.BLANK));
301 Arrays.sort(hiddenNodes);
302
303 for(WikiNode node : nodes) {
304 if ((Arrays.binarySearch(hiddenNodes, node.getName()) < 0) &&
305 (WikiNodePermission.contains(permissionChecker, node,
306 ActionKeys.VIEW))) {
307 return node;
308 }
309 }
310 return null;
311 }
312
313 public static String getHelpPage(String format) {
314 return _instance._getHelpPage(format);
315 }
316
317 public static String getHelpURL(String format) {
318 return _instance._getHelpURL(format);
319 }
320
321 public static Map<String, Boolean> getLinks(WikiPage page)
322 throws PageContentException {
323
324 return _instance._getLinks(page);
325 }
326
327 public static String getMailId(String mx, long nodeId, long pageId) {
328 StringBundler sb = new StringBundler(10);
329
330 sb.append(StringPool.LESS_THAN);
331 sb.append(POP_PORTLET_PREFIX);
332 sb.append(nodeId);
333 sb.append(StringPool.PERIOD);
334 sb.append(pageId);
335 sb.append(StringPool.AT);
336 sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
337 sb.append(StringPool.PERIOD);
338 sb.append(mx);
339 sb.append(StringPool.GREATER_THAN);
340
341 return sb.toString();
342 }
343
344 public static List<String> getNodeNames(List<WikiNode> nodes) {
345 List<String> nodeNames = new ArrayList<String>(nodes.size());
346
347 for (WikiNode node : nodes) {
348 nodeNames.add(node.getName());
349 }
350
351 return nodeNames;
352 }
353
354 public static List<WikiNode> getNodes(
355 List<WikiNode> nodes, String[] hiddenNodes,
356 PermissionChecker permissionChecker) {
357
358 nodes = ListUtil.copy(nodes);
359
360 Arrays.sort(hiddenNodes);
361
362 Iterator<WikiNode> itr = nodes.iterator();
363
364 while (itr.hasNext()) {
365 WikiNode node = itr.next();
366
367 if (!(Arrays.binarySearch(hiddenNodes, node.getName()) < 0) ||
368 !WikiNodePermission.contains(
369 permissionChecker, node, ActionKeys.VIEW)) {
370
371 itr.remove();
372 }
373 }
374
375 return nodes;
376 }
377
378 public static OrderByComparator getPageOrderByComparator(
379 String orderByCol, String orderByType) {
380
381 boolean orderByAsc = false;
382
383 if (orderByType.equals("asc")) {
384 orderByAsc = true;
385 }
386
387 OrderByComparator orderByComparator = null;
388
389 if (orderByCol.equals("modifiedDate")) {
390 orderByComparator = new PageCreateDateComparator(orderByAsc);
391 }
392 else if (orderByCol.equals("title")) {
393 orderByComparator = new PageTitleComparator(orderByAsc);
394 }
395 else if (orderByCol.equals("version")) {
396 orderByComparator = new PageVersionComparator(orderByAsc);
397 }
398
399 return orderByComparator;
400 }
401
402 public static List<WikiNode> orderNodes(
403 List<WikiNode> nodes, String[] visibleNodeNames) {
404
405 if ((visibleNodeNames == null) || (visibleNodeNames.length == 0)) {
406 return nodes;
407 }
408
409 nodes = ListUtil.copy(nodes);
410
411 List<WikiNode> orderedNodes = new ArrayList<WikiNode>(nodes.size());
412
413 for (String visibleNodeName : visibleNodeNames) {
414 for (WikiNode node : nodes) {
415 if (node.getName().equals(visibleNodeName)) {
416 orderedNodes.add(node);
417
418 nodes.remove(node);
419
420 break;
421 }
422 }
423 }
424
425 orderedNodes.addAll(nodes);
426
427 return orderedNodes;
428 }
429
430 public static String processContent(String content) {
431 content = content.replaceAll("</p>", "</p>\n");
432 content = content.replaceAll("</br>", "</br>\n");
433 content = content.replaceAll("</div>", "</div>\n");
434
435 return content;
436 }
437
438 public static boolean validate(
439 long nodeId, String content, String format)
440 throws WikiFormatException {
441
442 return _instance._validate(nodeId, content, format);
443 }
444
445 private static String _decodeJSPWikiContent(String jspWikiContent) {
446 return StringUtil.replace(
447 jspWikiContent, _JSP_WIKI_NAME_2, _JSP_WIKI_NAME_1);
448 }
449
450 private String _convert(
451 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
452 String attachmentURLPrefix)
453 throws PageContentException, WikiFormatException {
454
455 LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
456 LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
457
458 WikiEngine engine = _getEngine(page.getFormat());
459
460 String content = engine.convert(page, editPageURL);
461
462 String editPageURLString = StringPool.BLANK;
463
464 if (editPageURL != null) {
465 liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
466
467 editPageURLString = editPageURL.toString();
468
469 editPageURLString = StringUtil.replace(
470 editPageURLString, "__REPLACEMENT__", "$1");
471 }
472
473 Matcher matcher = _editPageURLPattern.matcher(content);
474
475 content = matcher.replaceAll(editPageURLString);
476
477 String viewPageURLString = StringPool.BLANK;
478
479 if (viewPageURL != null) {
480 liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
481
482 viewPageURLString = viewPageURL.toString();
483
484 viewPageURLString = StringUtil.replace(
485 viewPageURLString, "__REPLACEMENT__", "$1");
486 }
487
488 matcher = _viewPageURLPattern.matcher(content);
489
490 content = matcher.replaceAll(viewPageURLString);
491
492 content = _replaceAttachments(
493 content, page.getTitle(), attachmentURLPrefix);
494
495 content = _decodeJSPWikiContent(content);
496
497 return content;
498 }
499
500 private String _getEditPage(String format) {
501 return PropsUtil.get(
502 PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
503 }
504
505 private WikiEngine _getEngine(String format) throws WikiFormatException {
506 WikiEngine engine = _engines.get(format);
507
508 if (engine == null) {
509 try {
510 String engineClass = PropsUtil.get(
511 PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
512
513 if (engineClass != null) {
514 if (!InstancePool.contains(engineClass)) {
515 engine = (WikiEngine)InstancePool.get(engineClass);
516
517 engine.setMainConfiguration(
518 _readConfigurationFile(
519 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN,
520 format));
521
522 engine.setInterWikiConfiguration(
523 _readConfigurationFile(
524 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
525 format));
526 }
527 else {
528 engine = (WikiEngine)InstancePool.get(engineClass);
529 }
530
531 _engines.put(format, engine);
532 }
533 }
534 catch (Exception e) {
535 throw new WikiFormatException(e);
536 }
537
538 if (engine == null) {
539 throw new WikiFormatException(format);
540 }
541 }
542
543 return engine;
544 }
545
546 private String _getHelpPage(String format) {
547 return PropsUtil.get(
548 PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
549 }
550
551 private String _getHelpURL(String format) {
552 return PropsUtil.get(
553 PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
554 }
555
556 private Map<String, Boolean> _getLinks(WikiPage page)
557 throws PageContentException {
558
559 try {
560 return _getEngine(page.getFormat()).getOutgoingLinks(page);
561 }
562 catch (WikiFormatException wfe) {
563 return Collections.EMPTY_MAP;
564 }
565 }
566
567 private String _readConfigurationFile(String propertyName, String format)
568 throws IOException {
569
570 ClassLoader classLoader = getClass().getClassLoader();
571
572 String configurationFile = PropsUtil.get(
573 propertyName, new Filter(format));
574
575 if (Validator.isNotNull(configurationFile)) {
576 return HttpUtil.URLtoString(
577 classLoader.getResource(configurationFile));
578 }
579 else {
580 return StringPool.BLANK;
581 }
582 }
583
584 private String _replaceAttachments(
585 String content, String title, String attachmentURLPrefix) {
586
587 content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
588
589 content = StringUtil.replace(
590 content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
591
592 return content;
593 }
594
595 private boolean _validate(long nodeId, String content, String format)
596 throws WikiFormatException {
597
598 return _getEngine(format).validate(nodeId, content);
599 }
600
601 private static final String[] _JSP_WIKI_NAME_1 = {
602 StringPool.APOSTROPHE, StringPool.AT, StringPool.CARET,
603 StringPool.EXCLAMATION, StringPool.INVERTED_EXCLAMATION,
604 StringPool.INVERTED_QUESTION, StringPool.GRAVE_ACCENT,
605 StringPool.QUESTION, StringPool.SLASH, StringPool.STAR
606 };
607
608 private static final String[] _JSP_WIKI_NAME_2 = {
609 "__APO__", "__AT__", "__CAR__", "__EXM__", "__INE__", "__INQ__",
610 "__GRA__", "__QUE__", "__SLA__", "__STA__"
611 };
612
613 private static WikiUtil _instance = new WikiUtil();
614
615 private static Pattern _editPageURLPattern = Pattern.compile(
616 "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
617 private static Pattern _viewPageURLPattern = Pattern.compile(
618 "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
619 private static Pattern _wikiLinkPattern = Pattern.compile(
620 "[\\[]{2,2}(.+?)[\\]]{2,2}");
621
622 private Map<String, WikiEngine> _engines =
623 new HashMap<String, WikiEngine>();
624
625 }