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