001    /**
002     * Copyright (c) 2000-2011 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.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 =
256                            StringUtil.split(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(
382                            long nodeId, String content, String format)
383                    throws WikiFormatException {
384    
385                    return _instance._validate(nodeId, content, format);
386            }
387    
388            private String _convert(
389                            WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
390                            String attachmentURLPrefix)
391                    throws PageContentException, WikiFormatException {
392    
393                    LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
394                    LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
395    
396                    WikiEngine engine = _getEngine(page.getFormat());
397    
398                    String content = engine.convert(
399                            page, viewPageURL, editPageURL, attachmentURLPrefix);
400    
401                    String editPageURLString = StringPool.BLANK;
402    
403                    if (editPageURL != null) {
404                            liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
405    
406                            editPageURLString = editPageURL.toString();
407    
408                            editPageURLString = StringUtil.replace(
409                                    editPageURLString, "__REPLACEMENT__", "$1");
410                    }
411    
412                    Matcher matcher = _editPageURLPattern.matcher(content);
413    
414                    content = _convertURLs(editPageURLString, matcher);
415    
416                    String viewPageURLString = StringPool.BLANK;
417    
418                    if (viewPageURL != null) {
419                            liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
420    
421                            viewPageURLString = viewPageURL.toString();
422    
423                            viewPageURLString = StringUtil.replace(
424                                    viewPageURLString, "__REPLACEMENT__", "$1");
425                    }
426    
427                    matcher = _viewPageURLPattern.matcher(content);
428    
429                    content = _convertURLs(viewPageURLString, matcher);
430    
431                    content = _replaceAttachments(
432                            content, page.getTitle(), attachmentURLPrefix);
433    
434                    return content;
435            }
436    
437            private String _convertURLs(String url, Matcher matcher) {
438                    StringBuffer sb = new StringBuffer();
439    
440                    while (matcher.find()) {
441                            String replacement = null;
442    
443                            if (matcher.groupCount() >= 1) {
444                                    String encodedTitle = HttpUtil.encodeURL(matcher.group(1));
445    
446                                    replacement = url.replace("$1", encodedTitle);
447                            }
448                            else {
449                                    replacement = url;
450                            }
451    
452                            matcher.appendReplacement(sb, replacement);
453                    }
454    
455                    return matcher.appendTail(sb).toString();
456            }
457    
458            private String _getEditPage(String format) {
459                    return PropsUtil.get(
460                            PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
461            }
462    
463            private WikiEngine _getEngine(String format) throws WikiFormatException {
464                    WikiEngine engine = _engines.get(format);
465    
466                    if (engine != null) {
467                            return engine;
468                    }
469    
470                    synchronized (_engines) {
471                            engine = _engines.get(format);
472    
473                            if (engine != null) {
474                                    return engine;
475                            }
476    
477                            try {
478                                    String engineClass = PropsUtil.get(
479                                            PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
480    
481                                    if (engineClass == null) {
482                                            throw new WikiFormatException(format);
483                                    }
484    
485                                    if (!InstancePool.contains(engineClass)) {
486                                            engine = (WikiEngine)InstancePool.get(engineClass);
487    
488                                            engine.setMainConfiguration(
489                                                    _readConfigurationFile(
490                                                            PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN, format));
491    
492                                            engine.setInterWikiConfiguration(
493                                                    _readConfigurationFile(
494                                                            PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
495                                                            format));
496                                    }
497                                    else {
498                                            engine = (WikiEngine)InstancePool.get(engineClass);
499                                    }
500    
501                                    _engines.put(format, engine);
502    
503                                    return engine;
504                            }
505                            catch (Exception e) {
506                                    throw new WikiFormatException(e);
507                            }
508                    }
509            }
510    
511            private String _getHelpPage(String format) {
512                    return PropsUtil.get(
513                            PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
514            }
515    
516            private String _getHelpURL(String format) {
517                    return PropsUtil.get(
518                            PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
519            }
520    
521            private Map<String, Boolean> _getLinks(WikiPage page)
522                    throws PageContentException {
523    
524                    try {
525                            return _getEngine(page.getFormat()).getOutgoingLinks(page);
526                    }
527                    catch (WikiFormatException wfe) {
528                            return Collections.emptyMap();
529                    }
530            }
531    
532            private String _readConfigurationFile(String propertyName, String format)
533                    throws IOException {
534    
535                    ClassLoader classLoader = getClass().getClassLoader();
536    
537                    String configurationFile = PropsUtil.get(
538                            propertyName, new Filter(format));
539    
540                    if (Validator.isNotNull(configurationFile)) {
541                            return HttpUtil.URLtoString(
542                                    classLoader.getResource(configurationFile));
543                    }
544                    else {
545                            return StringPool.BLANK;
546                    }
547            }
548    
549            private String _replaceAttachments(
550                    String content, String title, String attachmentURLPrefix) {
551    
552                    content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
553    
554                    content = StringUtil.replace(
555                            content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
556    
557                    return content;
558            }
559    
560            private boolean _validate(long nodeId, String content, String format)
561                    throws WikiFormatException {
562    
563                    return _getEngine(format).validate(nodeId, content);
564            }
565    
566            private static WikiUtil _instance = new WikiUtil();
567    
568            private static Pattern _editPageURLPattern = Pattern.compile(
569                    "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)" +
570                            "\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
571            private static Pattern _viewPageURLPattern = Pattern.compile(
572                    "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
573    
574            private Map<String, WikiEngine> _engines =
575                    new ConcurrentHashMap<String, WikiEngine>();
576    
577    }