View Javadoc

1   package com.atlassian.plugin.webresource;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.elements.ResourceDescriptor;
5   import com.atlassian.plugin.servlet.BaseFileServerServlet;
6   import org.apache.commons.collections.set.ListOrderedSet;
7   import org.apache.commons.logging.Log;
8   import org.apache.commons.logging.LogFactory;
9   
10  import java.io.IOException;
11  import java.io.Writer;
12  import java.util.*;
13  
14  /**
15   * A handy super-class that handles most of the resource management.
16   * <p/>
17   * To use this manager, you need to have the following UrlRewriteFilter code:
18   * <pre>
19   * &lt;rule>
20   * &lt;from>^/s/(.*)/_/(.*)&lt;/from>
21   * &lt;run class="com.atlassian.plugin.servlet.ResourceDownloadUtils" method="addCachingHeaders" />
22   * &lt;to type="forward">/$2&lt;/to>
23   * &lt;/rule>
24   * </pre>
25   * <p/>
26   * Sub-classes should implement the abstract methods
27   */
28  public class WebResourceManagerImpl implements WebResourceManager
29  {
30      private static final Log log = LogFactory.getLog(WebResourceManagerImpl.class);
31  
32      static final String STATIC_RESOURCE_PREFIX = "s";
33      static final String STATIC_RESOURCE_SUFFIX = "_";
34  
35      private static final String REQUEST_CACHE_RESOURCE_KEY = "plugin.webresource.names";
36      private static final String REQUEST_CACHE_MODE_KEY = "plugin.webresource.mode";
37  
38      private static final IncludeMode DEFAULT_INCLUDE_MODE = WebResourceManager.DELAYED_INCLUDE_MODE;
39      private static final WebResourceFormatter[] WEB_RESOURCE_FORMATTERS = new WebResourceFormatter[] {
40          new CssWebResourceFormatter(),
41          new JavascriptWebResourceFormatter(),
42      };
43  
44      private final WebResourceIntegration webResourceIntegration;
45  
46      public WebResourceManagerImpl(WebResourceIntegration webResourceIntegration)
47      {
48          this.webResourceIntegration = webResourceIntegration; //constructor for JIRA / Pico
49      }
50  
51      public void requireResource(String resourceName)
52      {
53          if (WebResourceManager.DELAYED_INCLUDE_MODE.equals(getIncludeMode()))
54          {
55              requireDelayedResource(resourceName);
56          }
57          else
58          {
59              throw new IllegalStateException("Require Writer for Inline mode.");
60          }
61      }
62  
63      public void requireResource(String resourceName, Writer writer)
64      {
65          if (WebResourceManager.DELAYED_INCLUDE_MODE.equals(getIncludeMode()))
66          {
67              requireDelayedResource(resourceName);
68          }
69          else
70          {
71              try
72              {
73                  includeResource(resourceName, writer);
74              }
75              catch (IOException e)
76              {
77                  log.error(e);
78              }
79          }
80      }
81  
82      private void requireDelayedResource(String resourceName)
83      {
84          Map cache = webResourceIntegration.getRequestCache();
85          Collection webResourceNames = (Collection) cache.get(REQUEST_CACHE_RESOURCE_KEY);
86          if (webResourceNames == null)
87          {
88              webResourceNames = new ListOrderedSet();
89          }
90  
91          webResourceNames.add(resourceName);
92          cache.put(REQUEST_CACHE_RESOURCE_KEY, webResourceNames);
93      }
94  
95      public void includeResources(Writer writer)
96      {
97          try
98          {
99              if (WebResourceManager.DELAYED_INCLUDE_MODE.equals(getIncludeMode()))
100             {
101                 includeDelayedResources(writer);
102             }
103         }
104         catch (IOException e)
105         {
106             log.error(e);
107         }
108 
109     }
110 
111     private void includeDelayedResources(Writer writer) throws IOException
112     {
113         Collection webResourceNames = (Collection) webResourceIntegration.getRequestCache().get(REQUEST_CACHE_RESOURCE_KEY);
114         if (webResourceNames == null || webResourceNames.isEmpty())
115         {
116             return;
117         }
118 
119         for (Iterator iterator = webResourceNames.iterator(); iterator.hasNext();)
120         {
121             String resourceName = (String) iterator.next();
122             includeResource(resourceName, writer);
123         }
124     }
125 
126     private void includeResource(String resourceName, Writer writer) throws IOException
127     {
128         ModuleDescriptor descriptor = webResourceIntegration.getPluginAccessor().getEnabledPluginModule(resourceName);
129         if (descriptor == null)
130         {
131             writer.write("<!-- Error loading resource \"" + resourceName + "\".  Resource not found -->\n");
132             return;
133         }
134         else if (!(descriptor instanceof WebResourceModuleDescriptor))
135         {
136             writer.write("<!-- Error loading resource \"" + descriptor + "\". Resource is not a WebResourceModule -->\n");
137             return;
138         }
139 
140         for (Iterator iterator1 = descriptor.getResourceDescriptors().iterator(); iterator1.hasNext();)
141         {
142             ResourceDescriptor resourceDescriptor = (ResourceDescriptor) iterator1.next();
143             String name = resourceDescriptor.getName();
144             final String linkToResource;
145             if ("false".equalsIgnoreCase(resourceDescriptor.getParameter("cache")))
146             {
147                 linkToResource = webResourceIntegration.getBaseUrl() + getResourceUrl(descriptor, name);
148             }
149             else
150             {
151                 linkToResource = getStaticPluginResource(descriptor, name);
152             }
153 
154             WebResourceFormatter webResourceFormatter = getWebResourceFormatter(name);
155             if(webResourceFormatter != null)
156             {
157                 writer.write(webResourceFormatter.formatResource(name, linkToResource, resourceDescriptor.getParameters()));
158             }
159             else
160             {
161                 writer.write("<!-- Error loading resource \"" + descriptor + "\". Type " + resourceDescriptor.getType() + " is not handled -->\n");
162             }
163         }
164     }
165 
166     private WebResourceFormatter getWebResourceFormatter(String name)
167     {
168         for (int i = 0; i < WEB_RESOURCE_FORMATTERS.length; i++)
169         {
170             WebResourceFormatter webResourceFormatter = WEB_RESOURCE_FORMATTERS[i];
171             if(webResourceFormatter.matches(name))
172             {
173                 return webResourceFormatter;
174             }
175         }
176         return null;
177     }
178 
179     public String getStaticResourcePrefix()
180     {
181         // "{base url}/s/{build num}/{system counter}/_"
182         return webResourceIntegration.getBaseUrl() + "/" +
183                 STATIC_RESOURCE_PREFIX + "/" +
184                 webResourceIntegration.getSystemBuildNumber() + "/" +
185                 webResourceIntegration.getSystemCounter() + "/" +
186                 STATIC_RESOURCE_SUFFIX;
187     }
188 
189     public String getStaticResourcePrefix(String resourceCounter)
190     {
191         // "{base url}/s/{build num}/{system counter}/{resource counter}/_"
192         return webResourceIntegration.getBaseUrl() + "/" +
193                 STATIC_RESOURCE_PREFIX + "/" +
194                 webResourceIntegration.getSystemBuildNumber() + "/" +
195                 webResourceIntegration.getSystemCounter() + "/" +
196                 resourceCounter + "/" +
197                 STATIC_RESOURCE_SUFFIX;
198     }
199 
200     /**
201      * @deprecated Use {@link #getStaticPluginResource(com.atlassian.plugin.ModuleDescriptor, String)} instead
202      */
203     public String getStaticPluginResourcePrefix(ModuleDescriptor moduleDescriptor, String resourceName)
204     {
205         return getStaticPluginResource(moduleDescriptor, resourceName);
206     }
207 
208     /**
209      * @return "{base url}/s/{build num}/{system counter}/{plugin version}/_/download/resources/{plugin.key:module.key}/{resource.name}"
210      */
211     public String getStaticPluginResource(ModuleDescriptor moduleDescriptor, String resourceName)
212     {
213         // "{base url}/s/{build num}/{system counter}/{plugin version}/_"
214         String prefix = getStaticResourcePrefix(moduleDescriptor.getPlugin().getPluginInformation().getVersion());
215 
216         // "/download/resources/plugin.key:module.key/resource.name"
217         String suffix = getResourceUrl(moduleDescriptor, resourceName);
218         return prefix + suffix;
219     }
220 
221     // "/download/resources/plugin.key:module.key/resource.name"
222     private String getResourceUrl(ModuleDescriptor moduleDescriptor, String resourceName)
223     {
224         return "/" + BaseFileServerServlet.SERVLET_PATH + "/" + BaseFileServerServlet.RESOURCE_URL_PREFIX + "/" + moduleDescriptor.getCompleteKey() + "/" + resourceName;
225     }
226 
227     public String getStaticPluginResource(String pluginModuleKey, String resourceName)
228     {
229         return getStaticPluginResource(webResourceIntegration.getPluginAccessor().getEnabledPluginModule(pluginModuleKey), resourceName);
230     }
231 
232     public void setIncludeMode(IncludeMode includeMode)
233     {
234         webResourceIntegration.getRequestCache().put(REQUEST_CACHE_MODE_KEY, includeMode);
235     }
236 
237     IncludeMode getIncludeMode()
238     {
239         IncludeMode includeMode = (IncludeMode) webResourceIntegration.getRequestCache().get(REQUEST_CACHE_MODE_KEY);
240         if (includeMode == null)
241         {
242             includeMode = DEFAULT_INCLUDE_MODE;
243         }
244         return includeMode;
245     }
246 
247 
248 }