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