1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.wiki.util;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.configuration.Filter;
28  import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
29  import com.liferay.portal.kernel.portlet.LiferayPortletURL;
30  import com.liferay.portal.kernel.util.ArrayUtil;
31  import com.liferay.portal.kernel.util.DiffHtmlUtil;
32  import com.liferay.portal.kernel.util.GetterUtil;
33  import com.liferay.portal.kernel.util.HttpUtil;
34  import com.liferay.portal.kernel.util.InstancePool;
35  import com.liferay.portal.kernel.util.ListUtil;
36  import com.liferay.portal.kernel.util.PropsKeys;
37  import com.liferay.portal.kernel.util.StringPool;
38  import com.liferay.portal.kernel.util.StringUtil;
39  import com.liferay.portal.kernel.util.Validator;
40  import com.liferay.portal.security.permission.ActionKeys;
41  import com.liferay.portal.security.permission.PermissionChecker;
42  import com.liferay.portal.theme.ThemeDisplay;
43  import com.liferay.portal.util.ContentUtil;
44  import com.liferay.portal.util.PropsUtil;
45  import com.liferay.portal.util.PropsValues;
46  import com.liferay.portal.util.WebKeys;
47  import com.liferay.portlet.wiki.PageContentException;
48  import com.liferay.portlet.wiki.WikiFormatException;
49  import com.liferay.portlet.wiki.engines.WikiEngine;
50  import com.liferay.portlet.wiki.model.WikiNode;
51  import com.liferay.portlet.wiki.model.WikiPage;
52  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
53  import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
54  
55  import java.io.IOException;
56  
57  import java.util.ArrayList;
58  import java.util.Collections;
59  import java.util.HashMap;
60  import java.util.Iterator;
61  import java.util.List;
62  import java.util.Map;
63  import java.util.regex.Matcher;
64  import java.util.regex.Pattern;
65  
66  import javax.portlet.PortletPreferences;
67  import javax.portlet.PortletURL;
68  import javax.portlet.RenderRequest;
69  
70  /**
71   * <a href="WikiUtil.java.html"><b><i>View Source</i></b></a>
72   *
73   * @author Brian Wing Shun Chan
74   * @author Jorge Ferrer
75   */
76  public class WikiUtil {
77  
78      public static final String POP_PORTLET_PREFIX = "wiki.";
79  
80      public static String convert(
81              WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
82              String attachmentURLPrefix)
83          throws PageContentException, WikiFormatException {
84  
85          return _instance._convert(
86              page, viewPageURL, editPageURL, attachmentURLPrefix);
87      }
88  
89      public static String diffHtml (
90              WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
91              PortletURL editPageURL, String attachmentURLPrefix)
92          throws Exception {
93  
94          String sourceContent = StringPool.BLANK;
95          String targetContent = StringPool.BLANK;
96  
97          if (sourcePage != null) {
98              sourceContent = WikiUtil.convert(
99                  sourcePage, viewPageURL, editPageURL,attachmentURLPrefix);
100         }
101 
102         if (targetPage != null) {
103             targetContent = WikiUtil.convert(
104                 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
105         }
106 
107         return DiffHtmlUtil.diff(
108             new UnsyncStringReader(sourceContent),
109             new UnsyncStringReader(targetContent));
110     }
111 
112     public static String getEditPage(String format) {
113         return _instance._getEditPage(format);
114     }
115 
116     public static String getEmailFromAddress(PortletPreferences preferences) {
117         String emailFromAddress = PropsUtil.get(
118             PropsKeys.WIKI_EMAIL_FROM_ADDRESS);
119 
120         return preferences.getValue("email-from-address", emailFromAddress);
121     }
122 
123     public static String getEmailFromName(PortletPreferences preferences) {
124         String emailFromName = PropsUtil.get(PropsKeys.WIKI_EMAIL_FROM_NAME);
125 
126         return preferences.getValue("email-from-name", emailFromName);
127     }
128 
129     public static boolean getEmailPageAddedEnabled(
130         PortletPreferences preferences) {
131 
132         String emailPageAddedEnabled = preferences.getValue(
133             "email-page-added-enabled", StringPool.BLANK);
134 
135         if (Validator.isNotNull(emailPageAddedEnabled)) {
136             return GetterUtil.getBoolean(emailPageAddedEnabled);
137         }
138         else {
139             return GetterUtil.getBoolean(PropsUtil.get(
140                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_ENABLED));
141         }
142     }
143 
144     public static String getEmailPageAddedBody(PortletPreferences preferences) {
145         String emailPageAddedBody = preferences.getValue(
146             "email-page-added-body", StringPool.BLANK);
147 
148         if (Validator.isNotNull(emailPageAddedBody)) {
149             return emailPageAddedBody;
150         }
151         else {
152             return ContentUtil.get(PropsUtil.get(
153                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_BODY));
154         }
155     }
156 
157     public static String getEmailPageAddedSignature(
158         PortletPreferences preferences) {
159 
160         String emailPageAddedSignature = preferences.getValue(
161             "email-page-added-signature", StringPool.BLANK);
162 
163         if (Validator.isNotNull(emailPageAddedSignature)) {
164             return emailPageAddedSignature;
165         }
166         else {
167             return ContentUtil.get(PropsUtil.get(
168                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
169         }
170     }
171 
172     public static String getEmailPageAddedSubjectPrefix(
173         PortletPreferences preferences) {
174 
175         String emailPageAddedSubjectPrefix = preferences.getValue(
176             "email-page-added-subject-prefix", StringPool.BLANK);
177 
178         if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
179             return emailPageAddedSubjectPrefix;
180         }
181         else {
182             return ContentUtil.get(PropsUtil.get(
183                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
184         }
185     }
186 
187     public static boolean getEmailPageUpdatedEnabled(
188         PortletPreferences preferences) {
189 
190         String emailPageUpdatedEnabled = preferences.getValue(
191             "email-page-updated-enabled", StringPool.BLANK);
192 
193         if (Validator.isNotNull(emailPageUpdatedEnabled)) {
194             return GetterUtil.getBoolean(emailPageUpdatedEnabled);
195         }
196         else {
197             return GetterUtil.getBoolean(PropsUtil.get(
198                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
199         }
200     }
201 
202     public static String getEmailPageUpdatedBody(
203         PortletPreferences preferences) {
204 
205         String emailPageUpdatedBody = preferences.getValue(
206             "email-page-updated-body", StringPool.BLANK);
207 
208         if (Validator.isNotNull(emailPageUpdatedBody)) {
209             return emailPageUpdatedBody;
210         }
211         else {
212             return ContentUtil.get(PropsUtil.get(
213                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
214         }
215     }
216 
217     public static String getEmailPageUpdatedSignature(
218         PortletPreferences preferences) {
219 
220         String emailPageUpdatedSignature = preferences.getValue(
221             "email-page-updated-signature", StringPool.BLANK);
222 
223         if (Validator.isNotNull(emailPageUpdatedSignature)) {
224             return emailPageUpdatedSignature;
225         }
226         else {
227             return ContentUtil.get(PropsUtil.get(
228                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
229         }
230     }
231 
232     public static String getEmailPageUpdatedSubjectPrefix(
233         PortletPreferences preferences) {
234 
235         String emailPageUpdatedSubject = preferences.getValue(
236             "email-page-updated-subject-prefix", StringPool.BLANK);
237 
238         if (Validator.isNotNull(emailPageUpdatedSubject)) {
239             return emailPageUpdatedSubject;
240         }
241         else {
242             return ContentUtil.get(PropsUtil.get(
243                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
244         }
245     }
246 
247     public static String getHelpPage(String format) {
248         return _instance._getHelpPage(format);
249     }
250 
251     public static String getHelpURL(String format) {
252         return _instance._getHelpURL(format);
253     }
254 
255     public static Map<String, Boolean> getLinks(WikiPage page)
256         throws PageContentException {
257 
258         return _instance._getLinks(page);
259     }
260 
261     public static String getMailId(String mx, long nodeId, long pageId) {
262         StringBuilder sb = new StringBuilder();
263 
264         sb.append(StringPool.LESS_THAN);
265         sb.append(POP_PORTLET_PREFIX);
266         sb.append(nodeId);
267         sb.append(StringPool.PERIOD);
268         sb.append(pageId);
269         sb.append(StringPool.AT);
270         sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
271         sb.append(StringPool.PERIOD);
272         sb.append(mx);
273         sb.append(StringPool.GREATER_THAN);
274 
275         return sb.toString();
276     }
277 
278     public static List<WikiNode> getNodes(RenderRequest renderRequest)
279         throws PortalException, SystemException {
280 
281         ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
282             WebKeys.THEME_DISPLAY);
283 
284         long groupId = themeDisplay.getScopeGroupId();
285 
286         String allNodes = ListUtil.toString(
287             WikiNodeLocalServiceUtil.getNodes(groupId), "name");
288 
289         String[] visibleNodes = StringUtil.split(
290             renderRequest.getPreferences().getValue("visible-nodes", allNodes));
291         String[] hiddenNodes = StringUtil.split(
292             renderRequest.getPreferences().getValue(
293                 "hidden-nodes", StringPool.BLANK));
294 
295         return getNodes(
296             groupId, visibleNodes, hiddenNodes,
297             themeDisplay.getPermissionChecker());
298     }
299 
300     public static List<WikiNode> getNodes(
301             long groupId, String[] visibleNodes, String[] hiddenNodes,
302             PermissionChecker permissionChecker)
303         throws PortalException, SystemException {
304 
305         List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
306 
307         nodes = ListUtil.copy(nodes);
308         nodes = _orderNodes(nodes, visibleNodes);
309 
310         Iterator<WikiNode> itr = nodes.iterator();
311 
312         while (itr.hasNext()) {
313             WikiNode node = itr.next();
314 
315             if (ArrayUtil.contains(hiddenNodes, node.getName()) ||
316                 !WikiNodePermission.contains(
317                     permissionChecker, node.getNodeId(), ActionKeys.VIEW)) {
318 
319                 itr.remove();
320             }
321         }
322 
323         return nodes;
324     }
325 
326     public static String processContent(String content) {
327         content = content.replaceAll("</p>", "</p>\n");
328         content = content.replaceAll("</br>", "</br>\n");
329         content = content.replaceAll("</div>", "</div>\n");
330 
331         return content;
332     }
333 
334     public static boolean validate(
335             long nodeId, String content, String format)
336         throws WikiFormatException {
337 
338         return _instance._validate(nodeId, content, format);
339     }
340 
341     private static List<WikiNode> _orderNodes(
342         List<WikiNode> nodes, String[] nodeNames) {
343 
344         List<WikiNode> orderedNodes = new ArrayList<WikiNode>();
345 
346         for (String nodeName : nodeNames) {
347             for (WikiNode node : nodes) {
348                 if (node.getName().equals(nodeName)) {
349                     orderedNodes.add(node);
350 
351                     nodes.remove(node);
352 
353                     break;
354                 }
355             }
356         }
357 
358         orderedNodes.addAll(nodes);
359 
360         return orderedNodes;
361     }
362 
363     private String _convert(
364             WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
365             String attachmentURLPrefix)
366         throws PageContentException, WikiFormatException {
367 
368         LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
369         LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
370 
371         WikiEngine engine = _getEngine(page.getFormat());
372 
373         String content = engine.convert(page, editPageURL);
374 
375         String editPageURLString = StringPool.BLANK;
376 
377         if (editPageURL != null) {
378             liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
379 
380             editPageURLString = editPageURL.toString();
381 
382             editPageURLString = StringUtil.replace(
383                 editPageURLString, "__REPLACEMENT__", "$1");
384         }
385 
386         Matcher matcher = _editPageURLPattern.matcher(content);
387 
388         content = matcher.replaceAll(editPageURLString);
389 
390         String viewPageURLString = StringPool.BLANK;
391 
392         if (viewPageURL != null) {
393             liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
394 
395             viewPageURLString = viewPageURL.toString();
396 
397             viewPageURLString = StringUtil.replace(
398                 viewPageURLString, "__REPLACEMENT__", "$1");
399         }
400 
401         matcher = _viewPageURLPattern.matcher(content);
402 
403         content = matcher.replaceAll(viewPageURLString);
404 
405         content = _replaceAttachments(
406             content, page.getTitle(), attachmentURLPrefix);
407 
408         return content;
409     }
410 
411     private String _getEditPage(String format) {
412         return PropsUtil.get(
413             PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
414     }
415 
416     private WikiEngine _getEngine(String format) throws WikiFormatException {
417         WikiEngine engine = _engines.get(format);
418 
419         if (engine == null) {
420             try {
421                 String engineClass = PropsUtil.get(
422                     PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
423 
424                 if (engineClass != null) {
425                     if (!InstancePool.contains(engineClass)) {
426                         engine = (WikiEngine)InstancePool.get(engineClass);
427 
428                         engine.setMainConfiguration(
429                             _readConfigurationFile(
430                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN,
431                                 format));
432 
433                         engine.setInterWikiConfiguration(
434                             _readConfigurationFile(
435                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
436                                 format));
437                     }
438                     else {
439                         engine = (WikiEngine)InstancePool.get(engineClass);
440                     }
441 
442                     _engines.put(format, engine);
443                 }
444             }
445             catch (Exception e) {
446                 throw new WikiFormatException(e);
447             }
448 
449             if (engine == null) {
450                 throw new WikiFormatException(format);
451             }
452         }
453 
454         return engine;
455     }
456 
457     private String _getHelpPage(String format) {
458         return PropsUtil.get(
459             PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
460     }
461 
462     private String _getHelpURL(String format) {
463         return PropsUtil.get(
464             PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
465     }
466 
467     private Map<String, Boolean> _getLinks(WikiPage page)
468         throws PageContentException {
469 
470         try {
471             return _getEngine(page.getFormat()).getOutgoingLinks(page);
472         }
473         catch (WikiFormatException wfe) {
474             return Collections.EMPTY_MAP;
475         }
476     }
477 
478     private String _readConfigurationFile(String propertyName, String format)
479         throws IOException {
480 
481         ClassLoader classLoader = getClass().getClassLoader();
482 
483         String configurationFile = PropsUtil.get(
484             propertyName, new Filter(format));
485 
486         if (Validator.isNotNull(configurationFile)) {
487             return HttpUtil.URLtoString(
488                 classLoader.getResource(configurationFile));
489         }
490         else {
491             return StringPool.BLANK;
492         }
493     }
494 
495     private String _replaceAttachments(
496         String content, String title, String attachmentURLPrefix) {
497 
498         content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
499 
500         content = StringUtil.replace(
501             content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
502 
503         return content;
504     }
505 
506     private boolean _validate(long nodeId, String content, String format)
507         throws WikiFormatException {
508 
509         return _getEngine(format).validate(nodeId, content);
510     }
511 
512     private static WikiUtil _instance = new WikiUtil();
513 
514     private static Pattern _editPageURLPattern = Pattern.compile(
515         "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
516     private static Pattern _viewPageURLPattern = Pattern.compile(
517         "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
518 
519     private Map<String, WikiEngine> _engines =
520         new HashMap<String, WikiEngine>();
521 
522 }