001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    /**
088     * @author Brian Wing Shun Chan
089     * @author Jorge Ferrer
090     */
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    }