View Javadoc

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