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