Add common interface for formatters
Having a common interface for formatters makes it easier to add
additional formatters. Now to add a new formatter one only needs to
implement the Formatter interface and register the implementation in a
DynamicMap.
Change-Id: I4cbbf6cff89b18a277f8d828486ae9cc023c2dca
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/ConfigSection.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/ConfigSection.java
new file mode 100644
index 0000000..7da04a0
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/ConfigSection.java
@@ -0,0 +1,78 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.xdocs;
+
+import com.google.common.base.MoreObjects;
+
+import org.eclipse.jgit.lib.Config;
+
+import java.util.Set;
+
+public class ConfigSection {
+ private final Config cfg;
+ private final String section;
+ private final String subsection;
+
+ ConfigSection(Config cfg, String section) {
+ this(cfg, section, null);
+ }
+
+ ConfigSection(Config cfg, String section, String subsection) {
+ this.cfg = cfg;
+ this.section = section;
+ this.subsection = subsection;
+ }
+
+ public String getString(String name) {
+ return cfg.getString(section, subsection, name);
+ }
+
+ public String getString(String name, String defaultValue) {
+ if (defaultValue == null) {
+ return cfg.getString(section, subsection, name);
+ } else {
+ return MoreObjects.firstNonNull(cfg.getString(section, subsection, name),
+ defaultValue);
+ }
+ }
+
+ public String[] getStringList(String name) {
+ return cfg.getStringList(section, subsection, name);
+ }
+
+ public int getInt(String name, int defaultValue) {
+ return cfg.getInt(section, subsection, name, defaultValue);
+ }
+
+ public long getLong(String name, long defaultValue) {
+ return cfg.getLong(section, subsection, name, defaultValue);
+ }
+
+ public boolean getBoolean(String name, boolean defaultValue) {
+ return cfg.getBoolean(section, subsection, name, defaultValue);
+ }
+
+ public <T extends Enum<?>> T getEnum(String name, T defaultValue) {
+ return cfg.getEnum(section, subsection, name, defaultValue);
+ }
+
+ public <T extends Enum<?>> T getEnum(T[] all, String name, T defaultValue) {
+ return cfg.getEnum(all, section, subsection, name, defaultValue);
+ }
+
+ public Set<String> getNames() {
+ return cfg.getNames(section, subsection);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
index c313f4d..1f3dac5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
@@ -15,7 +15,9 @@
package com.googlesource.gerrit.plugins.xdocs;
import com.google.common.collect.Lists;
+import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.webui.BranchWebLink;
import com.google.gerrit.extensions.webui.FileWebLink;
@@ -25,6 +27,10 @@
import com.google.gerrit.server.config.FactoryModule;
import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.MarkdownFormatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.PlainTextFormatter;
+
import java.util.List;
public class Module extends FactoryModule {
@@ -40,6 +46,14 @@
install(new XDocLoader.Module());
factory(XDocProjectConfig.Factory.class);
+ DynamicMap.mapOf(binder(), Formatter.class);
+ bind(Formatter.class)
+ .annotatedWith(Exports.named(MarkdownFormatter.NAME))
+ .to(MarkdownFormatter.class);
+ bind(Formatter.class)
+ .annotatedWith(Exports.named(PlainTextFormatter.NAME))
+ .to(PlainTextFormatter.class);
+
DynamicSet.bind(binder(), ProjectWebLink.class)
.to(XDocWebLink.class);
DynamicSet.bind(binder(), BranchWebLink.class)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocFileWebLink.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocFileWebLink.java
index cd5d676..934e9b1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocFileWebLink.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocFileWebLink.java
@@ -18,13 +18,13 @@
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.webui.FileWebLink;
import com.google.gerrit.httpd.resources.Resource;
-import com.google.gerrit.server.FileTypeRegistry;
-import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
import com.google.inject.name.Named;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters;
+
public class XDocFileWebLink extends XDocWebLink implements FileWebLink {
@Inject
@@ -34,10 +34,8 @@
@Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache,
XDocProjectConfig.Factory cfgFactory,
ProjectCache projectCache,
- FileTypeRegistry fileTypeRegistry,
- PluginConfigFactory pluginCfgFactory) {
- super(pluginName, repoManager, cache, cfgFactory, projectCache,
- fileTypeRegistry, pluginCfgFactory);
+ Formatters formatters) {
+ super(pluginName, repoManager, cache, cfgFactory, projectCache, formatters);
}
@Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
index 6fbce26..b7fadf4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
@@ -14,48 +14,31 @@
package com.googlesource.gerrit.plugins.xdocs;
-import eu.medsea.mimeutil.MimeType;
+import com.googlesource.gerrit.plugins.xdocs.formatter.MarkdownFormatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.PlainTextFormatter;
import org.eclipse.jgit.lib.Config;
-import java.util.HashMap;
-import java.util.Map;
-
public class XDocGlobalConfig {
private static final String SECTION_FORMATTER = "formatter";
- private static final String KEY_ALLOW_HTML = "allowHtml";
- private static final String KEY_MIME_TYPE = "mimeType";
- enum Formatter {
- MARKDOWN, PLAIN_TEXT;
- }
+ public static final String KEY_ALLOW_HTML = "allowHtml";
+ public static final String KEY_MIME_TYPE = "mimeType";
private final Config cfg;
- XDocGlobalConfig(Config cfg) {
+ public XDocGlobalConfig(Config cfg) {
this.cfg = cfg;
}
- boolean isHtmlAllowed(Formatter formatter) {
- return cfg.getBoolean(SECTION_FORMATTER, formatter.name(),
- KEY_ALLOW_HTML, false);
- }
-
- Map<MimeType, Formatter> getMimeTypes() {
- Map<MimeType, Formatter> mimeTypes = new HashMap<>();
- for (Formatter f : Formatter.values()) {
- for (String mimeType :
- cfg.getStringList(SECTION_FORMATTER, f.name(), KEY_MIME_TYPE)) {
- mimeTypes.put(new MimeType(mimeType), f);
- }
- }
- return mimeTypes;
+ public ConfigSection getFormatterConfig(String formatterName) {
+ return new ConfigSection(cfg, SECTION_FORMATTER, formatterName);
}
static void initialize(Config cfg) {
- cfg.setString(SECTION_FORMATTER, Formatter.MARKDOWN.name(), KEY_MIME_TYPE,
+ cfg.setString(SECTION_FORMATTER, MarkdownFormatter.NAME, KEY_MIME_TYPE,
"text/x-markdown");
- cfg.setString(SECTION_FORMATTER, Formatter.PLAIN_TEXT.name(), KEY_MIME_TYPE,
+ cfg.setString(SECTION_FORMATTER, PlainTextFormatter.NAME, KEY_MIME_TYPE,
"text/plain");
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocLoader.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocLoader.java
index ebfb54d..9fd8ac1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocLoader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocLoader.java
@@ -15,7 +15,6 @@
package com.googlesource.gerrit.plugins.xdocs;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
import com.google.common.base.Strings;
import com.google.common.cache.CacheLoader;
@@ -28,13 +27,13 @@
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.PluginConfigFactory;
-import com.google.gerrit.server.documentation.MarkdownFormatter;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.Formatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters.FormatterProvider;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@@ -45,7 +44,6 @@
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
-import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -58,22 +56,31 @@
private final Provider<String> webUrl;
private final String pluginName;
private final PluginConfigFactory cfgFactory;
+ private final Formatters formatters;
@Inject
XDocLoader(GitRepositoryManager repoManager,
@CanonicalWebUrl Provider<String> webUrl,
@PluginName String pluginName,
- PluginConfigFactory cfgFactory) {
+ PluginConfigFactory cfgFactory,
+ Formatters formatters) {
this.repoManager = repoManager;
this.webUrl = webUrl;
this.pluginName = pluginName;
this.cfgFactory = cfgFactory;
+ this.formatters = formatters;
}
@Override
public Resource load(String strKey) throws Exception {
XDocResourceKey key = XDocResourceKey.fromString(strKey);
- XDocGlobalConfig cfg = new XDocGlobalConfig(cfgFactory.getGlobalPluginConfig(pluginName));
+ XDocGlobalConfig cfg =
+ new XDocGlobalConfig(cfgFactory.getGlobalPluginConfig(pluginName));
+ FormatterProvider formatter = formatters.getByName(key.getFormatter());
+ if (formatter == null) {
+ return Resource.NOT_FOUND;
+ }
+ ConfigSection formatterCfg = cfg.getFormatterConfig(formatter.getName());
Repository repo = repoManager.openRepository(key.getProject());
try {
RevWalk rw = new RevWalk(repo);
@@ -91,8 +98,9 @@
ObjectId objectId = tw.getObjectId(0);
ObjectLoader loader = repo.open(objectId);
byte[] raw = loader.getBytes(Integer.MAX_VALUE);
- byte[] html = formatAsHtml(cfg, key.getFormatter(),
- replaceMacros(key.getProject(), new String(raw, UTF_8)));
+ String html =
+ formatter.get().format(formatterCfg,
+ replaceMacros(key.getProject(), raw));
return getAsHtmlResource(html, commit.getCommitTime());
} finally {
tw.release();
@@ -105,7 +113,7 @@
}
}
- private String replaceMacros(Project.NameKey project, String raw) {
+ private String replaceMacros(Project.NameKey project, byte[] raw) {
Map<String, String> macros = Maps.newHashMap();
String url = webUrl.get();
@@ -117,7 +125,8 @@
macros.put("PROJECT", project.get());
macros.put("PROJECT_URL", url + "#/admin/projects/" + project.get());
- Matcher m = Pattern.compile("(\\\\)?@([A-Z_]+)@").matcher(raw);
+ Matcher m = Pattern.compile("(\\\\)?@([A-Z_]+)@")
+ .matcher(new String(raw, UTF_8));
StringBuffer sb = new StringBuffer();
while (m.find()) {
String key = m.group(2);
@@ -132,35 +141,8 @@
return sb.toString();
}
- private byte[] formatAsHtml(XDocGlobalConfig cfg, Formatter formatter,
- String raw) throws IOException {
- switch (formatter) {
- case MARKDOWN:
- return formatMarkdownAsHtml(cfg, raw);
- case PLAIN_TEXT:
- return formatTxtAsHtml(raw);
- default:
- throw new IllegalStateException("Unsupported formatter: "
- + formatter.name());
- }
- }
-
- private byte[] formatMarkdownAsHtml(XDocGlobalConfig cfg, String md)
- throws IOException {
- MarkdownFormatter f = new MarkdownFormatter();
- if (!cfg.isHtmlAllowed(Formatter.MARKDOWN)) {
- f.suppressHtml();
- }
- return f.markdownToDocHtml(md, UTF_8.name());
- }
-
- private byte[] formatTxtAsHtml(String txt) {
- String html = "<pre>" + escapeHtml(txt) + "</pre>";
- return html.getBytes(UTF_8);
- }
-
- private Resource getAsHtmlResource(byte[] html, int lastModified) {
- return new SmallResource(html)
+ private Resource getAsHtmlResource(String html, int lastModified) {
+ return new SmallResource(html.getBytes(UTF_8))
.setContentType("text/html")
.setCharacterEncoding(UTF_8.name())
.setLastModified(lastModified);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocResourceKey.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocResourceKey.java
index 09bc287..2407490 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocResourceKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocResourceKey.java
@@ -18,17 +18,15 @@
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.reviewdb.client.Project;
-import com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.Formatter;
-
import org.eclipse.jgit.lib.ObjectId;
public class XDocResourceKey {
- private final Formatter formatter;
+ private final String formatter;
private final Project.NameKey project;
private final String resource;
private final ObjectId revId;
- XDocResourceKey(Formatter formatter, Project.NameKey project, String r,
+ XDocResourceKey(String formatter, Project.NameKey project, String r,
ObjectId revId) {
this.formatter = formatter;
this.project = project;
@@ -36,7 +34,7 @@
this.revId = revId;
}
- public Formatter getFormatter() {
+ public String getFormatter() {
return formatter;
}
@@ -69,7 +67,7 @@
public String asString() {
StringBuilder b = new StringBuilder();
- b.append(formatter.name());
+ b.append(IdString.fromDecoded(formatter).encoded());
b.append("/");
b.append(IdString.fromDecoded(project.get()).encoded());
b.append("/");
@@ -81,12 +79,12 @@
public static XDocResourceKey fromString(String str) {
String[] s = str.split("/");
- Formatter formatter = null;
+ String formatter = null;
String project = null;
String file = null;
String revision = null;
if (s.length > 0) {
- formatter = Formatter.valueOf(s[0]);
+ formatter = IdString.fromUrl(s[0]).get();
}
if (s.length > 1) {
project = IdString.fromUrl(s[1]).get();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocServlet.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocServlet.java
index 2befa05..786a646 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocServlet.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocServlet.java
@@ -22,7 +22,6 @@
import com.google.common.cache.LoadingCache;
import com.google.common.hash.Hashing;
import com.google.common.net.HttpHeaders;
-import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -31,7 +30,6 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.FileTypeRegistry;
-import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.GetHead;
import com.google.gerrit.server.project.NoSuchProjectException;
@@ -45,7 +43,8 @@
import com.google.inject.Singleton;
import com.google.inject.name.Named;
-import com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.Formatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters.FormatterProvider;
import eu.medsea.mimeutil.MimeType;
@@ -62,7 +61,6 @@
import org.eclipse.jgit.treewalk.filter.PathFilter;
import java.io.IOException;
-import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServlet;
@@ -83,8 +81,7 @@
private final LoadingCache<String, Resource> docCache;
private final FileTypeRegistry fileTypeRegistry;
private final XDocProjectConfig.Factory cfgFactory;
- private final String pluginName;
- private final PluginConfigFactory pluginCfgFactory;
+ private final Formatters formatters;
@Inject
XDocServlet(
@@ -96,8 +93,7 @@
@Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache,
FileTypeRegistry fileTypeRegistry,
XDocProjectConfig.Factory cfgFactory,
- @PluginName String pluginName,
- PluginConfigFactory pluginCfgFactory) {
+ Formatters formatters) {
this.db = db;
this.projectControlFactory = projectControlFactory;
this.projectCache = projectCache;
@@ -106,8 +102,7 @@
this.docCache = cache;
this.fileTypeRegistry = fileTypeRegistry;
this.cfgFactory = cfgFactory;
- this.pluginName = pluginName;
- this.pluginCfgFactory = pluginCfgFactory;
+ this.formatters = formatters;
}
@Override
@@ -130,11 +125,9 @@
res.sendRedirect(getRedirectUrl(req, key, cfg));
return;
}
- XDocGlobalConfig pluginCfg =
- new XDocGlobalConfig(pluginCfgFactory.getGlobalPluginConfig(pluginName));
MimeType mimeType = fileTypeRegistry.getMimeType(key.file, null);
- Map<MimeType, Formatter> mimeTypes = pluginCfg.getMimeTypes();
- if (!mimeTypes.keySet().contains(mimeType)
+ FormatterProvider formatter = formatters.get(key.file);
+ if (formatter == null
&& !("image".equals(mimeType.getMediaType())
&& fileTypeRegistry.isSafeInline(mimeType))) {
Resource.NOT_FOUND.send(req, res);
@@ -191,10 +184,9 @@
}
Resource rsc;
- Formatter formatter = mimeTypes.get(mimeType);
if (formatter != null) {
rsc = docCache.getUnchecked(
- (new XDocResourceKey(formatter, key.project, key.file, revId)).asString());
+ (new XDocResourceKey(formatter.getName(), key.project, key.file, revId)).asString());
} else if ("image".equals(mimeType.getMediaType())) {
rsc = getImageResource(repo, revId, key.file);
} else {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocWebLink.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocWebLink.java
index 2c25095..e0b7a60 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocWebLink.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocWebLink.java
@@ -21,8 +21,6 @@
import com.google.gerrit.extensions.webui.ProjectWebLink;
import com.google.gerrit.httpd.resources.Resource;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.FileTypeRegistry;
-import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
@@ -30,9 +28,8 @@
import com.google.inject.Singleton;
import com.google.inject.name.Named;
-import com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.Formatter;
-
-import eu.medsea.mimeutil.MimeType;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters;
+import com.googlesource.gerrit.plugins.xdocs.formatter.Formatters.FormatterProvider;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -52,8 +49,7 @@
private final LoadingCache<String, Resource> docCache;
private final XDocProjectConfig.Factory cfgFactory;
private final ProjectCache projectCache;
- private final FileTypeRegistry fileTypeRegistry;
- private final PluginConfigFactory pluginCfgFactory;
+ private final Formatters formatters;
@Inject
XDocWebLink(
@@ -62,15 +58,13 @@
@Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache,
XDocProjectConfig.Factory cfgFactory,
ProjectCache projectCache,
- FileTypeRegistry fileTypeRegistry,
- PluginConfigFactory pluginCfgFactory) {
+ Formatters formatters) {
this.pluginName = pluginName;
this.repoManager = repoManager;
this.docCache = cache;
this.cfgFactory = cfgFactory;
this.projectCache = projectCache;
- this.fileTypeRegistry = fileTypeRegistry;
- this.pluginCfgFactory = pluginCfgFactory;
+ this.formatters = formatters;
}
@Override
@@ -96,10 +90,7 @@
public String getPatchUrl(String projectName, String revision,
String fileName) {
- XDocGlobalConfig pluginCfg =
- new XDocGlobalConfig(pluginCfgFactory.getGlobalPluginConfig(pluginName));
- MimeType mimeType = fileTypeRegistry.getMimeType(fileName, null);
- Formatter formatter = pluginCfg.getMimeTypes().get(mimeType);
+ FormatterProvider formatter = formatters.get(fileName);
if (formatter == null) {
return null;
}
@@ -113,7 +104,7 @@
return null;
}
Resource rsc = docCache.getUnchecked(
- (new XDocResourceKey(formatter, p, fileName, revId)).asString());
+ (new XDocResourceKey(formatter.getName(), p, fileName, revId)).asString());
if (rsc != Resource.NOT_FOUND) {
StringBuilder url = new StringBuilder();
url.append("plugins/");
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/Formatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/Formatter.java
new file mode 100644
index 0000000..e934c0d
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/Formatter.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.xdocs.formatter;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+import com.googlesource.gerrit.plugins.xdocs.ConfigSection;
+
+import java.io.IOException;
+
+@ExtensionPoint
+public interface Formatter {
+
+ /**
+ * Formats the given raw text as html.
+ *
+ * @param cfg the configuration for this formatter
+ * @param raw the raw text
+ * @return the given text formatted as html
+ * @throws IOException thrown if the formatting fails
+ */
+ public String format(ConfigSection cfg, String raw) throws IOException;
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/Formatters.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/Formatters.java
new file mode 100644
index 0000000..b338027
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/Formatters.java
@@ -0,0 +1,100 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.xdocs.formatter;
+
+import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_MIME_TYPE;
+
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.server.FileTypeRegistry;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig;
+
+import eu.medsea.mimeutil.MimeType;
+
+import java.util.Map.Entry;
+
+@Singleton
+public class Formatters {
+ private final String pluginName;
+ private final PluginConfigFactory pluginCfgFactory;
+ private final FileTypeRegistry fileTypeRegistry;
+ private final DynamicMap<Formatter> formatters;
+
+ @Inject
+ Formatters(
+ @PluginName String pluginName,
+ PluginConfigFactory pluginCfgFactory,
+ FileTypeRegistry fileTypeRegistry,
+ DynamicMap<Formatter> formatters) {
+ this.pluginName = pluginName;
+ this.pluginCfgFactory = pluginCfgFactory;
+ this.fileTypeRegistry = fileTypeRegistry;
+ this.formatters = formatters;
+ }
+
+ public FormatterProvider get(String fileName) {
+ XDocGlobalConfig pluginCfg =
+ new XDocGlobalConfig(pluginCfgFactory.getGlobalPluginConfig(pluginName));
+ MimeType mimeType = fileTypeRegistry.getMimeType(fileName, null);
+ for (String pluginName : formatters.plugins()) {
+ for (Entry<String, Provider<Formatter>> e :
+ formatters.byPlugin(pluginName).entrySet()) {
+ for (String configuredMimeType :
+ pluginCfg.getFormatterConfig(e.getKey()).getStringList(KEY_MIME_TYPE)) {
+ if (mimeType.equals(new MimeType(configuredMimeType))) {
+ return new FormatterProvider(e.getKey(), e.getValue());
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public FormatterProvider getByName(String formatterName) {
+ for (String pluginName : formatters.plugins()) {
+ for (Entry<String, Provider<Formatter>> e :
+ formatters.byPlugin(pluginName).entrySet()) {
+ if (formatterName.equals(e.getKey())) {
+ return new FormatterProvider(formatterName, e.getValue());
+ }
+ }
+ }
+ return null;
+ }
+
+ public static class FormatterProvider {
+ private final String name;
+ private final Provider<Formatter> formatter;
+
+ FormatterProvider(String name,
+ Provider<Formatter> formatter) {
+ this.name = name;
+ this.formatter = formatter;
+ }
+
+ public Formatter get() {
+ return formatter.get();
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
new file mode 100644
index 0000000..6a3a896
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.xdocs.formatter;
+
+import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_ALLOW_HTML;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.googlesource.gerrit.plugins.xdocs.ConfigSection;
+
+import java.io.UnsupportedEncodingException;
+
+public class MarkdownFormatter implements Formatter {
+ public final static String NAME = "MARKDOWN";
+
+ @Override
+ public String format(ConfigSection cfg, String raw)
+ throws UnsupportedEncodingException {
+ com.google.gerrit.server.documentation.MarkdownFormatter f =
+ new com.google.gerrit.server.documentation.MarkdownFormatter();
+ if (!cfg.getBoolean(KEY_ALLOW_HTML, false)) {
+ f.suppressHtml();
+ }
+ byte[] b = f.markdownToDocHtml(raw, UTF_8.name());
+ return new String(b, UTF_8);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/PlainTextFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/PlainTextFormatter.java
new file mode 100644
index 0000000..d6ad0cd
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/PlainTextFormatter.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.xdocs.formatter;
+
+import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
+
+import com.googlesource.gerrit.plugins.xdocs.ConfigSection;
+
+public class PlainTextFormatter implements Formatter {
+ public final static String NAME = "PLAIN_TEXT";
+
+ @Override
+ public String format(ConfigSection cfg, String raw) {
+ return "<pre>" + escapeHtml(raw) + "</pre>";
+ }
+}