001
014
015 package com.liferay.portlet.wiki.util;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.dao.orm.QueryUtil;
019 import com.liferay.portal.kernel.diff.DiffHtmlUtil;
020 import com.liferay.portal.kernel.diff.DiffVersion;
021 import com.liferay.portal.kernel.diff.DiffVersionsInfo;
022 import com.liferay.portal.kernel.exception.PortalException;
023 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
024 import com.liferay.portal.kernel.language.LanguageUtil;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
028 import com.liferay.portal.kernel.search.Document;
029 import com.liferay.portal.kernel.search.Field;
030 import com.liferay.portal.kernel.search.Hits;
031 import com.liferay.portal.kernel.util.ArrayUtil;
032 import com.liferay.portal.kernel.util.GetterUtil;
033 import com.liferay.portal.kernel.util.HtmlUtil;
034 import com.liferay.portal.kernel.util.HttpUtil;
035 import com.liferay.portal.kernel.util.InstanceFactory;
036 import com.liferay.portal.kernel.util.ListUtil;
037 import com.liferay.portal.kernel.util.OrderByComparator;
038 import com.liferay.portal.kernel.util.ParamUtil;
039 import com.liferay.portal.kernel.util.PropsKeys;
040 import com.liferay.portal.kernel.util.StringBundler;
041 import com.liferay.portal.kernel.util.StringPool;
042 import com.liferay.portal.kernel.util.StringUtil;
043 import com.liferay.portal.kernel.util.Validator;
044 import com.liferay.portal.model.Company;
045 import com.liferay.portal.security.permission.ActionKeys;
046 import com.liferay.portal.security.permission.PermissionChecker;
047 import com.liferay.portal.theme.PortletDisplay;
048 import com.liferay.portal.theme.ThemeDisplay;
049 import com.liferay.portal.util.PortalUtil;
050 import com.liferay.portal.util.PropsUtil;
051 import com.liferay.portal.util.WebKeys;
052 import com.liferay.portlet.PortletURLUtil;
053 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
054 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
055 import com.liferay.portlet.messageboards.model.MBMessage;
056 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
057 import com.liferay.portlet.wiki.PageContentException;
058 import com.liferay.portlet.wiki.WikiFormatException;
059 import com.liferay.portlet.wiki.WikiPortletInstanceSettings;
060 import com.liferay.portlet.wiki.engines.WikiEngine;
061 import com.liferay.portlet.wiki.model.WikiNode;
062 import com.liferay.portlet.wiki.model.WikiPage;
063 import com.liferay.portlet.wiki.model.WikiPageDisplay;
064 import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
065 import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
066 import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
067 import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
068 import com.liferay.portlet.wiki.util.comparator.PageTitleComparator;
069 import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
070
071 import java.io.IOException;
072
073 import java.util.ArrayList;
074 import java.util.Arrays;
075 import java.util.Collections;
076 import java.util.HashSet;
077 import java.util.Iterator;
078 import java.util.LinkedHashMap;
079 import java.util.List;
080 import java.util.Map;
081 import java.util.Set;
082 import java.util.concurrent.ConcurrentHashMap;
083 import java.util.regex.Matcher;
084 import java.util.regex.Pattern;
085
086 import javax.portlet.PortletRequest;
087 import javax.portlet.PortletURL;
088 import javax.portlet.RenderRequest;
089 import javax.portlet.RenderResponse;
090
091 import javax.servlet.http.HttpServletRequest;
092
093
097 public class WikiUtil {
098
099 public static String convert(
100 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
101 String attachmentURLPrefix)
102 throws PageContentException, WikiFormatException {
103
104 return _instance._convert(
105 page, viewPageURL, editPageURL, attachmentURLPrefix);
106 }
107
108 public static String diffHtml(
109 WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
110 PortletURL editPageURL, String attachmentURLPrefix)
111 throws Exception {
112
113 String sourceContent = StringPool.BLANK;
114 String targetContent = StringPool.BLANK;
115
116 if (sourcePage != null) {
117 sourceContent = convert(
118 sourcePage, viewPageURL, editPageURL, attachmentURLPrefix);
119 }
120
121 if (targetPage != null) {
122 targetContent = convert(
123 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
124 }
125
126 return DiffHtmlUtil.diff(
127 new UnsyncStringReader(sourceContent),
128 new UnsyncStringReader(targetContent));
129 }
130
131 public static String escapeName(String name) {
132 return StringUtil.replace(name, _UNESCAPED_CHARS, _ESCAPED_CHARS);
133 }
134
135 public static List<WikiPage> filterOrphans(List<WikiPage> pages)
136 throws PortalException {
137
138 List<Map<String, Boolean>> pageTitles =
139 new ArrayList<Map<String, Boolean>>();
140
141 for (WikiPage page : pages) {
142 pageTitles.add(WikiCacheUtil.getOutgoingLinks(page));
143 }
144
145 Set<WikiPage> notOrphans = new HashSet<WikiPage>();
146
147 for (WikiPage page : pages) {
148 for (Map<String, Boolean> pageTitle : pageTitles) {
149 String pageTitleLowerCase = page.getTitle();
150
151 pageTitleLowerCase = StringUtil.toLowerCase(pageTitleLowerCase);
152
153 if (pageTitle.get(pageTitleLowerCase) != null) {
154 notOrphans.add(page);
155
156 break;
157 }
158 }
159 }
160
161 List<WikiPage> orphans = new ArrayList<WikiPage>();
162
163 for (WikiPage page : pages) {
164 if (!notOrphans.contains(page)) {
165 orphans.add(page);
166 }
167 }
168
169 orphans = ListUtil.sort(orphans);
170
171 return orphans;
172 }
173
174 public static String getAttachmentURLPrefix(
175 String mainPath, long plid, long nodeId, String title) {
176
177 StringBundler sb = new StringBundler(8);
178
179 sb.append(mainPath);
180 sb.append("/wiki/get_page_attachment?p_l_id=");
181 sb.append(plid);
182 sb.append("&nodeId=");
183 sb.append(nodeId);
184 sb.append("&title=");
185 sb.append(HttpUtil.encodeURL(title));
186 sb.append("&fileName=");
187
188 return sb.toString();
189 }
190
191 public static DiffVersionsInfo getDiffVersionsInfo(
192 long nodeId, String title, double sourceVersion, double targetVersion,
193 HttpServletRequest request) {
194
195 double previousVersion = 0;
196 double nextVersion = 0;
197
198 List<WikiPage> pages = WikiPageLocalServiceUtil.getPages(
199 nodeId, title, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
200 new PageVersionComparator(true));
201
202 for (WikiPage page : pages) {
203 if ((page.getVersion() < sourceVersion) &&
204 (page.getVersion() > previousVersion)) {
205
206 previousVersion = page.getVersion();
207 }
208
209 if ((page.getVersion() > targetVersion) &&
210 ((page.getVersion() < nextVersion) || (nextVersion == 0))) {
211
212 nextVersion = page.getVersion();
213 }
214 }
215
216 List<DiffVersion> diffVersions = new ArrayList<DiffVersion>();
217
218 for (WikiPage page : pages) {
219 String extraInfo = StringPool.BLANK;
220
221 if (page.isMinorEdit()) {
222 extraInfo = LanguageUtil.get(request, "minor-edit");
223 }
224
225 DiffVersion diffVersion = new DiffVersion(
226 page.getUserId(), page.getVersion(), page.getModifiedDate(),
227 page.getSummary(), extraInfo);
228
229 diffVersions.add(diffVersion);
230 }
231
232 return new DiffVersionsInfo(diffVersions, nextVersion, previousVersion);
233 }
234
235 public static String getEditPage(String format) {
236 return _instance._getEditPage(format);
237 }
238
239 public static Map<String, String> getEmailFromDefinitionTerms(
240 RenderRequest request) {
241
242 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
243 WebKeys.THEME_DISPLAY);
244
245 Map<String, String> definitionTerms =
246 new LinkedHashMap<String, String>();
247
248 definitionTerms.put(
249 "[$COMPANY_ID$]",
250 LanguageUtil.get(
251 themeDisplay.getLocale(),
252 "the-company-id-associated-with-the-wiki"));
253 definitionTerms.put(
254 "[$COMPANY_MX$]",
255 LanguageUtil.get(
256 themeDisplay.getLocale(),
257 "the-company-mx-associated-with-the-wiki"));
258 definitionTerms.put(
259 "[$COMPANY_NAME$]",
260 LanguageUtil.get(
261 themeDisplay.getLocale(),
262 "the-company-name-associated-with-the-wiki"));
263 definitionTerms.put(
264 "[$PAGE_USER_ADDRESS$]",
265 LanguageUtil.get(
266 themeDisplay.getLocale(),
267 "the-email-address-of-the-user-who-added-the-page"));
268 definitionTerms.put(
269 "[$PAGE_USER_NAME$]",
270 LanguageUtil.get(
271 themeDisplay.getLocale(), "the-user-who-added-the-page"));
272 definitionTerms.put(
273 "[$PORTLET_NAME$]", PortalUtil.getPortletTitle(request));
274 definitionTerms.put(
275 "[$SITE_NAME$]",
276 LanguageUtil.get(
277 themeDisplay.getLocale(),
278 "the-site-name-associated-with-the-wiki"));
279
280 return definitionTerms;
281 }
282
283 public static Map<String, String> getEmailNotificationDefinitionTerms(
284 RenderRequest request, String emailFromAddress, String emailFromName) {
285
286 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
287 WebKeys.THEME_DISPLAY);
288
289 Map<String, String> definitionTerms =
290 new LinkedHashMap<String, String>();
291
292 definitionTerms.put(
293 "[$COMPANY_ID$]",
294 LanguageUtil.get(
295 themeDisplay.getLocale(),
296 "the-company-id-associated-with-the-wiki"));
297 definitionTerms.put(
298 "[$COMPANY_MX$]",
299 LanguageUtil.get(
300 themeDisplay.getLocale(),
301 "the-company-mx-associated-with-the-wiki"));
302 definitionTerms.put(
303 "[$COMPANY_NAME$]",
304 LanguageUtil.get(
305 themeDisplay.getLocale(),
306 "the-company-name-associated-with-the-wiki"));
307 definitionTerms.put(
308 "[$DIFFS_URL$]",
309 LanguageUtil.get(
310 themeDisplay.getLocale(),
311 "the-url-of-the-page-comparing-this-page-content-with-the-" +
312 "previous-version"));
313 definitionTerms.put(
314 "[$FROM_ADDRESS$]", HtmlUtil.escape(emailFromAddress));
315 definitionTerms.put("[$FROM_NAME$]", HtmlUtil.escape(emailFromName));
316 definitionTerms.put(
317 "[$NODE_NAME$]",
318 LanguageUtil.get(
319 themeDisplay.getLocale(),
320 "the-node-in-which-the-page-was-added"));
321 definitionTerms.put(
322 "[$PAGE_CONTENT$]",
323 LanguageUtil.get(themeDisplay.getLocale(), "the-page-content"));
324 definitionTerms.put(
325 "[$PAGE_DATE_UPDATE$]",
326 LanguageUtil.get(
327 themeDisplay.getLocale(), "the-date-of-the-modifications"));
328 definitionTerms.put(
329 "[$PAGE_DIFFS$]",
330 LanguageUtil.get(
331 themeDisplay.getLocale(),
332 "the-page-content-compared-with-the-previous-version-page-" +
333 "content"));
334 definitionTerms.put(
335 "[$PAGE_ID$]",
336 LanguageUtil.get(themeDisplay.getLocale(), "the-page-id"));
337 definitionTerms.put(
338 "[$PAGE_SUMMARY$]",
339 LanguageUtil.get(
340 themeDisplay.getLocale(),
341 "the-summary-of-the-page-or-the-modifications"));
342 definitionTerms.put(
343 "[$PAGE_TITLE$]",
344 LanguageUtil.get(themeDisplay.getLocale(), "the-page-title"));
345 definitionTerms.put(
346 "[$PAGE_URL$]",
347 LanguageUtil.get(themeDisplay.getLocale(), "the-page-url"));
348 definitionTerms.put(
349 "[$PAGE_USER_ADDRESS$]",
350 LanguageUtil.get(
351 themeDisplay.getLocale(),
352 "the-email-address-of-the-user-who-added-the-page"));
353 definitionTerms.put(
354 "[$PAGE_USER_NAME$]",
355 LanguageUtil.get(
356 themeDisplay.getLocale(), "the-user-who-added-the-page"));
357
358 Company company = themeDisplay.getCompany();
359
360 definitionTerms.put("[$PORTAL_URL$]", company.getVirtualHostname());
361
362 definitionTerms.put(
363 "[$PORTLET_NAME$]", PortalUtil.getPortletTitle(request));
364 definitionTerms.put(
365 "[$SITE_NAME$]",
366 LanguageUtil.get(
367 themeDisplay.getLocale(),
368 "the-site-name-associated-with-the-wiki"));
369 definitionTerms.put(
370 "[$TO_ADDRESS$]",
371 LanguageUtil.get(
372 themeDisplay.getLocale(),
373 "the-address-of-the-email-recipient"));
374 definitionTerms.put(
375 "[$TO_NAME$]",
376 LanguageUtil.get(
377 themeDisplay.getLocale(), "the-name-of-the-email-recipient"));
378
379 return definitionTerms;
380 }
381
382 public static List<Object> getEntries(Hits hits) {
383 List<Object> entries = new ArrayList<Object>();
384
385 for (Document document : hits.getDocs()) {
386 String entryClassName = GetterUtil.getString(
387 document.get(Field.ENTRY_CLASS_NAME));
388 long entryClassPK = GetterUtil.getLong(
389 document.get(Field.ENTRY_CLASS_PK));
390
391 try {
392 Object obj = null;
393
394 if (entryClassName.equals(DLFileEntry.class.getName())) {
395 long classPK = GetterUtil.getLong(
396 document.get(Field.CLASS_PK));
397
398 WikiPageLocalServiceUtil.getPage(classPK);
399
400 obj = DLFileEntryLocalServiceUtil.getDLFileEntry(
401 entryClassPK);
402 }
403 else if (entryClassName.equals(MBMessage.class.getName())) {
404 long classPK = GetterUtil.getLong(
405 document.get(Field.CLASS_PK));
406
407 WikiPageLocalServiceUtil.getPage(classPK);
408
409 obj = MBMessageLocalServiceUtil.getMessage(entryClassPK);
410 }
411 else if (entryClassName.equals(WikiPage.class.getName())) {
412 obj = WikiPageLocalServiceUtil.getPage(entryClassPK);
413 }
414
415 entries.add(obj);
416 }
417 catch (Exception e) {
418 if (_log.isWarnEnabled()) {
419 _log.warn(
420 "Wiki search index is stale and contains entry " +
421 "{className=" + entryClassName + ", classPK=" +
422 entryClassPK + "}");
423 }
424 }
425 }
426
427 return entries;
428 }
429
430 public static WikiNode getFirstNode(PortletRequest portletRequest)
431 throws PortalException {
432
433 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
434 WebKeys.THEME_DISPLAY);
435 long groupId = themeDisplay.getScopeGroupId();
436 PermissionChecker permissionChecker =
437 themeDisplay.getPermissionChecker();
438
439 List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
440
441 PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
442
443 WikiPortletInstanceSettings wikiPortletInstanceSettings =
444 WikiPortletInstanceSettings.getInstance(
445 themeDisplay.getLayout(), portletDisplay.getId());
446
447 String[] visibleNodeNames =
448 wikiPortletInstanceSettings.getVisibleNodes();
449
450 nodes = orderNodes(nodes, visibleNodeNames);
451
452 String[] hiddenNodes = wikiPortletInstanceSettings.getHiddenNodes();
453 Arrays.sort(hiddenNodes);
454
455 for (WikiNode node : nodes) {
456 if ((Arrays.binarySearch(hiddenNodes, node.getName()) < 0) &&
457 WikiNodePermission.contains(
458 permissionChecker, node, ActionKeys.VIEW)) {
459
460 return node;
461 }
462 }
463
464 return null;
465 }
466
467 public static String getFormattedContent(
468 RenderRequest renderRequest, RenderResponse renderResponse,
469 WikiPage wikiPage, PortletURL viewPageURL, PortletURL editPageURL,
470 String title, boolean preview)
471 throws Exception {
472
473 ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
474 WebKeys.THEME_DISPLAY);
475
476 double version = ParamUtil.getDouble(renderRequest, "version");
477
478 PortletURL curViewPageURL = PortletURLUtil.clone(
479 viewPageURL, renderResponse);
480 PortletURL curEditPageURL = PortletURLUtil.clone(
481 editPageURL, renderResponse);
482
483 StringBundler sb = new StringBundler(8);
484
485 sb.append(themeDisplay.getPathMain());
486 sb.append("/wiki/get_page_attachment?p_l_id=");
487 sb.append(themeDisplay.getPlid());
488 sb.append("&nodeId=");
489 sb.append(wikiPage.getNodeId());
490 sb.append("&title=");
491 sb.append(HttpUtil.encodeURL(wikiPage.getTitle()));
492 sb.append("&fileName=");
493
494 String attachmentURLPrefix = sb.toString();
495
496 if (!preview && (version == 0)) {
497 WikiPageDisplay pageDisplay = WikiCacheUtil.getDisplay(
498 wikiPage.getNodeId(), title, curViewPageURL, curEditPageURL,
499 attachmentURLPrefix);
500
501 if (pageDisplay != null) {
502 return pageDisplay.getFormattedContent();
503 }
504 }
505
506 return convert(
507 wikiPage, curViewPageURL, curEditPageURL, attachmentURLPrefix);
508 }
509
510 public static String getHelpPage(String format) {
511 return _instance._getHelpPage(format);
512 }
513
514 public static String getHelpURL(String format) {
515 return _instance._getHelpURL(format);
516 }
517
518 public static Map<String, Boolean> getLinks(WikiPage page)
519 throws PageContentException {
520
521 return _instance._getLinks(page);
522 }
523
524 public static List<String> getNodeNames(List<WikiNode> nodes) {
525 List<String> nodeNames = new ArrayList<String>(nodes.size());
526
527 for (WikiNode node : nodes) {
528 nodeNames.add(node.getName());
529 }
530
531 return nodeNames;
532 }
533
534 public static List<WikiNode> getNodes(
535 List<WikiNode> nodes, String[] hiddenNodes,
536 PermissionChecker permissionChecker) {
537
538 nodes = ListUtil.copy(nodes);
539
540 Arrays.sort(hiddenNodes);
541
542 Iterator<WikiNode> itr = nodes.iterator();
543
544 while (itr.hasNext()) {
545 WikiNode node = itr.next();
546
547 if (!(Arrays.binarySearch(hiddenNodes, node.getName()) < 0) ||
548 !WikiNodePermission.contains(
549 permissionChecker, node, ActionKeys.VIEW)) {
550
551 itr.remove();
552 }
553 }
554
555 return nodes;
556 }
557
558 public static OrderByComparator<WikiPage> getPageOrderByComparator(
559 String orderByCol, String orderByType) {
560
561 boolean orderByAsc = false;
562
563 if (orderByType.equals("asc")) {
564 orderByAsc = true;
565 }
566
567 OrderByComparator<WikiPage> orderByComparator = null;
568
569 if (orderByCol.equals("modifiedDate")) {
570 orderByComparator = new PageCreateDateComparator(orderByAsc);
571 }
572 else if (orderByCol.equals("title")) {
573 orderByComparator = new PageTitleComparator(orderByAsc);
574 }
575 else if (orderByCol.equals("version")) {
576 orderByComparator = new PageVersionComparator(orderByAsc);
577 }
578
579 return orderByComparator;
580 }
581
582 public static List<WikiNode> orderNodes(
583 List<WikiNode> nodes, String[] visibleNodeNames) {
584
585 if (ArrayUtil.isEmpty(visibleNodeNames)) {
586 return nodes;
587 }
588
589 nodes = ListUtil.copy(nodes);
590
591 List<WikiNode> orderedNodes = new ArrayList<WikiNode>(nodes.size());
592
593 for (String visibleNodeName : visibleNodeNames) {
594 for (WikiNode node : nodes) {
595 if (node.getName().equals(visibleNodeName)) {
596 orderedNodes.add(node);
597
598 nodes.remove(node);
599
600 break;
601 }
602 }
603 }
604
605 orderedNodes.addAll(nodes);
606
607 return orderedNodes;
608 }
609
610 public static String processContent(String content) {
611 content = StringUtil.replace(content, "</p>", "</p>\n");
612 content = StringUtil.replace(content, "</br>", "</br>\n");
613 content = StringUtil.replace(content, "</div>", "</div>\n");
614
615 return content;
616 }
617
618 public static String unescapeName(String name) {
619 return StringUtil.replace(name, _ESCAPED_CHARS, _UNESCAPED_CHARS);
620 }
621
622 public static boolean validate(long nodeId, String content, String format)
623 throws WikiFormatException {
624
625 return _instance._validate(nodeId, content, format);
626 }
627
628 private String _convert(
629 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
630 String attachmentURLPrefix)
631 throws PageContentException, WikiFormatException {
632
633 LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
634 LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
635
636 WikiEngine engine = _getEngine(page.getFormat());
637
638 String content = engine.convert(
639 page, viewPageURL, editPageURL, attachmentURLPrefix);
640
641 String editPageURLString = StringPool.BLANK;
642
643 if (editPageURL != null) {
644 liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
645
646 editPageURLString = editPageURL.toString();
647
648 editPageURLString = StringUtil.replace(
649 editPageURLString, "__REPLACEMENT__", "$1");
650 }
651
652 Matcher matcher = _editPageURLPattern.matcher(content);
653
654 content = _convertURLs(editPageURLString, matcher);
655
656 String viewPageURLString = StringPool.BLANK;
657
658 if (viewPageURL != null) {
659 liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
660
661 viewPageURLString = viewPageURL.toString();
662
663 viewPageURLString = StringUtil.replace(
664 viewPageURLString, "__REPLACEMENT__", "$1");
665 }
666
667 matcher = _viewPageURLPattern.matcher(content);
668
669 content = _convertURLs(viewPageURLString, matcher);
670
671 content = _replaceAttachments(
672 content, page.getTitle(), attachmentURLPrefix);
673
674 return content;
675 }
676
677 private String _convertURLs(String url, Matcher matcher) {
678 StringBuffer sb = new StringBuffer();
679
680 while (matcher.find()) {
681 String replacement = null;
682
683 if (matcher.groupCount() >= 1) {
684 String encodedTitle = HttpUtil.encodeURL(
685 HtmlUtil.unescape(matcher.group(1)));
686
687 replacement = url.replace("$1", encodedTitle);
688 }
689 else {
690 replacement = url;
691 }
692
693 matcher.appendReplacement(sb, replacement);
694 }
695
696 return matcher.appendTail(sb).toString();
697 }
698
699 private String _getEditPage(String format) {
700 return PropsUtil.get(
701 PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
702 }
703
704 private WikiEngine _getEngine(String format) throws WikiFormatException {
705 WikiEngine engine = _engines.get(format);
706
707 if (engine != null) {
708 return engine;
709 }
710
711 synchronized (_engines) {
712 engine = _engines.get(format);
713
714 if (engine != null) {
715 return engine;
716 }
717
718 try {
719 String engineClassName = PropsUtil.get(
720 PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
721
722 if (engineClassName == null) {
723 throw new WikiFormatException(format);
724 }
725
726 Class<?> clazz = getClass();
727
728 engine = (WikiEngine)InstanceFactory.newInstance(
729 clazz.getClassLoader(), engineClassName);
730
731 engine.setInterWikiConfiguration(
732 _readConfigurationFile(
733 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
734 format));
735 engine.setMainConfiguration(
736 _readConfigurationFile(
737 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN, format));
738
739 _engines.put(format, engine);
740
741 return engine;
742 }
743 catch (Exception e) {
744 throw new WikiFormatException(e);
745 }
746 }
747 }
748
749 private String _getHelpPage(String format) {
750 return PropsUtil.get(
751 PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
752 }
753
754 private String _getHelpURL(String format) {
755 return PropsUtil.get(
756 PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
757 }
758
759 private Map<String, Boolean> _getLinks(WikiPage page)
760 throws PageContentException {
761
762 try {
763 return _getEngine(page.getFormat()).getOutgoingLinks(page);
764 }
765 catch (WikiFormatException wfe) {
766 return Collections.emptyMap();
767 }
768 }
769
770 private String _readConfigurationFile(String propertyName, String format)
771 throws IOException {
772
773 ClassLoader classLoader = getClass().getClassLoader();
774
775 String configurationFile = PropsUtil.get(
776 propertyName, new Filter(format));
777
778 if (Validator.isNotNull(configurationFile)) {
779 return HttpUtil.URLtoString(
780 classLoader.getResource(configurationFile));
781 }
782 else {
783 return StringPool.BLANK;
784 }
785 }
786
787 private String _replaceAttachments(
788 String content, String title, String attachmentURLPrefix) {
789
790 content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
791
792 content = StringUtil.replace(
793 content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
794
795 return content;
796 }
797
798 private boolean _validate(long nodeId, String content, String format)
799 throws WikiFormatException {
800
801 return _getEngine(format).validate(nodeId, content);
802 }
803
804 private static final String[] _ESCAPED_CHARS = new String[] {
805 "<PLUS>", "<QUESTION>", "<SLASH>"
806 };
807
808 private static final String[] _UNESCAPED_CHARS = new String[] {
809 StringPool.PLUS, StringPool.QUESTION, StringPool.SLASH
810 };
811
812 private static final Log _log = LogFactoryUtil.getLog(WikiUtil.class);
813
814 private static final WikiUtil _instance = new WikiUtil();
815
816 private static final Pattern _editPageURLPattern = Pattern.compile(
817 "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)" +
818 "\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
819 private static final Pattern _viewPageURLPattern = Pattern.compile(
820 "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
821
822 private final Map<String, WikiEngine> _engines =
823 new ConcurrentHashMap<String, WikiEngine>();
824
825 }