View Javadoc

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   * Reads plugin information from a plugin descriptor.
32   *
33   * @see com.atlassian.plugin.parsers.PluginDescriptorReader#getPluginInformationReader()
34   * @since 3.0.0
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.map(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); // name might be null
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, Element>
322     {
323         private final String name;
324 
325         public ChildElementFunction(String name)
326         {
327             this.name = name;
328         }
329 
330         @Override
331         public Element apply(Element el)
332         {
333             return 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 }