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.info("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.info("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.info("No resources required to write");
116 return;
117 }
118
119 for (Object webResourceName : webResourceNames)
120 {
121 String resourceName = (String) webResourceName;
122 requireResource(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 List<PluginResource> resources = pluginResourceLocator.getPluginResources(moduleCompleteKey);
136 if (resources == null)
137 {
138 writeContentAndSwallowErrors("<!-- Error loading resource \"" + moduleCompleteKey + "\". Resource not found -->\n", writer);
139 return;
140 }
141
142 for (PluginResource resource : resources)
143 {
144 WebResourceFormatter formatter = getWebResourceFormatter(resource.getResourceName());
145 if (formatter == null)
146 {
147 writeContentAndSwallowErrors("<!-- Error loading resource \"" + moduleCompleteKey + "\". Resource formatter not found -->\n", writer);
148 continue;
149 }
150
151 String url = resource.getUrl();
152 if (resource.isCacheSupported())
153 {
154 Plugin plugin = webResourceIntegration.getPluginAccessor().getEnabledPluginModule(resource.getModuleCompleteKey()).getPlugin();
155 url = getStaticResourcePrefix(plugin.getPluginInformation().getVersion()) + url;
156 }
157 writeContentAndSwallowErrors(formatter.formatResource(url, resource.getParams()), writer);
158 }
159 }
160
161 public String getResourceTags(String moduleCompleteKey)
162 {
163 StringWriter writer = new StringWriter();
164 requireResource(moduleCompleteKey, writer);
165 return writer.toString();
166 }
167
168 private void writeContentAndSwallowErrors(String content, Writer writer)
169 {
170 try
171 {
172 writer.write(content);
173 }
174 catch (IOException e)
175 {
176 log.error(e);
177 }
178 }
179
180 private WebResourceFormatter getWebResourceFormatter(String resourceName)
181 {
182 for (WebResourceFormatter webResourceFormatter : webResourceFormatters)
183 {
184 if (webResourceFormatter.matches(resourceName))
185 return webResourceFormatter;
186 }
187 return null;
188 }
189
190 public String getStaticResourcePrefix()
191 {
192
193 return webResourceIntegration.getBaseUrl() + "/" +
194 STATIC_RESOURCE_PREFIX + "/" +
195 webResourceIntegration.getSystemBuildNumber() + "/" +
196 webResourceIntegration.getSystemCounter() + "/" +
197 STATIC_RESOURCE_SUFFIX;
198 }
199
200 public String getStaticResourcePrefix(String resourceCounter)
201 {
202
203 return webResourceIntegration.getBaseUrl() + "/" +
204 STATIC_RESOURCE_PREFIX + "/" +
205 webResourceIntegration.getSystemBuildNumber() + "/" +
206 webResourceIntegration.getSystemCounter() + "/" +
207 resourceCounter + "/" +
208 STATIC_RESOURCE_SUFFIX;
209 }
210
211 public String getStaticPluginResource(String moduleCompleteKey, String resourceName)
212 {
213 ModuleDescriptor moduleDescriptor = webResourceIntegration.getPluginAccessor().getEnabledPluginModule(moduleCompleteKey);
214 if(moduleDescriptor == null)
215 return null;
216
217 return getStaticPluginResource(moduleDescriptor, resourceName);
218 }
219
220
221
222
223 public String getStaticPluginResource(ModuleDescriptor moduleDescriptor, String resourceName)
224 {
225
226 String staticUrlPrefix = getStaticResourcePrefix(String.valueOf(moduleDescriptor.getPlugin().getPluginsVersion()));
227
228 return staticUrlPrefix + pluginResourceLocator.getResourceUrl(moduleDescriptor.getCompleteKey(), resourceName);
229 }
230
231
232
233
234
235
236 public String getStaticPluginResourcePrefix(ModuleDescriptor moduleDescriptor, String resourceName)
237 {
238 return getStaticPluginResource(moduleDescriptor, resourceName);
239 }
240
241
242
243
244 private static final String REQUEST_CACHE_MODE_KEY = "plugin.webresource.mode";
245
246
247
248
249 private static final IncludeMode DEFAULT_INCLUDE_MODE = WebResourceManager.DELAYED_INCLUDE_MODE;
250
251
252
253
254 public void setIncludeMode(IncludeMode includeMode)
255 {
256 webResourceIntegration.getRequestCache().put(REQUEST_CACHE_MODE_KEY, includeMode);
257 }
258
259 IncludeMode getIncludeMode()
260 {
261 IncludeMode includeMode = (IncludeMode) webResourceIntegration.getRequestCache().get(REQUEST_CACHE_MODE_KEY);
262 if (includeMode == null)
263 {
264 includeMode = DEFAULT_INCLUDE_MODE;
265 }
266 return includeMode;
267 }
268 }