Serve static resources for non-jar Server plugins
Abstract from the Server plugins external packaging and allows to serve static resources from any form of Server plugin that exposes a PluginContentScanner. This allows potentially other forms of plugins (e.g. Scripting, directory-based or any other) to provide their on-line documentation and serve their static resources. Change-Id: I80b8159cf87255e3132298f5863b374b5bd44a6c
This commit is contained in:
		@@ -14,7 +14,11 @@
 | 
			
		||||
 | 
			
		||||
package com.google.gerrit.httpd.plugins;
 | 
			
		||||
 | 
			
		||||
import static com.google.gerrit.server.plugins.PluginEntry.ATTR_CHARACTER_ENCODING;
 | 
			
		||||
import static com.google.gerrit.server.plugins.PluginEntry.ATTR_CONTENT_TYPE;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.CharMatcher;
 | 
			
		||||
import com.google.common.base.Optional;
 | 
			
		||||
import com.google.common.base.Splitter;
 | 
			
		||||
import com.google.common.base.Strings;
 | 
			
		||||
import com.google.common.cache.Cache;
 | 
			
		||||
@@ -27,9 +31,11 @@ import com.google.gerrit.server.config.CanonicalWebUrl;
 | 
			
		||||
import com.google.gerrit.server.config.GerritServerConfig;
 | 
			
		||||
import com.google.gerrit.server.documentation.MarkdownFormatter;
 | 
			
		||||
import com.google.gerrit.server.plugins.Plugin;
 | 
			
		||||
import com.google.gerrit.server.plugins.Plugin.ApiType;
 | 
			
		||||
import com.google.gerrit.server.plugins.PluginContentScanner;
 | 
			
		||||
import com.google.gerrit.server.plugins.PluginEntry;
 | 
			
		||||
import com.google.gerrit.server.plugins.PluginsCollection;
 | 
			
		||||
import com.google.gerrit.server.plugins.ReloadPluginListener;
 | 
			
		||||
import com.google.gerrit.server.plugins.ServerPlugin;
 | 
			
		||||
import com.google.gerrit.server.plugins.StartPluginListener;
 | 
			
		||||
import com.google.gerrit.server.ssh.SshInfo;
 | 
			
		||||
import com.google.gwtexpui.server.CacheHeaders;
 | 
			
		||||
@@ -55,14 +61,11 @@ import java.io.OutputStream;
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.Enumeration;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.ConcurrentMap;
 | 
			
		||||
import java.util.jar.Attributes;
 | 
			
		||||
import java.util.jar.JarEntry;
 | 
			
		||||
import java.util.jar.JarFile;
 | 
			
		||||
import java.util.regex.Matcher;
 | 
			
		||||
import java.util.regex.Pattern;
 | 
			
		||||
 | 
			
		||||
@@ -83,13 +86,6 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
  private static final long serialVersionUID = 1L;
 | 
			
		||||
  private static final Logger log
 | 
			
		||||
      = LoggerFactory.getLogger(HttpPluginServlet.class);
 | 
			
		||||
  private static final Comparator<JarEntry> JAR_ENTRY_COMPARATOR_BY_NAME =
 | 
			
		||||
      new Comparator<JarEntry>() {
 | 
			
		||||
        @Override
 | 
			
		||||
        public int compare(JarEntry a, JarEntry b) {
 | 
			
		||||
          return a.getName().compareTo(b.getName());
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
  private final MimeUtilFileTypeRegistry mimeUtil;
 | 
			
		||||
  private final Provider<String> webUrl;
 | 
			
		||||
@@ -276,17 +272,17 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (file.startsWith(holder.staticPrefix)) {
 | 
			
		||||
      JarFile jar = jarFileOf(holder.plugin);
 | 
			
		||||
      if (jar != null) {
 | 
			
		||||
        JarEntry entry = jar.getJarEntry(file);
 | 
			
		||||
        if (exists(entry)) {
 | 
			
		||||
          sendResource(jar, entry, key, res);
 | 
			
		||||
      if (holder.plugin.getApiType() == ApiType.JS) {
 | 
			
		||||
        sendJsPlugin(holder.plugin, key, req, res);
 | 
			
		||||
      } else {
 | 
			
		||||
        PluginContentScanner scanner = holder.plugin.getContentScanner();
 | 
			
		||||
        Optional<PluginEntry> entry = scanner.getEntry(file);
 | 
			
		||||
        if (entry.isPresent()) {
 | 
			
		||||
          sendResource(scanner, entry.get(), key, res);
 | 
			
		||||
        } else {
 | 
			
		||||
          resourceCache.put(key, Resource.NOT_FOUND);
 | 
			
		||||
          Resource.NOT_FOUND.send(req, res);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        sendJsPlugin(holder.plugin, key, req, res);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (file.equals(
 | 
			
		||||
        holder.docPrefix.substring(0, holder.docPrefix.length() - 1))) {
 | 
			
		||||
@@ -294,19 +290,19 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    } else if (file.startsWith(holder.docPrefix) && file.endsWith("/")) {
 | 
			
		||||
      res.sendRedirect(uri + "index.html");
 | 
			
		||||
    } else if (file.startsWith(holder.docPrefix)) {
 | 
			
		||||
      JarFile jar = jarFileOf(holder.plugin);
 | 
			
		||||
      JarEntry entry = jar.getJarEntry(file);
 | 
			
		||||
      if (!exists(entry)) {
 | 
			
		||||
        entry = findSource(jar, file);
 | 
			
		||||
      PluginContentScanner scanner = holder.plugin.getContentScanner();
 | 
			
		||||
      Optional<PluginEntry> entry = scanner.getEntry(file);
 | 
			
		||||
      if (!entry.isPresent()) {
 | 
			
		||||
        entry = findSource(scanner, file);
 | 
			
		||||
      }
 | 
			
		||||
      if (!exists(entry) && file.endsWith("/index.html")) {
 | 
			
		||||
      if (!entry.isPresent() && file.endsWith("/index.html")) {
 | 
			
		||||
        String pfx = file.substring(0, file.length() - "index.html".length());
 | 
			
		||||
        sendAutoIndex(jar, pfx, holder.plugin.getName(), key, res,
 | 
			
		||||
        sendAutoIndex(scanner, pfx, holder.plugin.getName(), key, res,
 | 
			
		||||
            holder.plugin.getSrcFile().lastModified());
 | 
			
		||||
      } else if (exists(entry) && entry.getName().endsWith(".md")) {
 | 
			
		||||
        sendMarkdownAsHtml(jar, entry, holder.plugin.getName(), key, res);
 | 
			
		||||
      } else if (exists(entry)) {
 | 
			
		||||
        sendResource(jar, entry, key, res);
 | 
			
		||||
      } else if (entry.isPresent() && entry.get().getName().endsWith(".md")) {
 | 
			
		||||
        sendMarkdownAsHtml(scanner, entry.get(), holder.plugin.getName(), key, res);
 | 
			
		||||
      } else if (entry.isPresent()) {
 | 
			
		||||
        sendResource(scanner, entry.get(), key, res);
 | 
			
		||||
      } else {
 | 
			
		||||
        resourceCache.put(key, Resource.NOT_FOUND);
 | 
			
		||||
        Resource.NOT_FOUND.send(req, res);
 | 
			
		||||
@@ -317,18 +313,18 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void appendEntriesSection(JarFile jar, List<JarEntry> entries,
 | 
			
		||||
  private void appendEntriesSection(PluginContentScanner scanner, List<PluginEntry> entries,
 | 
			
		||||
      String sectionTitle, StringBuilder md, String prefix,
 | 
			
		||||
      int nameOffset) throws IOException {
 | 
			
		||||
    if (!entries.isEmpty()) {
 | 
			
		||||
      md.append("## ").append(sectionTitle).append(" ##\n");
 | 
			
		||||
      for(JarEntry entry : entries) {
 | 
			
		||||
      for(PluginEntry entry : entries) {
 | 
			
		||||
        String rsrc = entry.getName().substring(prefix.length());
 | 
			
		||||
        String entryTitle;
 | 
			
		||||
        if (rsrc.endsWith(".html")) {
 | 
			
		||||
          entryTitle = rsrc.substring(nameOffset, rsrc.length() - 5).replace('-', ' ');
 | 
			
		||||
        } else if (rsrc.endsWith(".md")) {
 | 
			
		||||
          entryTitle = extractTitleFromMarkdown(jar, entry);
 | 
			
		||||
          entryTitle = extractTitleFromMarkdown(scanner, entry);
 | 
			
		||||
          if (Strings.isNullOrEmpty(entryTitle)) {
 | 
			
		||||
            entryTitle = rsrc.substring(nameOffset, rsrc.length() - 3).replace('-', ' ');
 | 
			
		||||
          }
 | 
			
		||||
@@ -342,24 +338,25 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void sendAutoIndex(JarFile jar,
 | 
			
		||||
  private void sendAutoIndex(PluginContentScanner scanner,
 | 
			
		||||
      String prefix, String pluginName,
 | 
			
		||||
      ResourceKey cacheKey, HttpServletResponse res, long lastModifiedTime)
 | 
			
		||||
      ResourceKey cacheKey, HttpServletResponse res,long lastModifiedTime)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    List<JarEntry> cmds = Lists.newArrayList();
 | 
			
		||||
    List<JarEntry> servlets = Lists.newArrayList();
 | 
			
		||||
    List<JarEntry> restApis = Lists.newArrayList();
 | 
			
		||||
    List<JarEntry> docs = Lists.newArrayList();
 | 
			
		||||
    JarEntry about = null;
 | 
			
		||||
    Enumeration<JarEntry> entries = jar.entries();
 | 
			
		||||
    List<PluginEntry> cmds = Lists.newArrayList();
 | 
			
		||||
    List<PluginEntry> servlets = Lists.newArrayList();
 | 
			
		||||
    List<PluginEntry> restApis = Lists.newArrayList();
 | 
			
		||||
    List<PluginEntry> docs = Lists.newArrayList();
 | 
			
		||||
    PluginEntry about = null;
 | 
			
		||||
    Enumeration<PluginEntry> entries = scanner.entries();
 | 
			
		||||
    while (entries.hasMoreElements()) {
 | 
			
		||||
      JarEntry entry = entries.nextElement();
 | 
			
		||||
      PluginEntry entry = entries.nextElement();
 | 
			
		||||
      String name = entry.getName();
 | 
			
		||||
      long size = entry.getSize();
 | 
			
		||||
      Optional<Long> size = entry.getSize();
 | 
			
		||||
      if (name.startsWith(prefix)
 | 
			
		||||
          && (name.endsWith(".md")
 | 
			
		||||
              || name.endsWith(".html"))
 | 
			
		||||
          && 0 < size && size <= SMALL_RESOURCE) {
 | 
			
		||||
              && size.isPresent()
 | 
			
		||||
          && 0 < size.get() && size.get() <= SMALL_RESOURCE) {
 | 
			
		||||
        name = name.substring(prefix.length());
 | 
			
		||||
        if (name.startsWith("cmd-")) {
 | 
			
		||||
          cmds.add(entry);
 | 
			
		||||
@@ -377,16 +374,16 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Collections.sort(cmds, JAR_ENTRY_COMPARATOR_BY_NAME);
 | 
			
		||||
    Collections.sort(docs, JAR_ENTRY_COMPARATOR_BY_NAME);
 | 
			
		||||
    Collections.sort(cmds, PluginEntry.COMPARATOR_BY_NAME);
 | 
			
		||||
    Collections.sort(docs, PluginEntry.COMPARATOR_BY_NAME);
 | 
			
		||||
 | 
			
		||||
    StringBuilder md = new StringBuilder();
 | 
			
		||||
    md.append(String.format("# Plugin %s #\n", pluginName));
 | 
			
		||||
    md.append("\n");
 | 
			
		||||
    appendPluginInfoTable(md, jar.getManifest().getMainAttributes());
 | 
			
		||||
    appendPluginInfoTable(md, scanner.getManifest().getMainAttributes());
 | 
			
		||||
 | 
			
		||||
    if (about != null) {
 | 
			
		||||
      InputStreamReader isr = new InputStreamReader(jar.getInputStream(about));
 | 
			
		||||
      InputStreamReader isr = new InputStreamReader(scanner.getInputStream(about));
 | 
			
		||||
      BufferedReader reader = new BufferedReader(isr);
 | 
			
		||||
      StringBuilder aboutContent = new StringBuilder();
 | 
			
		||||
      String line;
 | 
			
		||||
@@ -407,10 +404,10 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    appendEntriesSection(jar, docs, "Documentation", md, prefix, 0);
 | 
			
		||||
    appendEntriesSection(jar, servlets, "Servlets", md, prefix, "servlet-".length());
 | 
			
		||||
    appendEntriesSection(jar, restApis, "REST APIs", md, prefix, "rest-api-".length());
 | 
			
		||||
    appendEntriesSection(jar, cmds, "Commands", md, prefix, "cmd-".length());
 | 
			
		||||
    appendEntriesSection(scanner, docs, "Documentation", md, prefix, 0);
 | 
			
		||||
    appendEntriesSection(scanner, servlets, "Servlets", md, prefix, "servlet-".length());
 | 
			
		||||
    appendEntriesSection(scanner, restApis, "REST APIs", md, prefix, "rest-api-".length());
 | 
			
		||||
    appendEntriesSection(scanner, cmds, "Commands", md, prefix, "cmd-".length());
 | 
			
		||||
 | 
			
		||||
    sendMarkdownAsHtml(md.toString(), pluginName, cacheKey, res, lastModifiedTime);
 | 
			
		||||
  }
 | 
			
		||||
@@ -494,41 +491,38 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static String extractTitleFromMarkdown(JarFile jar, JarEntry entry)
 | 
			
		||||
  private static String extractTitleFromMarkdown(PluginContentScanner scanner, PluginEntry entry)
 | 
			
		||||
        throws IOException {
 | 
			
		||||
    String charEnc = null;
 | 
			
		||||
    Attributes atts = entry.getAttributes();
 | 
			
		||||
    Map<Object, String> atts = entry.getAttrs();
 | 
			
		||||
    if (atts != null) {
 | 
			
		||||
      charEnc = Strings.emptyToNull(atts.getValue("Character-Encoding"));
 | 
			
		||||
      charEnc = Strings.emptyToNull(atts.get(ATTR_CHARACTER_ENCODING));
 | 
			
		||||
    }
 | 
			
		||||
    if (charEnc == null) {
 | 
			
		||||
      charEnc = "UTF-8";
 | 
			
		||||
    }
 | 
			
		||||
    return new MarkdownFormatter().extractTitleFromMarkdown(
 | 
			
		||||
          readWholeEntry(jar, entry),
 | 
			
		||||
          readWholeEntry(scanner, entry),
 | 
			
		||||
          charEnc);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static JarEntry findSource(JarFile jar, String file) {
 | 
			
		||||
  private static Optional<PluginEntry> findSource(
 | 
			
		||||
      PluginContentScanner scanner, String file) throws IOException {
 | 
			
		||||
    if (file.endsWith(".html")) {
 | 
			
		||||
      int d = file.lastIndexOf('.');
 | 
			
		||||
      return jar.getJarEntry(file.substring(0, d) + ".md");
 | 
			
		||||
      return scanner.getEntry(file.substring(0, d) + ".md");
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
    return Optional.absent();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static boolean exists(JarEntry entry) {
 | 
			
		||||
    return entry != null && entry.getSize() > 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void sendMarkdownAsHtml(JarFile jar, JarEntry entry,
 | 
			
		||||
  private void sendMarkdownAsHtml(PluginContentScanner scanner, PluginEntry entry,
 | 
			
		||||
      String pluginName, ResourceKey key, HttpServletResponse res)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    byte[] rawmd = readWholeEntry(jar, entry);
 | 
			
		||||
    byte[] rawmd = readWholeEntry(scanner, entry);
 | 
			
		||||
    String encoding = null;
 | 
			
		||||
    Attributes atts = entry.getAttributes();
 | 
			
		||||
    Map<Object, String> atts = entry.getAttrs();
 | 
			
		||||
    if (atts != null) {
 | 
			
		||||
      encoding = Strings.emptyToNull(atts.getValue("Character-Encoding"));
 | 
			
		||||
      encoding = Strings.emptyToNull(atts.get(ATTR_CHARACTER_ENCODING));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String txtmd = RawParseUtils.decode(
 | 
			
		||||
@@ -541,20 +535,21 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    sendMarkdownAsHtml(txtmd, pluginName, key, res, time);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void sendResource(JarFile jar, JarEntry entry,
 | 
			
		||||
  private void sendResource(PluginContentScanner scanner, PluginEntry entry,
 | 
			
		||||
      ResourceKey key, HttpServletResponse res)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    byte[] data = null;
 | 
			
		||||
    if (entry.getSize() <= SMALL_RESOURCE) {
 | 
			
		||||
      data = readWholeEntry(jar, entry);
 | 
			
		||||
    Optional<Long> size = entry.getSize();
 | 
			
		||||
    if (size.isPresent() && size.get() <= SMALL_RESOURCE) {
 | 
			
		||||
      data = readWholeEntry(scanner, entry);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String contentType = null;
 | 
			
		||||
    String charEnc = null;
 | 
			
		||||
    Attributes atts = entry.getAttributes();
 | 
			
		||||
    Map<Object, String> atts = entry.getAttrs();
 | 
			
		||||
    if (atts != null) {
 | 
			
		||||
      contentType = Strings.emptyToNull(atts.getValue("Content-Type"));
 | 
			
		||||
      charEnc = Strings.emptyToNull(atts.getValue("Character-Encoding"));
 | 
			
		||||
      contentType = Strings.emptyToNull(atts.get(ATTR_CONTENT_TYPE));
 | 
			
		||||
      charEnc = Strings.emptyToNull(atts.get(ATTR_CHARACTER_ENCODING));
 | 
			
		||||
    }
 | 
			
		||||
    if (contentType == null) {
 | 
			
		||||
      contentType = mimeUtil.getMimeType(entry.getName(), data).toString();
 | 
			
		||||
@@ -568,7 +563,9 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    if (0 < time) {
 | 
			
		||||
      res.setDateHeader("Last-Modified", time);
 | 
			
		||||
    }
 | 
			
		||||
    res.setHeader("Content-Length", Long.toString(entry.getSize()));
 | 
			
		||||
    if (size.isPresent()) {
 | 
			
		||||
      res.setHeader("Content-Length", size.get().toString());
 | 
			
		||||
    }
 | 
			
		||||
    res.setContentType(contentType);
 | 
			
		||||
    if (charEnc != null) {
 | 
			
		||||
      res.setCharacterEncoding(charEnc);
 | 
			
		||||
@@ -580,7 +577,7 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
          .setLastModified(time));
 | 
			
		||||
      res.getOutputStream().write(data);
 | 
			
		||||
    } else {
 | 
			
		||||
      writeToResponse(res, jar.getInputStream(entry));
 | 
			
		||||
      writeToResponse(res, scanner.getInputStream(entry));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -620,10 +617,10 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static byte[] readWholeEntry(JarFile jar, JarEntry entry)
 | 
			
		||||
  private static byte[] readWholeEntry(PluginContentScanner scanner, PluginEntry entry)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    byte[] data = new byte[(int) entry.getSize()];
 | 
			
		||||
    InputStream in = jar.getInputStream(entry);
 | 
			
		||||
    byte[] data = new byte[entry.getSize().get().intValue()];
 | 
			
		||||
    InputStream in = scanner.getInputStream(entry);
 | 
			
		||||
    try {
 | 
			
		||||
      IO.readFully(in, data, 0, data.length);
 | 
			
		||||
    } finally {
 | 
			
		||||
@@ -632,14 +629,6 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    return data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static JarFile jarFileOf(Plugin plugin) {
 | 
			
		||||
    if(plugin instanceof ServerPlugin) {
 | 
			
		||||
      return ((ServerPlugin) plugin).getJarFile();
 | 
			
		||||
    } else {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static class PluginHolder {
 | 
			
		||||
    final Plugin plugin;
 | 
			
		||||
    final GuiceFilter filter;
 | 
			
		||||
@@ -656,13 +645,14 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String getPrefix(Plugin plugin, String attr, String def) {
 | 
			
		||||
      JarFile jarFile = jarFileOf(plugin);
 | 
			
		||||
      if (jarFile == null) {
 | 
			
		||||
      File srcFile = plugin.getSrcFile();
 | 
			
		||||
      PluginContentScanner scanner = plugin.getContentScanner();
 | 
			
		||||
      if (srcFile == null || scanner == PluginContentScanner.EMPTY) {
 | 
			
		||||
        return def;
 | 
			
		||||
      }
 | 
			
		||||
      try {
 | 
			
		||||
        String prefix = jarFile.getManifest().getMainAttributes()
 | 
			
		||||
            .getValue(attr);
 | 
			
		||||
        String prefix =
 | 
			
		||||
            scanner.getManifest().getMainAttributes().getValue(attr);
 | 
			
		||||
        if (prefix != null) {
 | 
			
		||||
          return CharMatcher.is('/').trimFrom(prefix) + "/";
 | 
			
		||||
        } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -299,7 +299,7 @@ public class JarScanner implements PluginContentScanner {
 | 
			
		||||
 | 
			
		||||
  private PluginEntry resourceOf(JarEntry jarEntry) throws IOException {
 | 
			
		||||
    return new PluginEntry(jarEntry.getName(), jarEntry.getTime(),
 | 
			
		||||
        jarEntry.getSize(), attributesOf(jarEntry));
 | 
			
		||||
        Optional.of(jarEntry.getSize()), attributesOf(jarEntry));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private Map<Object, String> attributesOf(JarEntry jarEntry)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,10 @@
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
package com.google.gerrit.server.plugins;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Optional;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -26,15 +29,23 @@ import java.util.Map;
 | 
			
		||||
public class PluginEntry {
 | 
			
		||||
  public static final String ATTR_CHARACTER_ENCODING = "Character-Encoding";
 | 
			
		||||
  public static final String ATTR_CONTENT_TYPE = "Content-Type";
 | 
			
		||||
  public static final Comparator<PluginEntry> COMPARATOR_BY_NAME =
 | 
			
		||||
      new Comparator<PluginEntry>() {
 | 
			
		||||
        @Override
 | 
			
		||||
        public int compare(PluginEntry a, PluginEntry b) {
 | 
			
		||||
          return a.getName().compareTo(b.getName());
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
  private static final Map<Object,String> EMPTY_ATTRS = Collections.emptyMap();
 | 
			
		||||
  private static final Map<Object, String> EMPTY_ATTRS = Collections.emptyMap();
 | 
			
		||||
  private static final Optional<Long> NO_SIZE = Optional.absent();
 | 
			
		||||
 | 
			
		||||
  private final String name;
 | 
			
		||||
  private final long time;
 | 
			
		||||
  private final long size;
 | 
			
		||||
  private final Optional<Long> size;
 | 
			
		||||
  private final Map<Object, String> attrs;
 | 
			
		||||
 | 
			
		||||
  public PluginEntry(String name, long time, long size,
 | 
			
		||||
  public PluginEntry(String name, long time, Optional<Long> size,
 | 
			
		||||
      Map<Object, String> attrs) {
 | 
			
		||||
    this.name = name;
 | 
			
		||||
    this.time = time;
 | 
			
		||||
@@ -42,10 +53,14 @@ public class PluginEntry {
 | 
			
		||||
    this.attrs = attrs;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public PluginEntry(String name, long time, long size) {
 | 
			
		||||
  public PluginEntry(String name, long time, Optional<Long> size) {
 | 
			
		||||
    this(name, time, size, EMPTY_ATTRS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public PluginEntry(String name, long time) {
 | 
			
		||||
    this(name, time, NO_SIZE, EMPTY_ATTRS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getName() {
 | 
			
		||||
    return name;
 | 
			
		||||
  }
 | 
			
		||||
@@ -54,7 +69,7 @@ public class PluginEntry {
 | 
			
		||||
    return time;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public long getSize() {
 | 
			
		||||
  public Optional<Long> getSize() {
 | 
			
		||||
    return size;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user