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.portlet.LiferayPortletURL;
29  import com.liferay.portal.kernel.util.ArrayUtil;
30  import com.liferay.portal.kernel.util.DiffHtmlUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.HttpUtil;
33  import com.liferay.portal.kernel.util.InstancePool;
34  import com.liferay.portal.kernel.util.ListUtil;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.StringUtil;
37  import com.liferay.portal.kernel.util.Validator;
38  import com.liferay.portal.security.permission.ActionKeys;
39  import com.liferay.portal.security.permission.PermissionChecker;
40  import com.liferay.portal.theme.ThemeDisplay;
41  import com.liferay.portal.util.ContentUtil;
42  import com.liferay.portal.util.PropsKeys;
43  import com.liferay.portal.util.PropsUtil;
44  import com.liferay.portal.util.PropsValues;
45  import com.liferay.portal.util.WebKeys;
46  import com.liferay.portlet.wiki.PageContentException;
47  import com.liferay.portlet.wiki.WikiFormatException;
48  import com.liferay.portlet.wiki.engines.WikiEngine;
49  import com.liferay.portlet.wiki.model.WikiNode;
50  import com.liferay.portlet.wiki.model.WikiPage;
51  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
52  import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
53  import com.liferay.portlet.wiki.util.comparator.VisibleNodesComparator;
54  
55  import java.io.IOException;
56  import java.io.StringReader;
57  
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   */
77  public class WikiUtil {
78  
79      public static final String POP_PORTLET_PREFIX = "wiki.";
80  
81      public static String convert(
82              WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
83              String attachmentURLPrefix)
84          throws PageContentException, WikiFormatException {
85  
86          return _instance._convert(
87              page, viewPageURL, editPageURL, attachmentURLPrefix);
88      }
89  
90      public static String diffHtml (
91              WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
92              PortletURL editPageURL, String attachmentURLPrefix)
93          throws Exception {
94  
95          String sourceContent = StringPool.BLANK;
96          String targetContent = StringPool.BLANK;
97  
98          if (sourcePage != null) {
99              sourceContent = WikiUtil.convert(
100                 sourcePage, viewPageURL, editPageURL,attachmentURLPrefix);
101         }
102 
103         if (targetPage != null) {
104             targetContent = WikiUtil.convert(
105                 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
106         }
107 
108         return DiffHtmlUtil.diff(
109             new StringReader(sourceContent),new StringReader(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.sort(nodes, new VisibleNodesComparator(visibleNodes));
308 
309         Iterator<WikiNode> itr = nodes.iterator();
310 
311         while (itr.hasNext()) {
312             WikiNode node = itr.next();
313 
314             if (ArrayUtil.contains(hiddenNodes, node.getName()) ||
315                 !WikiNodePermission.contains(
316                     permissionChecker, node.getNodeId(), ActionKeys.VIEW)) {
317 
318                 itr.remove();
319             }
320         }
321 
322         return nodes;
323     }
324 
325     public static String processContent(String content) {
326         content = content.replaceAll("</p>", "</p>\n");
327         content = content.replaceAll("</br>", "</br>\n");
328         content = content.replaceAll("</div>", "</div>\n");
329 
330         return content;
331     }
332 
333     public static boolean validate(
334             long nodeId, String content, String format)
335         throws WikiFormatException {
336 
337         return _instance._validate(nodeId, content, format);
338     }
339 
340     private String _convert(
341             WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
342             String attachmentURLPrefix)
343         throws PageContentException, WikiFormatException {
344 
345         LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
346         LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
347 
348         WikiEngine engine = _getEngine(page.getFormat());
349 
350         String content = engine.convert(page, editPageURL);
351 
352         String editPageURLString = StringPool.BLANK;
353 
354         if (editPageURL != null) {
355             liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
356 
357             editPageURLString = editPageURL.toString();
358 
359             editPageURLString = StringUtil.replace(
360                 editPageURLString, "__REPLACEMENT__", "$1");
361         }
362 
363         Matcher matcher = _editPageURLPattern.matcher(content);
364 
365         content = matcher.replaceAll(editPageURLString);
366 
367         String viewPageURLString = StringPool.BLANK;
368 
369         if (viewPageURL != null) {
370             liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
371 
372             viewPageURLString = viewPageURL.toString();
373 
374             viewPageURLString = StringUtil.replace(
375                 viewPageURLString, "__REPLACEMENT__", "$1");
376         }
377 
378         matcher = _viewPageURLPattern.matcher(content);
379 
380         content = matcher.replaceAll(viewPageURLString);
381 
382         content = _replaceAttachments(
383             content, page.getTitle(), attachmentURLPrefix);
384 
385         return content;
386     }
387 
388     private String _getEditPage(String format) {
389         return PropsUtil.get(
390             PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
391     }
392 
393     private WikiEngine _getEngine(String format) throws WikiFormatException {
394         WikiEngine engine = _engines.get(format);
395 
396         if (engine == null) {
397             try {
398                 String engineClass = PropsUtil.get(
399                     PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
400 
401                 if (engineClass != null) {
402                     if (!InstancePool.contains(engineClass)) {
403                         engine = (WikiEngine)InstancePool.get(engineClass);
404 
405                         engine.setMainConfiguration(
406                             _readConfigurationFile(
407                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN,
408                                 format));
409 
410                         engine.setInterWikiConfiguration(
411                             _readConfigurationFile(
412                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
413                                 format));
414                     }
415                     else {
416                         engine = (WikiEngine)InstancePool.get(engineClass);
417                     }
418 
419                     _engines.put(format, engine);
420                 }
421             }
422             catch (Exception e) {
423                 throw new WikiFormatException(e);
424             }
425 
426             if (engine == null) {
427                 throw new WikiFormatException(format);
428             }
429         }
430 
431         return engine;
432     }
433 
434     private String _getHelpPage(String format) {
435         return PropsUtil.get(
436             PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
437     }
438 
439     private String _getHelpURL(String format) {
440         return PropsUtil.get(
441             PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
442     }
443 
444     private Map<String, Boolean> _getLinks(WikiPage page)
445         throws PageContentException {
446 
447         try {
448             return _getEngine(page.getFormat()).getOutgoingLinks(page);
449         }
450         catch (WikiFormatException wfe) {
451             return Collections.EMPTY_MAP;
452         }
453     }
454 
455     private String _readConfigurationFile(String propertyName, String format)
456         throws IOException {
457 
458         ClassLoader classLoader = getClass().getClassLoader();
459 
460         String configurationFile = PropsUtil.get(
461             propertyName, new Filter(format));
462 
463         if (Validator.isNotNull(configurationFile)) {
464             return HttpUtil.URLtoString(
465                 classLoader.getResource(configurationFile));
466         }
467         else {
468             return StringPool.BLANK;
469         }
470     }
471 
472     private String _replaceAttachments(
473         String content, String title, String attachmentURLPrefix) {
474 
475         content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
476 
477         content = StringUtil.replace(
478             content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
479 
480         return content;
481     }
482 
483     private boolean _validate(long nodeId, String content, String format)
484         throws WikiFormatException {
485 
486         return _getEngine(format).validate(nodeId, content);
487     }
488 
489     private static WikiUtil _instance = new WikiUtil();
490 
491     private static Pattern _editPageURLPattern = Pattern.compile(
492         "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
493     private static Pattern _viewPageURLPattern = Pattern.compile(
494         "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
495 
496     private Map<String, WikiEngine> _engines =
497         new HashMap<String, WikiEngine>();
498 
499 }