1 package com.atlassian.plugin.parsers;
2
3
4 import com.atlassian.fugue.Option;
5 import com.atlassian.fugue.Suppliers;
6 import com.atlassian.plugin.Application;
7 import com.atlassian.plugin.InstallationMode;
8 import com.atlassian.plugin.Plugin;
9 import com.google.common.base.Function;
10 import com.google.common.base.Predicate;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.collect.Iterables;
15 import com.google.common.collect.Maps;
16 import org.apache.commons.lang.StringUtils;
17 import org.dom4j.Attribute;
18 import org.dom4j.Element;
19
20 import javax.annotation.Nullable;
21 import java.util.Map;
22 import java.util.Set;
23
24 import static com.atlassian.fugue.Option.option;
25 import static com.atlassian.plugin.parsers.PluginDescriptorReader.elements;
26 import static com.google.common.base.Preconditions.checkNotNull;
27 import static com.google.common.collect.ImmutableSet.copyOf;
28 import static com.google.common.collect.Iterables.filter;
29
30
31
32
33
34
35
36 public final class PluginInformationReader
37 {
38 static final String PLUGIN_INFO = "plugin-info";
39
40 private final Option<Element> pluginInfo;
41 private final Set<Application> applications;
42 private final int pluginsVersion;
43
44 PluginInformationReader(Option<Element> pluginInfo, Set<Application> applications, int pluginsVersion)
45 {
46 this.pluginsVersion = pluginsVersion;
47 this.pluginInfo = checkNotNull(pluginInfo);
48 this.applications = copyOf(checkNotNull(applications));
49 }
50
51 public Option<String> getDescription()
52 {
53 return getDescriptionElement().map(new Function<Element, String>()
54 {
55 @Override
56 public String apply(Element description)
57 {
58 return description.getTextTrim();
59 }
60 });
61 }
62
63 public Option<String> getDescriptionKey()
64 {
65 return getDescriptionElement().flatMap(new Function<Element, Option<String>>()
66 {
67 @Override
68 public Option<String> apply(Element description)
69 {
70 return option(description.attributeValue("key"));
71 }
72 });
73 }
74
75 public Option<String> getVersion()
76 {
77 return childElement("version").map(new Function<Element, String>()
78 {
79 @Override
80 public String apply(Element version)
81 {
82 return version.getTextTrim();
83 }
84 });
85 }
86
87 private Option<Element> childElement(final String name)
88 {
89 return pluginInfo.flatMap(new ChildElementFunction(name));
90 }
91
92 private Option<Iterable<Element>> childElements(final String name)
93 {
94 return pluginInfo.map(new ChildElementsFunction(name));
95 }
96
97 public Option<String> getVendorName()
98 {
99 return getVendorElement().flatMap(new Function<Element, Option<String>>()
100 {
101 @Override
102 public Option<String> apply(Element vendor)
103 {
104 return option(vendor.attributeValue("name"));
105 }
106 });
107 }
108
109 public Option<String> getVendorUrl()
110 {
111 return getVendorElement().flatMap(new Function<Element, Option<String>>()
112 {
113 @Override
114 public Option<String> apply(Element vendor)
115 {
116 return option(vendor.attributeValue("url"));
117 }
118 });
119 }
120
121 public Map<String, String> getParameters()
122 {
123 final ImmutableMap.Builder<String, String> params = ImmutableMap.builder();
124 for (Element param : getParamElements())
125 {
126 params.put(param.attribute("name").getData().toString(), param.getText());
127 }
128 return params.build();
129 }
130
131 public Option<Float> getMinVersion()
132 {
133 return getApplicationVersionElement().flatMap(new GetAttributeFunction("min")).map(new ParseAttributeValueAsFloatFunction());
134 }
135
136 public Option<Float> getMaxVersion()
137 {
138 return getApplicationVersionElement().flatMap(new GetAttributeFunction("max")).map(new ParseAttributeValueAsFloatFunction());
139 }
140
141 public Option<Float> getMinJavaVersion()
142 {
143 return childElement("java-version").flatMap(new GetAttributeFunction("min")).map(new ParseAttributeValueAsFloatFunction());
144 }
145
146 public Map<String, Option<String>> getPermissions()
147 {
148 final ImmutableMap.Builder<String, Option<String>> permissions = ImmutableMap.builder();
149 for (Element permission : getPermissionElements())
150 {
151 permissions.put(permission.getTextTrim(), option(permission.attributeValue("installation-mode")));
152 }
153 return permissions.build();
154 }
155
156 public boolean hasAllPermissions()
157 {
158 return getPermissions().isEmpty() && pluginsVersion < Plugin.VERSION_3;
159 }
160
161 public Set<String> getPermissions(final InstallationMode installationMode)
162 {
163 return copyOf(Maps.filterValues(getPermissions(), new Predicate<Option<String>>()
164 {
165 @Override
166 public boolean apply(Option<String> input)
167 {
168 return input
169 .flatMap(new Function<String, Option<InstallationMode>>()
170 {
171 @Override
172 public Option<InstallationMode> apply(String mode)
173 {
174 return InstallationMode.of(mode);
175 }
176 })
177 .fold(Suppliers.alwaysTrue(), new Function<InstallationMode, Boolean>()
178 {
179 @Override
180 public Boolean apply(InstallationMode input)
181 {
182 return input.equals(installationMode);
183 }
184 });
185 }
186 }).keySet());
187 }
188
189 private Iterable<Element> getPermissionElements()
190 {
191 return childElement("permissions")
192 .map(new Function<Element, Iterable<Element>>()
193 {
194 @Override
195 public Iterable<Element> apply(Element permissions)
196 {
197 return elements(permissions, "permission");
198 }
199 })
200 .map(new Function<Iterable<Element>, Iterable<Element>>()
201 {
202 @Override
203 public Iterable<Element> apply(@Nullable Iterable<Element> input)
204 {
205 return filter(input, new ElementWithForApplicationsPredicate(applications));
206 }
207 })
208 .map(new Function<Iterable<Element>, Iterable<Element>>()
209 {
210 @Override
211 public Iterable<Element> apply(@Nullable Iterable<Element> input)
212 {
213 return filter(input, new Predicate<Element>()
214 {
215 @Override
216 public boolean apply(Element p)
217 {
218 return StringUtils.isNotBlank(p.getTextTrim());
219 }
220 });
221 }
222 })
223 .getOrElse(ImmutableList.<Element>of());
224 }
225
226 private Option<Element> getApplicationVersionElement()
227 {
228 return childElement("application-version");
229 }
230
231 private Iterable<Element> getParamElements()
232 {
233 return childElements("param")
234 .map(new Function<Iterable<Element>, Iterable<Element>>()
235 {
236 @Override
237 public Iterable<Element> apply(Iterable<Element> input)
238 {
239 return filter(input, new Predicate<Element>()
240 {
241 @Override
242 public boolean apply(Element param)
243 {
244 return param.attribute("name") != null;
245 }
246 });
247 }
248 })
249 .getOrElse(ImmutableList.<Element>of());
250 }
251
252 private Option<Element> getVendorElement()
253 {
254 return childElement("vendor");
255 }
256
257 private Option<Element> getDescriptionElement()
258 {
259 return childElement("description");
260 }
261
262 private static final class ParseAttributeValueAsFloatFunction implements Function<Attribute, Float>
263 {
264 @Override
265 public Float apply(Attribute attr)
266 {
267 return Float.parseFloat(attr.getValue());
268 }
269 }
270
271 private static final class GetAttributeFunction implements Function<Element, Option<Attribute>>
272 {
273 private final String name;
274
275 private GetAttributeFunction(String name)
276 {
277 this.name = name;
278 }
279
280 @Override
281 public Option<Attribute> apply(Element applicationVersion)
282 {
283 return option(applicationVersion.attribute(name));
284 }
285 }
286
287 private static final class ApplicationWithNamePredicate implements Predicate<Application>
288 {
289 @Nullable
290 private final String name;
291
292 public ApplicationWithNamePredicate(String name)
293 {
294 this.name = name;
295 }
296
297 @Override
298 public boolean apply(Application app)
299 {
300 return app.getKey().equals(name);
301 }
302 }
303
304 private static final class ElementWithForApplicationsPredicate implements Predicate<Element>
305 {
306 private final Set<Application> applications;
307
308 private ElementWithForApplicationsPredicate(Set<Application> applications)
309 {
310 this.applications = checkNotNull(applications);
311 }
312
313 @Override
314 public boolean apply(final Element el)
315 {
316 final String appName = el.attributeValue("application");
317 return appName == null || Iterables.any(applications, new ApplicationWithNamePredicate(appName));
318 }
319 }
320
321 private static final class ChildElementFunction implements Function<Element, Option<Element>>
322 {
323 private final String name;
324
325 public ChildElementFunction(String name)
326 {
327 this.name = name;
328 }
329
330 @Override
331 public Option<Element> apply(Element el)
332 {
333 return option(el.element(name));
334 }
335 }
336
337 private static final class ChildElementsFunction implements Function<Element, Iterable<Element>>
338 {
339 private final String name;
340
341 public ChildElementsFunction(String name)
342 {
343 this.name = name;
344 }
345
346 @Override
347 public Iterable<Element> apply(Element el)
348 {
349 return elements(el, name);
350 }
351 }
352 }