1 package com.atlassian.plugin.webresource;
2
3 import static com.google.common.collect.ImmutableList.copyOf;
4 import static com.google.common.collect.Iterables.contains;
5 import static com.google.common.collect.Iterables.transform;
6 import static com.google.common.collect.Sets.newHashSet;
7
8 import com.atlassian.plugin.ModuleDescriptor;
9 import com.atlassian.plugin.servlet.DownloadableResource;
10 import com.google.common.base.Function;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.collect.ImmutableSortedSet;
13 import com.google.common.collect.Iterables;
14 import com.google.common.collect.Ordering;
15 import org.apache.commons.codec.binary.Hex;
16
17 import java.io.UnsupportedEncodingException;
18 import java.security.MessageDigest;
19 import java.security.NoSuchAlgorithmException;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28
29
30
31
32
33
34
35 class ContextBatch
36 {
37 private static final String UTF8 = "UTF-8";
38 private static final String MD5 = "MD5";
39 private static final Ordering<ModuleDescriptor<?>> MODULE_KEY_ORDERING = Ordering.natural().onResultOf(new TransformDescriptorToKey());
40
41 private final String key;
42 private final List<String> contexts;
43 private final Iterable<String> excludedContexts;
44 private final Iterable<WebResourceModuleDescriptor> resources;
45 private final Iterable<String> resourceKeys;
46 private final Set<PluginResourceBatchParams> resourceParams;
47
48 ContextBatch(final String context, final Iterable<WebResourceModuleDescriptor> resources)
49 {
50 this(context, ImmutableList.of(context), resources, ImmutableList.<PluginResourceBatchParams> of());
51 }
52
53
54
55
56
57
58
59
60
61 ContextBatch(final String key, final List<String> contexts, final Iterable<WebResourceModuleDescriptor> resources, final Iterable<PluginResourceBatchParams> resourceParams)
62 {
63 this(key, contexts, null, resources, resourceParams);
64 }
65
66
67
68
69
70
71
72
73
74
75 ContextBatch(final String key, final List<String> contexts, Iterable<String> excludedContexts,
76 final Iterable<WebResourceModuleDescriptor> resources, final Iterable<PluginResourceBatchParams> resourceParams)
77 {
78 this.key = key;
79 this.contexts = copyOf(contexts);
80 if (excludedContexts == null)
81 {
82 this.excludedContexts = Collections.emptyList();
83 }
84 else
85 {
86 this.excludedContexts = copyOf(excludedContexts);
87 }
88
89 this.resourceParams = newHashSet(resourceParams);
90
91
92
93
94 this.resources = ImmutableSortedSet.copyOf(MODULE_KEY_ORDERING, resources);
95
96 this.resourceKeys = transform(resources, new TransformDescriptorToKey());
97 }
98
99 boolean isResourceIncluded(final String resourceModuleKey)
100 {
101 return contains(resourceKeys, resourceModuleKey);
102 }
103
104 void addResourceType(final PluginResource pluginResource)
105 {
106 final Map<String, String> parameters = new HashMap<String, String>(PluginResourceLocator.BATCH_PARAMS.length);
107 final String type = pluginResource.getType();
108 for (final String key : PluginResourceLocator.BATCH_PARAMS)
109 {
110 if (pluginResource.getParams().get(key) != null)
111 {
112 parameters.put(key, pluginResource.getParams().get(key));
113 }
114 }
115
116 resourceParams.add(new PluginResourceBatchParams(type, parameters));
117 }
118
119
120
121
122
123
124
125
126
127
128
129 Iterable<PluginResource> buildPluginResources()
130 {
131 final String hash = createHash();
132
133
134
135 Set<BatchedWebResourceDescriptor> descriptors = new HashSet<BatchedWebResourceDescriptor>();
136 for (WebResourceModuleDescriptor wrmd : this.getResources())
137 {
138 descriptors.add(new BatchedWebResourceDescriptor(wrmd.getPlugin().getPluginInformation().getVersion(), wrmd.getCompleteKey()));
139 }
140
141 List<PluginResource> resources = new ArrayList<PluginResource>(resourceParams.size());
142 for (PluginResourceBatchParams param :resourceParams)
143 {
144 ContextBatchPluginResource contextBatchPluginResource = new ContextBatchPluginResource(key, contexts, excludedContexts, hash, param.getType(), param.getParameters(), descriptors);
145 resources.add(contextBatchPluginResource);
146 }
147
148 return resources;
149 }
150
151 private String createHash()
152 {
153 try
154 {
155 MessageDigest md5 = MessageDigest.getInstance(MD5);
156 for (WebResourceModuleDescriptor moduleDescriptor : resources)
157 {
158 String version = moduleDescriptor.getPlugin().getPluginInformation().getVersion();
159 md5.update(moduleDescriptor.getCompleteKey().getBytes(UTF8));
160 md5.update(version.getBytes(UTF8));
161 }
162
163 return new String(Hex.encodeHex(md5.digest()));
164 }
165 catch (NoSuchAlgorithmException e)
166 {
167 throw new AssertionError("MD5 hashing algorithm is not available.");
168 }
169 catch (UnsupportedEncodingException e)
170 {
171 throw new AssertionError("UTF-8 encoding is not available.");
172 }
173 }
174
175 String getKey()
176 {
177 return key;
178 }
179
180 List<String> getContexts()
181 {
182 return contexts;
183 }
184
185 public Iterable<String> getExcludedContexts()
186 {
187 return excludedContexts;
188 }
189
190 Iterable<WebResourceModuleDescriptor> getResources()
191 {
192 return resources;
193 }
194
195 Iterable<String> getResourceKeys()
196 {
197 return transform(resources, new Function<WebResourceModuleDescriptor,String>()
198 {
199 public String apply(WebResourceModuleDescriptor input)
200 {
201 return input.getCompleteKey();
202 }
203 });
204 }
205
206 Iterable<PluginResourceBatchParams> getResourceParams()
207 {
208 return Collections.unmodifiableSet(resourceParams);
209 }
210
211 @Override
212 public boolean equals(Object obj)
213 {
214 if (obj == null)
215 return false;
216
217 if (!(obj instanceof ContextBatch))
218 return false;
219
220 if (obj == this)
221 return true;
222
223 ContextBatch other = (ContextBatch)obj;
224
225 return this.key.equals(other.key);
226 }
227
228 @Override
229 public int hashCode()
230 {
231 return 17 * key.hashCode();
232 }
233
234 @Override
235 public String toString()
236 {
237 StringBuilder builder = new StringBuilder("ContextBatch[key=");
238 builder.append(getKey());
239
240 if (contexts != null && Iterables.size(contexts) > 0)
241 {
242 builder.append(", includedContexts=").append(Iterables.toString(contexts));
243 }
244
245 if (excludedContexts != null && Iterables.size(excludedContexts) > 0)
246 {
247 builder.append(", excludedContexts=").append(Iterables.toString(excludedContexts));
248 }
249
250 if (resourceKeys != null && Iterables.size(resourceKeys) > 0)
251 {
252 builder.append(", resourceKeys=").append(Iterables.toString(resourceKeys));
253 }
254
255 builder.append("]");
256
257 return builder.toString();
258 }
259 }