1 package com.atlassian.plugin.webresource;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.Plugin;
5 import org.apache.commons.collections.set.ListOrderedSet;
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8
9 import java.io.IOException;
10 import java.io.StringWriter;
11 import java.io.Writer;
12 import java.util.*;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 static final String REQUEST_CACHE_RESOURCE_KEY = "plugin.webresource.names";
36
37 protected final WebResourceIntegration webResourceIntegration;
38 protected final PluginResourceLocator pluginResourceLocator;
39 protected static final List<WebResourceFormatter> webResourceFormatters = Arrays.< WebResourceFormatter>asList(
40 new CssWebResourceFormatter(),
41 new JavascriptWebResourceFormatter()
42 );
43
44 public WebResourceManagerImpl(PluginResourceLocator pluginResourceLocator, WebResourceIntegration webResourceIntegration)
45 {
46 this.pluginResourceLocator = pluginResourceLocator;
47 this.webResourceIntegration = webResourceIntegration;
48 }
49
50 public void requireResource(String moduleCompleteKey)
51 {
52 log.debug("Requiring resource: " + moduleCompleteKey);
53 Map cache = webResourceIntegration.getRequestCache();
54 Collection webResourceNames = (Collection) cache.get(REQUEST_CACHE_RESOURCE_KEY);
55 if (webResourceNames == null)
56 {
57 webResourceNames = new ListOrderedSet();
58 }
59
60 ListOrderedSet resources = new ListOrderedSet();
61 addResourceWithDependencies(moduleCompleteKey, resources, new Stack<String>());
62 webResourceNames.addAll(resources);
63 cache.put(REQUEST_CACHE_RESOURCE_KEY, webResourceNames);
64 }
65
66
67
68
69
70
71
72
73
74
75 private void addResourceWithDependencies(String moduleKey, ListOrderedSet orderedResourceKeys, Stack<String> stack)
76 {
77 if (stack.contains(moduleKey))
78 {
79 log.warn("Cyclic plugin resource dependency has been detected with: " + moduleKey + "\n" +
80 "Stack trace: " + stack);
81 return;
82 }
83
84 ModuleDescriptor moduleDescriptor = webResourceIntegration.getPluginAccessor().getEnabledPluginModule(moduleKey);
85 if (!(moduleDescriptor instanceof WebResourceModuleDescriptor))
86 {
87 log.warn("Cannot find web resource module for: " + moduleKey);
88 return;
89 }
90
91 List<String> dependencies = ((WebResourceModuleDescriptor) moduleDescriptor).getDependencies();
92 log.debug("About to add resource [" + moduleKey + "] and its dependencies: " + dependencies);
93
94 stack.push(moduleKey);
95 try
96 {
97 for (String dependency : dependencies)
98 {
99 if (!orderedResourceKeys.contains(dependency))
100 addResourceWithDependencies(dependency, orderedResourceKeys, stack);
101 }
102 }
103 finally
104 {
105 stack.pop();
106 }
107 orderedResourceKeys.add(moduleKey);
108 }
109
110 public void includeResources(Writer writer)
111 {
112 Collection webResourceNames = (Collection) webResourceIntegration.getRequestCache().get(REQUEST_CACHE_RESOURCE_KEY);
113 if (webResourceNames == null || webResourceNames.isEmpty())
114 {
115 log.debug("No resources required to write");
116 return;
117 }
118
119 for (Object webResourceName : webResourceNames)
120 {
121 String resourceName = (String) webResourceName;
122 writeResourceTag(resourceName, writer);
123 }
124 }
125
126 public String getRequiredResources()
127 {
128 StringWriter writer = new StringWriter();
129 includeResources(writer);
130 return writer.toString();
131 }
132
133 public void requireResource(String moduleCompleteKey, Writer writer)
134 {
135 ListOrderedSet resourcesWithDeps = new ListOrderedSet();
136 addResourceWithDependencies(moduleCompleteKey, resourcesWithDeps, new Stack<String>());
137
138 for (Object resource : resourcesWithDeps)
139 {
140 writeResourceTag((String) resource, writer);
141 }
142 }
143
144 private void writeResourceTag(String moduleCompleteKey, Writer writer)
145 {
146 List<PluginResource> resources = pluginResourceLocator.getPluginResources(moduleCompleteKey);
147
148 if (resources == null)
149 {
150 writeContentAndSwallowErrors("<!-- Error loading resource \"" + moduleCompleteKey + "\". Resource not found -->\n", writer);
151 return;
152 }
153
154 for (PluginResource resource : resources)
155 {
156 WebResourceFormatter formatter = getWebResourceFormatter(resource.getResourceName());
157 if (formatter == null)
158 {
159 writeContentAndSwallowErrors("<!-- Error loading resource \"" + moduleCompleteKey + "\". Resource formatter not found -->\n", writer);
160 continue;
161 }
162
163 String url = resource.getUrl();
164 if (resource.isCacheSupported())
165 {
166 Plugin plugin = webResourceIntegration.getPluginAccessor().getEnabledPluginModule(resource.getModuleCompleteKey()).getPlugin();
167 url = getStaticResourcePrefix(plugin.getPluginInformation().getVersion()) + url;
168 }
169 else
170 {
171 url = webResourceIntegration.getBaseUrl() + url;
172 }
173 writeContentAndSwallowErrors(formatter.formatResource(url, resource.getParams()), writer);
174 }
175 }
176
177 public String getResourceTags(String moduleCompleteKey)
178 {
179 StringWriter writer = new StringWriter();
180 requireResource(moduleCompleteKey, writer);
181 return writer.toString();
182 }
183
184 private void writeContentAndSwallowErrors(String content, Writer writer)
185 {
186 try
187 {
188 writer.write(content);
189 }
190 catch (IOException e)
191 {
192 log.error(e);
193 }
194 }
195
196 private WebResourceFormatter getWebResourceFormatter(String resourceName)
197 {
198 for (WebResourceFormatter webResourceFormatter : webResourceFormatters)
199 {
200 if (webResourceFormatter.matches(resourceName))
201 return webResourceFormatter;
202 }
203 return null;
204 }
205
206 public String getStaticResourcePrefix()
207 {
208
209 return webResourceIntegration.getBaseUrl() + "/" +
210 STATIC_RESOURCE_PREFIX + "/" +
211 webResourceIntegration.getSystemBuildNumber() + "/" +
212 webResourceIntegration.getSystemCounter() + "/" +
213 STATIC_RESOURCE_SUFFIX;
214 }
215
216 public String getStaticResourcePrefix(String resourceCounter)
217 {
218
219 return webResourceIntegration.getBaseUrl() + "/" +
220 STATIC_RESOURCE_PREFIX + "/" +
221 webResourceIntegration.getSystemBuildNumber() + "/" +
222 webResourceIntegration.getSystemCounter() + "/" +
223 resourceCounter + "/" +
224 STATIC_RESOURCE_SUFFIX;
225 }
226
227 public String getStaticPluginResource(String moduleCompleteKey, String resourceName)
228 {
229 ModuleDescriptor moduleDescriptor = webResourceIntegration.getPluginAccessor().getEnabledPluginModule(moduleCompleteKey);
230 if(moduleDescriptor == null)
231 return null;
232
233 return getStaticPluginResource(moduleDescriptor, resourceName);
234 }
235
236
237
238
239 public String getStaticPluginResource(ModuleDescriptor moduleDescriptor, String resourceName)
240 {
241
242 String staticUrlPrefix = getStaticResourcePrefix(String.valueOf(moduleDescriptor.getPlugin().getPluginsVersion()));
243
244 return staticUrlPrefix + pluginResourceLocator.getResourceUrl(moduleDescriptor.getCompleteKey(), resourceName);
245 }
246
247
248
249
250
251
252 public String getStaticPluginResourcePrefix(ModuleDescriptor moduleDescriptor, String resourceName)
253 {
254 return getStaticPluginResource(moduleDescriptor, resourceName);
255 }
256
257
258
259
260 private static final String REQUEST_CACHE_MODE_KEY = "plugin.webresource.mode";
261
262
263
264
265 private static final IncludeMode DEFAULT_INCLUDE_MODE = WebResourceManager.DELAYED_INCLUDE_MODE;
266
267
268
269
270 public void setIncludeMode(IncludeMode includeMode)
271 {
272 webResourceIntegration.getRequestCache().put(REQUEST_CACHE_MODE_KEY, includeMode);
273 }
274
275 IncludeMode getIncludeMode()
276 {
277 IncludeMode includeMode = (IncludeMode) webResourceIntegration.getRequestCache().get(REQUEST_CACHE_MODE_KEY);
278 if (includeMode == null)
279 {
280 includeMode = DEFAULT_INCLUDE_MODE;
281 }
282 return includeMode;
283 }
284 }