/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.wiki.engine.jspwiki.internal;
import com.ecyrd.jspwiki.WikiContext;
import com.ecyrd.jspwiki.WikiException;
import com.ecyrd.jspwiki.WikiPage;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.AggregateResourceBundleLoader;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.ResourceBundleLoader;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.language.LanguageResources;
import com.liferay.wiki.configuration.WikiGroupServiceConfiguration;
import com.liferay.wiki.engine.WikiEngine;
import com.liferay.wiki.engine.input.editor.common.BaseInputEditorWikiEngine;
import com.liferay.wiki.exception.PageContentException;
import com.liferay.wiki.service.WikiPageLocalService;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.portlet.PortletURL;
import javax.servlet.ServletContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* @author Jorge Ferrer
*/
@Component(
property = {"service.ranking:Integer=-1000"}, service = WikiEngine.class
)
public class JSPWikiEngine extends BaseInputEditorWikiEngine {
public static String decodeJSPWikiName(String jspWikiName) {
return StringUtil.replace(
jspWikiName, _JSP_WIKI_NAME_2, _JSP_WIKI_NAME_1);
}
@Override
public String convert(
com.liferay.wiki.model.WikiPage page, PortletURL viewPageURL,
PortletURL editPageURL, String attachmentURLPrefix)
throws PageContentException {
try {
return convert(page);
}
catch (WikiException we) {
throw new PageContentException(we);
}
}
@Override
public String getEditorName() {
return _wikiGroupServiceConfiguration.getCreoleEditor();
}
@Override
public String getFormat() {
return "creole";
}
@Override
public String getHelpURL() {
return
"https://jspwiki-wiki.apache.org/Wiki.jsp?page=TextFormattingRules";
}
@Override
public Map<String, Boolean> getOutgoingLinks(
com.liferay.wiki.model.WikiPage page)
throws PageContentException {
if (Validator.isNull(page.getContent())) {
return Collections.emptyMap();
}
try {
LiferayJSPWikiEngine engine = getEngine(page.getNodeId());
WikiPage jspWikiPage = LiferayPageProvider.toJSPWikiPage(
page, engine);
Collection<String> titles = engine.scanWikiLinks(
jspWikiPage, _encodeJSPWikiContent(page.getContent()));
Map<String, Boolean> links = new HashMap<>();
for (String title : titles) {
if (title.startsWith("[[")) {
title = title.substring(2);
}
else if (title.startsWith("[")) {
title = title.substring(1);
}
if (title.endsWith("]]")) {
title = title.substring(0, title.length() - 2);
}
else if (title.endsWith("]")) {
title = title.substring(0, title.length() - 1);
}
Boolean existsObj = links.get(title);
if (existsObj == null) {
if (_wikiPageLocalService.getPagesCount(
page.getNodeId(), title, true) > 0) {
existsObj = Boolean.TRUE;
}
else {
existsObj = Boolean.FALSE;
}
links.put(title, existsObj);
}
}
return links;
}
catch (SystemException se) {
throw new PageContentException(se);
}
catch (WikiException we) {
throw new PageContentException(we);
}
}
@Activate
protected void activate() throws IOException {
Class<?> clazz = getClass();
ClassLoader classLoader = clazz.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(
"com/liferay/wiki/engine/jspwiki/dependencies/jspwiki.properties");
try {
_properties.load(inputStream);
}
finally {
inputStream.close();
}
}
protected String convert(com.liferay.wiki.model.WikiPage page)
throws WikiException {
String content = _encodeJSPWikiContent(page.getContent());
if (Validator.isNull(content)) {
return StringPool.BLANK;
}
com.ecyrd.jspwiki.WikiEngine engine = getEngine(page.getNodeId());
WikiPage jspWikiPage = LiferayPageProvider.toJSPWikiPage(page, engine);
WikiContext wikiContext = new WikiContext(engine, jspWikiPage);
return _decodeJSPWikiContent(engine.textToHTML(wikiContext, content));
}
protected LiferayJSPWikiEngine getEngine(long nodeId) throws WikiException {
LiferayJSPWikiEngine engine = _engines.get(nodeId);
if (engine != null) {
return engine;
}
synchronized (_engines) {
engine = _engines.get(nodeId);
if (engine != null) {
return engine;
}
Properties nodeProperties = new Properties(_properties);
nodeProperties.setProperty("nodeId", String.valueOf(nodeId));
String appName = nodeProperties.getProperty(
"jspwiki.applicationName");
nodeProperties.setProperty(
"jspwiki.applicationName", appName + " for node " + nodeId);
engine = new LiferayJSPWikiEngine(nodeProperties);
_engines.put(nodeId, engine);
return engine;
}
}
@Override
protected ServletContext getHelpPageServletContext() {
return _servletContext;
}
@Override
protected ResourceBundleLoader getResourceBundleLoader() {
return _resourceBundleLoader;
}
protected synchronized void setProperties(String configuration) {
_properties = new Properties();
InputStream is = new UnsyncByteArrayInputStream(
configuration.getBytes());
try {
_properties.load(is);
}
catch (IOException ioe) {
_log.error(ioe, ioe);
}
}
@Reference(
target = "(bundle.symbolic.name=com.liferay.wiki.engine.lang)",
unbind = "-"
)
protected void setResourceBundleLoader(
ResourceBundleLoader resourceBundleLoader) {
_resourceBundleLoader = new AggregateResourceBundleLoader(
resourceBundleLoader, LanguageResources.RESOURCE_BUNDLE_LOADER);
}
@Reference(
target = "(osgi.web.symbolicname=com.liferay.wiki.engine.jspwiki)",
unbind = "-"
)
protected void setServletContext(ServletContext servletContext) {
_servletContext = servletContext;
}
@Reference
protected void setWikiGroupServiceConfiguration(
WikiGroupServiceConfiguration wikiGroupServiceConfiguration) {
_wikiGroupServiceConfiguration = wikiGroupServiceConfiguration;
}
@Reference(unbind = "-")
protected void setWikiPageLocalService(
WikiPageLocalService wikiPageLocalService) {
_wikiPageLocalService = wikiPageLocalService;
}
protected void unsetWikiGroupServiceConfiguration(
WikiGroupServiceConfiguration wikiGroupServiceConfiguration) {
_wikiGroupServiceConfiguration = null;
}
private static String _decodeJSPWikiContent(String jspWikiContent) {
return StringUtil.replace(
jspWikiContent, _JSP_WIKI_NAME_2, _JSP_WIKI_NAME_1);
}
private static String _encodeJSPWikiContent(String content) {
StringBundler encodedContent = new StringBundler();
Matcher commentMatcher = _wikiCommentPattern.matcher(content);
int start = 0;
int end = 0;
while (commentMatcher.find()) {
end = commentMatcher.start();
String oldContent = content.substring(start, end);
Matcher wikiLinkMatcher = _wikiLinkPattern.matcher(oldContent);
encodedContent.append(_encodeLink(oldContent, wikiLinkMatcher));
encodedContent.append(
content.substring(
commentMatcher.start(), commentMatcher.end()));
start = commentMatcher.end();
}
if (start < content.length()) {
content = content.substring(start);
Matcher wikiLinkMatcher = _wikiLinkPattern.matcher(content);
encodedContent.append(_encodeLink(content, wikiLinkMatcher));
}
return encodedContent.toString();
}
private static String _encodeJSPWikiName(String name) {
if (name == null) {
return StringPool.BLANK;
}
return StringUtil.replace(name, _JSP_WIKI_NAME_1, _JSP_WIKI_NAME_2);
}
private static String _encodeLink(String content, Matcher wikiLinkMatcher) {
while (wikiLinkMatcher.find()) {
String link = wikiLinkMatcher.group();
String linkValues = wikiLinkMatcher.group(1);
String name = linkValues;
String url = linkValues;
int pos = linkValues.indexOf(CharPool.PIPE);
if (pos != -1) {
name = linkValues.substring(pos + 1);
url = linkValues.substring(0, pos);
}
String newLink =
"[[" + _encodeJSPWikiName(url) + "|" +
_encodeJSPWikiName(name) + "]]";
content = StringUtil.replace(content, link, newLink);
}
return content;
}
private static final String[] _JSP_WIKI_NAME_1 = {
StringPool.APOSTROPHE, StringPool.AT, StringPool.CARET,
StringPool.EXCLAMATION, StringPool.INVERTED_EXCLAMATION,
StringPool.INVERTED_QUESTION, StringPool.GRAVE_ACCENT,
StringPool.QUESTION, StringPool.SLASH, StringPool.STAR
};
private static final String[] _JSP_WIKI_NAME_2 = {
"__APO__", "__AT__", "__CAR__", "__EXM__", "__INE__", "__INQ__",
"__GRA__", "__QUE__", "__SLA__", "__STA__"
};
private static final Log _log = LogFactoryUtil.getLog(JSPWikiEngine.class);
private static final Pattern _wikiCommentPattern = Pattern.compile(
"[\\{]{3,3}(.*?)[\\}]{3,3}", Pattern.DOTALL);
private static final Pattern _wikiLinkPattern = Pattern.compile(
"[\\[]{1,2}(.+?)[\\]]{1,2}", Pattern.DOTALL);
private final Map<Long, LiferayJSPWikiEngine> _engines =
new ConcurrentHashMap<>();
private Properties _properties = new Properties();
private ResourceBundleLoader _resourceBundleLoader;
private ServletContext _servletContext;
private WikiGroupServiceConfiguration _wikiGroupServiceConfiguration;
private WikiPageLocalService _wikiPageLocalService;
}