Allow to configure the documentation index file per project

At the moment a README.md file in the project root serves as entry
point to the project documentation and the documentation links in the
web UI link to this file. This change makes the index file
configurable per project, e.g. it could be set to
'Documentation/README.md' or 'index.md'. This feature will be
important in future when the plugin supports also other syntaxes, e.g.
a project may use AsciiDoc for their project documentation and then
wants to use 'README.adoc' as entry point for the project
documentation. The configuration is inherited from the parent
project. 'README.md' stays the default if nothing is configured.

Change-Id: Ie9df03b44adc85cc2ce38713a01075690b11b837
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
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 28c89a5..9b20c57 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
@@ -22,12 +22,12 @@
 import com.google.gerrit.extensions.webui.GerritTopMenu;
 import com.google.gerrit.extensions.webui.ProjectWebLink;
 import com.google.gerrit.extensions.webui.TopMenu;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.server.config.FactoryModule;
 import com.google.inject.Inject;
 
 import java.util.List;
 
-public class Module extends AbstractModule {
+public class Module extends FactoryModule {
   private final String pluginName;
 
   @Inject
@@ -38,6 +38,7 @@
   @Override
   protected void configure() {
     install(new XDocLoader.Module());
+    factory(XDocConfig.Factory.class);
 
     DynamicSet.bind(binder(), ProjectWebLink.class)
         .to(XDocWebLink.class);
@@ -53,7 +54,7 @@
         url.append("/plugins/");
         url.append(pluginName);
         url.append(XDocServlet.PATH_PREFIX);
-        url.append("${projectName}/README.md");
+        url.append("${projectName}");
         return Lists.newArrayList(new MenuEntry(GerritTopMenu.PROJECTS,
             Lists.newArrayList(new MenuItem("Readme", url.toString()))));
       }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocConfig.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocConfig.java
new file mode 100644
index 0000000..8af2182
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocConfig.java
@@ -0,0 +1,48 @@
+// 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 com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.lib.Config;
+
+public class XDocConfig {
+  interface Factory {
+    XDocConfig create(ProjectState project);
+  }
+
+  private static final String SECTION_WEB = "web";
+  private static final String KEY_INDEX_FILE = "indexFile";
+  private static final String DEFAULT_INDEX_FILE = "README.md";
+
+  private final Config cfg;
+
+  @Inject
+  XDocConfig(@PluginName String pluginName, PluginConfigFactory cfgFactory,
+      @Assisted ProjectState project) {
+    this.cfg = cfgFactory.getProjectPluginConfigWithInheritance(project, pluginName);
+  }
+
+  String getIndexFile() {
+    return MoreObjects.firstNonNull(
+        cfg.getString(SECTION_WEB, null, KEY_INDEX_FILE),
+        DEFAULT_INDEX_FILE);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocPatchWebLink.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocPatchWebLink.java
index 912e520..b951445 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocPatchWebLink.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocPatchWebLink.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.extensions.webui.FileWebLink;
 import com.google.gerrit.httpd.resources.Resource;
 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;
 
@@ -28,8 +29,10 @@
   XDocPatchWebLink(
       @PluginName String pluginName,
       GitRepositoryManager repoManager,
-      @Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache) {
-    super(pluginName, repoManager, cache);
+      @Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache,
+      XDocConfig.Factory cfgFactory,
+      ProjectCache projectCache) {
+    super(pluginName, repoManager, cache, cfgFactory, projectCache);
   }
 
   @Override
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 73cd47d..64e3d60 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocServlet.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocServlet.java
@@ -36,6 +36,7 @@
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectResource;
+import com.google.gerrit.server.project.ProjectState;
 import com.google.gwtexpui.server.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -76,6 +77,7 @@
   private final GitRepositoryManager repoManager;
   private final LoadingCache<String, Resource> docCache;
   private final FileTypeRegistry fileTypeRegistry;
+  private final XDocConfig.Factory cfgFactory;
 
   @Inject
   XDocServlet(
@@ -85,7 +87,8 @@
       Provider<GetHead> getHead,
       GitRepositoryManager repoManager,
       @Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache,
-      FileTypeRegistry fileTypeRegistry) {
+      FileTypeRegistry fileTypeRegistry,
+      XDocConfig.Factory cfgFactory) {
     this.db = db;
     this.projectControlFactory = projectControlFactory;
     this.projectCache = projectCache;
@@ -93,6 +96,7 @@
     this.repoManager = repoManager;
     this.docCache = cache;
     this.fileTypeRegistry = fileTypeRegistry;
+    this.cfgFactory = cfgFactory;
   }
 
   @Override
@@ -105,12 +109,14 @@
     }
 
     ResourceKey key = ResourceKey.fromPath(req.getPathInfo());
-    if (projectCache.get(key.project) == null) {
+    ProjectState state = projectCache.get(key.project);
+    if (state == null) {
       Resource.NOT_FOUND.send(req, res);
       return;
     }
+    XDocConfig cfg = cfgFactory.create(state);
     if (key.file == null) {
-      res.sendRedirect(getRedirectUrl(req, key));
+      res.sendRedirect(getRedirectUrl(req, key, cfg));
       return;
     }
     MimeType mimeType = fileTypeRegistry.getMimeType(key.file, null);
@@ -244,7 +250,8 @@
         .hash().toString();
   }
 
-  private String getRedirectUrl(HttpServletRequest req, ResourceKey key) {
+  private String getRedirectUrl(HttpServletRequest req, ResourceKey key,
+      XDocConfig cfg) {
     StringBuilder redirectUrl = new StringBuilder();
     redirectUrl.append(req.getRequestURL().substring(0,
         req.getRequestURL().length() - req.getRequestURI().length()));
@@ -257,7 +264,7 @@
       redirectUrl.append(key.revision);
       redirectUrl.append("/");
     }
-    redirectUrl.append("README.md");
+    redirectUrl.append(IdString.fromDecoded(cfg.getIndexFile()).encoded());
     return redirectUrl.toString();
   }
 
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 75b9224..5355572 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocWebLink.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocWebLink.java
@@ -22,6 +22,8 @@
 import com.google.gerrit.httpd.resources.Resource;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
@@ -42,15 +44,21 @@
   private final String pluginName;
   private final GitRepositoryManager repoManager;
   private final LoadingCache<String, Resource> docCache;
+  private final XDocConfig.Factory cfgFactory;
+  private final ProjectCache projectCache;
 
   @Inject
   XDocWebLink(
       @PluginName String pluginName,
       GitRepositoryManager repoManager,
-      @Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache) {
+      @Named(XDocLoader.Module.X_DOC_RESOURCES) LoadingCache<String, Resource> cache,
+      XDocConfig.Factory cfgFactory,
+      ProjectCache projectCache) {
     this.pluginName = pluginName;
     this.repoManager = repoManager;
     this.docCache = cache;
+    this.cfgFactory = cfgFactory;
+    this.projectCache = projectCache;
   }
 
   @Override
@@ -65,7 +73,13 @@
 
   @Override
   public String getBranchUrl(String projectName, String branchName) {
-    return getPatchUrl(projectName, branchName, "README.md");
+    ProjectState state = projectCache.get(new Project.NameKey(projectName));
+    if (state == null) {
+      // project not found -> no link
+      return null;
+    }
+    return getPatchUrl(projectName, branchName,
+        cfgFactory.create(state).getIndexFile());
   }
 
   public String getPatchUrl(String projectName, String revision,
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
new file mode 100644
index 0000000..fe171ca
--- /dev/null
+++ b/src/main/resources/Documentation/config.md
@@ -0,0 +1,20 @@
+Configuration
+=============
+
+The configuration of the @PLUGIN@ plugin is done on project level in
+the `@PLUGIN@.config` file in the `refs/meta/config` branch of the
+project.
+
+```
+  [web]
+    indexFile = Documentation/README.md
+```
+
+<a id="webIndexFile">
+web.indexFile
+:	The documentation file that serves as entry point for the project
+	documentation.
+
+	The documentation links in web UI will link to this file.
+
+	Default: `README.md`
diff --git a/src/main/resources/Documentation/user.md b/src/main/resources/Documentation/user.md
index 1ea0c4f..1c0af7e 100644
--- a/src/main/resources/Documentation/user.md
+++ b/src/main/resources/Documentation/user.md
@@ -5,7 +5,8 @@
 project documentation as HTML pages.
 
 The entry point to the project documentation is a `README.md` file in
-the root directory of a project.
+the root directory of a project (if not [configured](config.html#webIndexFile)
+differently).
 
 If a project has a `README.md` file in its root directory then a link
 to the project documentation is displayed for it in the