View Javadoc

1   package com.atlassian.plugin.servlet;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginAccessor;
6   import com.atlassian.plugin.PluginManager;
7   import com.atlassian.plugin.elements.ResourceLocation;
8   import org.apache.commons.logging.Log;
9   import org.apache.commons.logging.LogFactory;
10  
11  import javax.servlet.http.HttpServletRequest;
12  import javax.servlet.http.HttpServletResponse;
13  import java.io.IOException;
14  
15  /**
16   * A downloadable plugin resource, as described here: http://confluence.atlassian.com/display/JIRA/Downloadable+plugin+resource
17   * <p/>
18   * The URL that it parses looks like this: <br> <code>{server root}/download/resources/{plugin key}:{module
19   * key}/{resource name}</code>
20   */
21  public class PluginResourceDownload implements DownloadStrategy
22  {
23      private static final Log log = LogFactory.getLog(PluginResourceDownload.class);
24      private static final String DOWNLOAD_RESOURCE = "download";
25      private final ResourceUrlParser urlParser = new ResourceUrlParser(BaseFileServerServlet.RESOURCE_URL_PREFIX);
26      private PluginAccessor pluginAccessor;
27  
28      // no arg constructor for confluence
29      public PluginResourceDownload()
30      {
31      }
32  
33      public PluginResourceDownload(PluginAccessor pluginAccessor)
34      {
35          this.pluginAccessor = pluginAccessor;
36      }
37  
38      public boolean matches(String urlPath)
39      {
40          return urlParser.matches(urlPath);
41      }
42  
43      public void setPluginManager(PluginManager pluginManager)
44      {
45          this.pluginAccessor = pluginManager;
46      }
47  
48      public void serveFile(BaseFileServerServlet servlet, HttpServletRequest httpServletRequest,
49          HttpServletResponse httpServletResponse) throws IOException
50      {
51          String requestUri = servlet.urlDecode(httpServletRequest.getRequestURI());
52          PluginResource resource = urlParser.parse(requestUri);
53  
54          if (resource != null)
55          {
56              servePluginResource(servlet, httpServletRequest, httpServletResponse, resource.getModuleCompleteKey(),
57                  resource.getResourceName());
58          }
59          else
60          {
61              log.info("Invalid resource path spec: " + httpServletRequest.getRequestURI());
62              httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
63          }
64      }
65  
66      protected void servePluginResource(BaseFileServerServlet servlet, HttpServletRequest httpServletRequest,
67          HttpServletResponse httpServletResponse, String moduleCompleteKey, String resourceName)
68          throws IOException
69      {
70          DownloadableResource resource = null;
71  
72          // resource from the module
73          if (moduleCompleteKey.indexOf(":") > -1)
74          {
75              ModuleDescriptor moduleDescriptor = pluginAccessor.getPluginModule(moduleCompleteKey);
76              if (moduleDescriptor != null && pluginAccessor.isPluginModuleEnabled(moduleCompleteKey))
77              {
78                  resource = getResourceFromModule(moduleDescriptor, resourceName, servlet);
79              }
80              else
81              {
82                  log.info("Module not found: " + moduleCompleteKey);
83                  httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
84              }
85          }
86          else // resource from plugin
87          {
88              Plugin plugin = pluginAccessor.getPlugin(moduleCompleteKey);
89              resource = getResourceFromPlugin(plugin, resourceName, "", servlet);
90          }
91  
92          if (resource == null)
93          {
94              resource = getResourceFromPlugin(moduleCompleteKey, resourceName, servlet);
95          }
96  
97          if (resource != null)
98          {
99              resource.serveResource(httpServletRequest, httpServletResponse);
100         }
101         else
102         {
103             log.info("Unable to find resource for plugin: " + moduleCompleteKey + " and path: " + resourceName);
104         }
105     }
106 
107     private DownloadableResource getResourceFromPlugin(String moduleKey, String resourcePath,
108         BaseFileServerServlet servlet)
109     {
110         if (moduleKey.indexOf(':') < 0 || moduleKey.indexOf(':') == moduleKey.length() - 1)
111         {
112             return null;
113         }
114 
115         Plugin plugin = pluginAccessor.getPlugin(moduleKey.substring(0, moduleKey.indexOf(':')));
116         if (plugin == null)
117         {
118             return null;
119         }
120 
121         return getResourceFromPlugin(plugin, resourcePath, "", servlet);
122     }
123 
124     private DownloadableResource getResourceFromPlugin(Plugin plugin, String resourcePath, String filePath,
125         BaseFileServerServlet servlet)
126     {
127         ResourceLocation resourceLocation = plugin.getResourceLocation(DOWNLOAD_RESOURCE, resourcePath);
128 
129         if (resourceLocation != null)
130         {
131             return getDownloadablePluginResource(servlet, plugin, resourceLocation, filePath);
132         }
133         else
134         {
135             String[] nextParts = splitLastPathPart(resourcePath);
136             if (nextParts == null)
137             {
138                 return null;
139             }
140             else
141             {
142                 return getResourceFromPlugin(plugin, nextParts[0], nextParts[1] + filePath, servlet);
143             }
144         }
145     }
146 
147     private DownloadableResource getResourceFromModule(ModuleDescriptor moduleDescriptor, String filePath,
148         BaseFileServerServlet servlet)
149     {
150         return getResourceFromModule(moduleDescriptor, filePath, "", servlet);
151     }
152 
153     DownloadableResource getResourceFromModule(ModuleDescriptor moduleDescriptor, String resourcePath, String filePath,
154         BaseFileServerServlet servlet)
155     {
156         Plugin plugin = pluginAccessor.getPlugin(moduleDescriptor.getPluginKey());
157         ResourceLocation resourceLocation = moduleDescriptor.getResourceLocation(DOWNLOAD_RESOURCE, resourcePath);
158 
159         if (resourceLocation != null)
160         {
161             return getDownloadablePluginResource(servlet, plugin, resourceLocation, filePath);
162         }
163         else
164         {
165             String[] nextParts = splitLastPathPart(resourcePath);
166             if (nextParts == null)
167             {
168                 return null;
169             }
170             else
171             {
172                 return getResourceFromModule(moduleDescriptor, nextParts[0], nextParts[1] + filePath, servlet);
173             }
174         }
175     }
176 
177     private DownloadableResource getDownloadablePluginResource(BaseFileServerServlet servlet, Plugin plugin,
178         ResourceLocation resourceLocation, String filePath)
179     {
180         if ("webContext".equalsIgnoreCase(resourceLocation.getParameter(
181             "source")))    // this allows plugins that are loaded from the web to be served
182             return new DownloadableWebResource(servlet, plugin, resourceLocation, filePath);
183         else
184             return new DownloadableClasspathResource(servlet, plugin, resourceLocation, filePath);
185     }
186 
187     String[] splitLastPathPart(String resourcePath)
188     {
189         int indexOfSlash = resourcePath.lastIndexOf('/');
190         if (resourcePath.endsWith("/")) // skip over the trailing slash
191         {
192             indexOfSlash = resourcePath.lastIndexOf('/', indexOfSlash - 1);
193         }
194 
195         if (indexOfSlash < 0) return null;
196 
197         return new String[]{
198             resourcePath.substring(0, indexOfSlash + 1),
199             resourcePath.substring(indexOfSlash + 1)
200         };
201     }
202 }
203