View Javadoc

1   package com.atlassian.plugin.servlet;
2   
3   import com.atlassian.plugin.webresource.PluginResourceLocator;
4   
5   import javax.servlet.http.HttpServletRequest;
6   import javax.servlet.http.HttpServletResponse;
7   import java.io.IOException;
8   import java.net.URLDecoder;
9   import java.util.Map;
10  import java.util.TreeMap;
11  
12  import org.slf4j.Logger;
13  import org.slf4j.LoggerFactory;
14  
15  
16  /**
17   * A downloadable plugin resource, as described here: http://confluence.atlassian.com/display/JIRA/Downloadable+plugin+resource
18   * It supports the download of single plugin resources as well as batching.
19   * <p/>
20   *
21   * The URL that it parses for a single resource looks like this: <br>
22   * <code>{server root}/download/resources/{plugin key}:{module key}/{resource name}</code>
23  
24   * The URL that it parses for a batch looks like this: <br>
25   * <code>{server root}/download/batch/{plugin key}:{module key}/all.css?ieonly=true</code>
26   */
27  public class PluginResourceDownload implements DownloadStrategy
28  {
29      private static final Logger log = LoggerFactory.getLogger(PluginResourceDownload.class);
30      private String characterEncoding = "UTF-8"; // default to sensible encoding
31      private PluginResourceLocator pluginResourceLocator;
32      private ContentTypeResolver contentTypeResolver;
33  
34      public PluginResourceDownload()
35      {
36      }
37  
38      public PluginResourceDownload(PluginResourceLocator pluginResourceLocator, ContentTypeResolver contentTypeResolver, String characterEncoding)
39      {
40          this.characterEncoding = characterEncoding;
41          this.pluginResourceLocator = pluginResourceLocator;
42          this.contentTypeResolver = contentTypeResolver;
43      }
44  
45      public boolean matches(String urlPath)
46      {
47          return pluginResourceLocator.matches(urlPath);
48      }
49  
50      public void serveFile(HttpServletRequest request, HttpServletResponse response) throws DownloadException
51      {
52          try
53          {
54              String requestUri = URLDecoder.decode(request.getRequestURI(), characterEncoding);
55              DownloadableResource downloadableResource = pluginResourceLocator.getDownloadableResource(requestUri, getQueryParameters(request));
56  
57              if (downloadableResource == null)
58              {
59                  log.info("Could not locate resource: " + request.getRequestURI());
60                  response.sendError(HttpServletResponse.SC_NOT_FOUND);
61                  return;
62              }
63  
64              if(downloadableResource.isResourceModified(request, response))
65              {
66                  log.info("Plugin Resource has been modified since plugin was loaded. Skipping: " + requestUri);
67                  return;
68              }
69  
70              String contentType = getContentType(requestUri, downloadableResource);
71              if (contentType != null)
72              {
73                  response.setContentType(contentType);
74              }
75              downloadableResource.serveResource(request, response);
76          }
77          catch(IOException e)
78          {
79              throw new DownloadException(e);
80          }
81      }
82  
83      public void setCharacterEncoding(String characterEncoding)
84      {
85          this.characterEncoding = characterEncoding;
86      }
87  
88      public void setContentTypeResolver(ContentTypeResolver contentTypeResolver)
89      {
90          this.contentTypeResolver = contentTypeResolver;
91      }
92  
93      public void setPluginResourceLocator(PluginResourceLocator pluginResourceLocator)
94      {
95          this.pluginResourceLocator = pluginResourceLocator;
96      }
97  
98      /**
99       * Gets the content type for the resource. If the downloadable resource does not specify one, look one up
100      * using the {@link ContentTypeResolver}.
101      */
102     private String getContentType(String requestUri, DownloadableResource downloadableResource)
103     {
104         String contentType = downloadableResource.getContentType();
105         if(contentType == null)
106         {
107             return contentTypeResolver.getContentType(requestUri);
108         }
109 
110         return contentType;
111     }
112 
113     /**
114      * Returns a Map of query parameters from the request. If there are multiple values for the same
115      * query parameter, the first value is used.
116      *
117      * @see {@link javax.servlet.ServletRequest#getParameterMap()}
118      */
119     private Map<String, String> getQueryParameters(HttpServletRequest request)
120     {
121         Map<String, String> result = new TreeMap<String, String>();
122         Map<String, String[]> parameters = request.getParameterMap();
123 
124         for (Map.Entry<String, String[]> entry : parameters.entrySet())
125         {
126             if(entry.getValue() != null && entry.getValue().length > 0)
127                 result.put(entry.getKey(), entry.getValue()[0]);
128         }
129 
130         return result;
131     }
132 }
133