1
14
15 package com.liferay.portlet.wiki.util;
16
17 import com.liferay.portal.SystemException;
18 import com.liferay.portal.kernel.configuration.Filter;
19 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
20 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
21 import com.liferay.portal.kernel.util.ArrayUtil;
22 import com.liferay.portal.kernel.util.DiffHtmlUtil;
23 import com.liferay.portal.kernel.util.GetterUtil;
24 import com.liferay.portal.kernel.util.HttpUtil;
25 import com.liferay.portal.kernel.util.InstancePool;
26 import com.liferay.portal.kernel.util.ListUtil;
27 import com.liferay.portal.kernel.util.PropsKeys;
28 import com.liferay.portal.kernel.util.StringBundler;
29 import com.liferay.portal.kernel.util.StringPool;
30 import com.liferay.portal.kernel.util.StringUtil;
31 import com.liferay.portal.kernel.util.Validator;
32 import com.liferay.portal.security.permission.ActionKeys;
33 import com.liferay.portal.security.permission.PermissionChecker;
34 import com.liferay.portal.theme.ThemeDisplay;
35 import com.liferay.portal.util.ContentUtil;
36 import com.liferay.portal.util.PropsUtil;
37 import com.liferay.portal.util.PropsValues;
38 import com.liferay.portal.util.WebKeys;
39 import com.liferay.portlet.wiki.PageContentException;
40 import com.liferay.portlet.wiki.WikiFormatException;
41 import com.liferay.portlet.wiki.engines.WikiEngine;
42 import com.liferay.portlet.wiki.model.WikiNode;
43 import com.liferay.portlet.wiki.model.WikiPage;
44 import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
45 import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
46
47 import java.io.IOException;
48
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.concurrent.ConcurrentHashMap;
55 import java.util.regex.Matcher;
56 import java.util.regex.Pattern;
57
58 import javax.portlet.PortletPreferences;
59 import javax.portlet.PortletRequest;
60 import javax.portlet.PortletURL;
61
62
68 public class WikiUtil {
69
70 public static final String POP_PORTLET_PREFIX = "wiki.";
71
72 public static String convert(
73 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
74 String attachmentURLPrefix)
75 throws PageContentException, WikiFormatException {
76
77 return _instance._convert(
78 page, viewPageURL, editPageURL, attachmentURLPrefix);
79 }
80
81 public static String diffHtml (
82 WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
83 PortletURL editPageURL, String attachmentURLPrefix)
84 throws Exception {
85
86 String sourceContent = StringPool.BLANK;
87 String targetContent = StringPool.BLANK;
88
89 if (sourcePage != null) {
90 sourceContent = WikiUtil.convert(
91 sourcePage, viewPageURL, editPageURL,attachmentURLPrefix);
92 }
93
94 if (targetPage != null) {
95 targetContent = WikiUtil.convert(
96 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
97 }
98
99 return DiffHtmlUtil.diff(
100 new UnsyncStringReader(sourceContent),
101 new UnsyncStringReader(targetContent));
102 }
103
104 public static String getEditPage(String format) {
105 return _instance._getEditPage(format);
106 }
107
108 public static String getEmailFromAddress(PortletPreferences preferences) {
109 String emailFromAddress = PropsUtil.get(
110 PropsKeys.WIKI_EMAIL_FROM_ADDRESS);
111
112 return preferences.getValue("email-from-address", emailFromAddress);
113 }
114
115 public static String getEmailFromName(PortletPreferences preferences) {
116 String emailFromName = PropsUtil.get(PropsKeys.WIKI_EMAIL_FROM_NAME);
117
118 return preferences.getValue("email-from-name", emailFromName);
119 }
120
121 public static String getEmailPageAddedBody(PortletPreferences preferences) {
122 String emailPageAddedBody = preferences.getValue(
123 "email-page-added-body", StringPool.BLANK);
124
125 if (Validator.isNotNull(emailPageAddedBody)) {
126 return emailPageAddedBody;
127 }
128 else {
129 return ContentUtil.get(PropsUtil.get(
130 PropsKeys.WIKI_EMAIL_PAGE_ADDED_BODY));
131 }
132 }
133
134 public static boolean getEmailPageAddedEnabled(
135 PortletPreferences preferences) {
136
137 String emailPageAddedEnabled = preferences.getValue(
138 "email-page-added-enabled", StringPool.BLANK);
139
140 if (Validator.isNotNull(emailPageAddedEnabled)) {
141 return GetterUtil.getBoolean(emailPageAddedEnabled);
142 }
143 else {
144 return GetterUtil.getBoolean(PropsUtil.get(
145 PropsKeys.WIKI_EMAIL_PAGE_ADDED_ENABLED));
146 }
147 }
148
149 public static String getEmailPageAddedSignature(
150 PortletPreferences preferences) {
151
152 String emailPageAddedSignature = preferences.getValue(
153 "email-page-added-signature", StringPool.BLANK);
154
155 if (Validator.isNotNull(emailPageAddedSignature)) {
156 return emailPageAddedSignature;
157 }
158 else {
159 return ContentUtil.get(PropsUtil.get(
160 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
161 }
162 }
163
164 public static String getEmailPageAddedSubjectPrefix(
165 PortletPreferences preferences) {
166
167 String emailPageAddedSubjectPrefix = preferences.getValue(
168 "email-page-added-subject-prefix", StringPool.BLANK);
169
170 if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
171 return emailPageAddedSubjectPrefix;
172 }
173 else {
174 return ContentUtil.get(PropsUtil.get(
175 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
176 }
177 }
178
179 public static String getEmailPageUpdatedBody(
180 PortletPreferences preferences) {
181
182 String emailPageUpdatedBody = preferences.getValue(
183 "email-page-updated-body", StringPool.BLANK);
184
185 if (Validator.isNotNull(emailPageUpdatedBody)) {
186 return emailPageUpdatedBody;
187 }
188 else {
189 return ContentUtil.get(PropsUtil.get(
190 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
191 }
192 }
193
194 public static boolean getEmailPageUpdatedEnabled(
195 PortletPreferences preferences) {
196
197 String emailPageUpdatedEnabled = preferences.getValue(
198 "email-page-updated-enabled", StringPool.BLANK);
199
200 if (Validator.isNotNull(emailPageUpdatedEnabled)) {
201 return GetterUtil.getBoolean(emailPageUpdatedEnabled);
202 }
203 else {
204 return GetterUtil.getBoolean(PropsUtil.get(
205 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
206 }
207 }
208
209 public static String getEmailPageUpdatedSignature(
210 PortletPreferences preferences) {
211
212 String emailPageUpdatedSignature = preferences.getValue(
213 "email-page-updated-signature", StringPool.BLANK);
214
215 if (Validator.isNotNull(emailPageUpdatedSignature)) {
216 return emailPageUpdatedSignature;
217 }
218 else {
219 return ContentUtil.get(PropsUtil.get(
220 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
221 }
222 }
223
224 public static String getEmailPageUpdatedSubjectPrefix(
225 PortletPreferences preferences) {
226
227 String emailPageUpdatedSubject = preferences.getValue(
228 "email-page-updated-subject-prefix", StringPool.BLANK);
229
230 if (Validator.isNotNull(emailPageUpdatedSubject)) {
231 return emailPageUpdatedSubject;
232 }
233 else {
234 return ContentUtil.get(PropsUtil.get(
235 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
236 }
237 }
238
239 public static String getHelpPage(String format) {
240 return _instance._getHelpPage(format);
241 }
242
243 public static String getHelpURL(String format) {
244 return _instance._getHelpURL(format);
245 }
246
247 public static Map<String, Boolean> getLinks(WikiPage page)
248 throws PageContentException {
249
250 return _instance._getLinks(page);
251 }
252
253 public static String getMailId(String mx, long nodeId, long pageId) {
254 StringBundler sb = new StringBundler(10);
255
256 sb.append(StringPool.LESS_THAN);
257 sb.append(POP_PORTLET_PREFIX);
258 sb.append(nodeId);
259 sb.append(StringPool.PERIOD);
260 sb.append(pageId);
261 sb.append(StringPool.AT);
262 sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
263 sb.append(StringPool.PERIOD);
264 sb.append(mx);
265 sb.append(StringPool.GREATER_THAN);
266
267 return sb.toString();
268 }
269
270 public static List<WikiNode> getNodes(PortletRequest portletRequest)
271 throws SystemException {
272
273 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
274 WebKeys.THEME_DISPLAY);
275
276 long groupId = themeDisplay.getScopeGroupId();
277
278 String allNodes = ListUtil.toString(
279 WikiNodeLocalServiceUtil.getNodes(groupId), "name");
280
281 PortletPreferences preferences = portletRequest.getPreferences();
282
283 String[] visibleNodes = StringUtil.split(
284 preferences.getValue("visible-nodes", allNodes));
285 String[] hiddenNodes = StringUtil.split(
286 preferences.getValue("hidden-nodes", StringPool.BLANK));
287
288 return getNodes(
289 groupId, visibleNodes, hiddenNodes,
290 themeDisplay.getPermissionChecker());
291 }
292
293 public static List<WikiNode> getNodes(
294 long groupId, String[] visibleNodes, String[] hiddenNodes,
295 PermissionChecker permissionChecker)
296 throws SystemException {
297
298 List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
299
300 nodes = ListUtil.copy(nodes);
301 nodes = _orderNodes(nodes, visibleNodes);
302
303 Iterator<WikiNode> itr = nodes.iterator();
304
305 while (itr.hasNext()) {
306 WikiNode node = itr.next();
307
308 if (ArrayUtil.contains(hiddenNodes, node.getName()) ||
309 !WikiNodePermission.contains(
310 permissionChecker, node, ActionKeys.VIEW)) {
311
312 itr.remove();
313 }
314 }
315
316 return nodes;
317 }
318
319 public static String processContent(String content) {
320 content = content.replaceAll("</p>", "</p>\n");
321 content = content.replaceAll("</br>", "</br>\n");
322 content = content.replaceAll("</div>", "</div>\n");
323
324 return content;
325 }
326
327 public static boolean validate(
328 long nodeId, String content, String format)
329 throws WikiFormatException {
330
331 return _instance._validate(nodeId, content, format);
332 }
333
334 private static List<WikiNode> _orderNodes(
335 List<WikiNode> nodes, String[] nodeNames) {
336
337 List<WikiNode> orderedNodes = new ArrayList<WikiNode>();
338
339 for (String nodeName : nodeNames) {
340 for (WikiNode node : nodes) {
341 if (node.getName().equals(nodeName)) {
342 orderedNodes.add(node);
343
344 nodes.remove(node);
345
346 break;
347 }
348 }
349 }
350
351 orderedNodes.addAll(nodes);
352
353 return orderedNodes;
354 }
355
356 private String _convert(
357 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
358 String attachmentURLPrefix)
359 throws PageContentException, WikiFormatException {
360
361 LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
362 LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
363
364 WikiEngine engine = _getEngine(page.getFormat());
365
366 String content = engine.convert(
367 page, viewPageURL, editPageURL, attachmentURLPrefix);
368
369 String editPageURLString = StringPool.BLANK;
370
371 if (editPageURL != null) {
372 liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
373
374 editPageURLString = editPageURL.toString();
375
376 editPageURLString = StringUtil.replace(
377 editPageURLString, "__REPLACEMENT__", "$1");
378 }
379
380 Matcher matcher = _editPageURLPattern.matcher(content);
381
382 content = _convertURLs(editPageURLString, matcher);
383
384 String viewPageURLString = StringPool.BLANK;
385
386 if (viewPageURL != null) {
387 liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
388
389 viewPageURLString = viewPageURL.toString();
390
391 viewPageURLString = StringUtil.replace(
392 viewPageURLString, "__REPLACEMENT__", "$1");
393 }
394
395 matcher = _viewPageURLPattern.matcher(content);
396
397 content = _convertURLs(viewPageURLString, matcher);
398
399 content = _replaceAttachments(
400 content, page.getTitle(), attachmentURLPrefix);
401
402 return content;
403 }
404
405 private String _convertURLs(String url, Matcher matcher) {
406 StringBuffer sb = new StringBuffer();
407
408 while (matcher.find()) {
409 String replacement = null;
410
411 if (matcher.groupCount() >= 1) {
412 String encodedTitle = HttpUtil.encodeURL(matcher.group(1));
413
414 replacement = url.replace("$1", encodedTitle);
415 }
416 else {
417 replacement = url;
418 }
419
420 matcher.appendReplacement(sb, replacement);
421 }
422
423 return matcher.appendTail(sb).toString();
424 }
425
426 private String _getEditPage(String format) {
427 return PropsUtil.get(
428 PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
429 }
430
431 private WikiEngine _getEngine(String format) throws WikiFormatException {
432 WikiEngine engine = _engines.get(format);
433
434 if (engine != null) {
435 return engine;
436 }
437
438 synchronized (_engines) {
439 engine = _engines.get(format);
440
441 if (engine != null) {
442 return engine;
443 }
444
445 try {
446 String engineClass = PropsUtil.get(
447 PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
448
449 if (engineClass == null) {
450 throw new WikiFormatException(format);
451 }
452
453 if (!InstancePool.contains(engineClass)) {
454 engine = (WikiEngine)InstancePool.get(engineClass);
455
456 engine.setMainConfiguration(
457 _readConfigurationFile(
458 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN, format));
459
460 engine.setInterWikiConfiguration(
461 _readConfigurationFile(
462 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
463 format));
464 }
465 else {
466 engine = (WikiEngine)InstancePool.get(engineClass);
467 }
468
469 _engines.put(format, engine);
470
471 return engine;
472 }
473 catch (Exception e) {
474 throw new WikiFormatException(e);
475 }
476 }
477 }
478
479 private String _getHelpPage(String format) {
480 return PropsUtil.get(
481 PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
482 }
483
484 private String _getHelpURL(String format) {
485 return PropsUtil.get(
486 PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
487 }
488
489 private Map<String, Boolean> _getLinks(WikiPage page)
490 throws PageContentException {
491
492 try {
493 return _getEngine(page.getFormat()).getOutgoingLinks(page);
494 }
495 catch (WikiFormatException wfe) {
496 return Collections.EMPTY_MAP;
497 }
498 }
499
500 private String _readConfigurationFile(String propertyName, String format)
501 throws IOException {
502
503 ClassLoader classLoader = getClass().getClassLoader();
504
505 String configurationFile = PropsUtil.get(
506 propertyName, new Filter(format));
507
508 if (Validator.isNotNull(configurationFile)) {
509 return HttpUtil.URLtoString(
510 classLoader.getResource(configurationFile));
511 }
512 else {
513 return StringPool.BLANK;
514 }
515 }
516
517 private String _replaceAttachments(
518 String content, String title, String attachmentURLPrefix) {
519
520 content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
521
522 content = StringUtil.replace(
523 content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
524
525 return content;
526 }
527
528 private boolean _validate(long nodeId, String content, String format)
529 throws WikiFormatException {
530
531 return _getEngine(format).validate(nodeId, content);
532 }
533
534 private static WikiUtil _instance = new WikiUtil();
535
536 private static Pattern _editPageURLPattern = Pattern.compile(
537 "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)" +
538 "\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
539 private static Pattern _viewPageURLPattern = Pattern.compile(
540 "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
541
542 private Map<String, WikiEngine> _engines =
543 new ConcurrentHashMap<String, WikiEngine>();
544
545 }