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