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