View Javadoc

1   package com.atlassian.plugin.util;
2   
3   import com.atlassian.fugue.Option;
4   import com.atlassian.plugin.Application;
5   import com.atlassian.plugin.InstallationMode;
6   import com.google.common.base.Function;
7   import com.google.common.base.Objects;
8   import com.google.common.base.Predicate;
9   import com.google.common.collect.ImmutableList;
10  import com.google.common.collect.Iterables;
11  import org.apache.commons.lang.StringUtils;
12  import org.dom4j.Element;
13  
14  import java.util.List;
15  import java.util.Set;
16  
17  import static com.atlassian.fugue.Suppliers.alwaysTrue;
18  import static com.google.common.base.Preconditions.checkNotNull;
19  import static com.google.common.base.Preconditions.checkState;
20  import static com.google.common.collect.Iterables.filter;
21  import static com.google.common.collect.Iterables.transform;
22  import static com.google.common.collect.Lists.newArrayList;
23  
24  /**
25   * Represents a list of {@link ModuleRestrict}. This represents the restricts
26   * as used in the plugin descriptor:
27   * <code><br>
28   * &nbsp;&nbsp;&lt;module key="module-key"><br>
29   * &nbsp;&nbsp;&nbsp;&nbsp;&lt;restrict ...>...&lt;/restrict><br>
30   * &nbsp;&nbsp;&nbsp;&nbsp;&lt;restrict ...>...&lt;/restrict><br>
31   * &nbsp;&nbsp;&lt;/module>
32   * </code>
33   *
34   * @since 3.0
35   */
36  final class ModuleRestricts
37  {
38      final Iterable<ModuleRestrict> restricts;
39  
40      private ModuleRestricts()
41      {
42          this(ImmutableList.<ModuleRestrict>of());
43      }
44  
45      private ModuleRestricts(Iterable<ModuleRestrict> restricts)
46      {
47          this.restricts = ImmutableList.copyOf(restricts);
48      }
49  
50      static ModuleRestricts parse(Element moduleElement)
51      {
52          final String applicationKeys = moduleElement.attributeValue("application");
53          if (applicationKeys != null)
54          {
55              return parseApplicationsFromAttribute(applicationKeys);
56          }
57          else if (!moduleElement.elements("restrict").isEmpty())
58          {
59              @SuppressWarnings("unchecked")
60              final List<Element> restrict = moduleElement.elements("restrict");
61              return parseApplicationsFromRestrictElements(restrict);
62          }
63          else
64          {
65              return new ModuleRestricts();
66          }
67      }
68  
69      private static ModuleRestricts parseApplicationsFromRestrictElements(List<Element> restrictElements)
70      {
71          return new ModuleRestricts(Iterables.transform(restrictElements, new Function<Element, ModuleRestrict>()
72          {
73              @Override
74              public ModuleRestrict apply(Element restrictElement)
75              {
76                  final String application = restrictElement.attributeValue("application");
77                  checkState(application != null, "No application defined for 'restrict' element.");
78                  return new ModuleRestrict(application, parseInstallationMode(restrictElement), parseVersionRange(restrictElement));
79              }
80          }));
81      }
82  
83      private static Option<InstallationMode> parseInstallationMode(Element restrictElement)
84      {
85          return InstallationMode.of(restrictElement.attributeValue("mode"));
86      }
87  
88      private static VersionRange parseVersionRange(Element restrictElement)
89      {
90          final String version = restrictElement.attributeValue("version");
91          if (version != null)
92          {
93              return VersionRange.parse(version);
94          }
95          else
96          {
97              final List<Element> versionElements = restrictElement.elements("version");
98              if (!versionElements.isEmpty())
99              {
100                 VersionRange range = VersionRange.empty();
101                 for (Element versionElement : versionElements)
102                 {
103                     range = range.or(VersionRange.parse(versionElement.getText()));
104                 }
105                 return range;
106             }
107             else
108             {
109                 return VersionRange.all();
110             }
111         }
112     }
113 
114     private static ModuleRestricts parseApplicationsFromAttribute(String applicationKeys)
115     {
116         final String[] keys = applicationKeys.split("\\s*,[,\\s]*");
117         final Iterable<ModuleRestrict> restricts = transform(filter(newArrayList(keys), new IsNotBlankPredicate()), new Function<String, ModuleRestrict>()
118         {
119             @Override
120             public ModuleRestrict apply(String app)
121             {
122                 return new ModuleRestrict(app);
123             }
124         });
125 
126         return new ModuleRestricts(restricts);
127     }
128 
129     public boolean isValidFor(Set<Application> applications, InstallationMode mode)
130     {
131         if (Iterables.isEmpty(restricts))
132         {
133             return true;
134         }
135 
136         for (Application application : applications)
137         {
138             if (Iterables.any(restricts, new RestrictMatchesApplication(application, mode)))
139             {
140                 return true;
141             }
142         }
143         return false;
144     }
145 
146     @Override
147     public String toString()
148     {
149         return restricts.toString();
150     }
151 
152     static final class ModuleRestrict
153     {
154         final String application;
155         final Option<InstallationMode> mode;
156         final VersionRange version;
157 
158         ModuleRestrict(String application)
159         {
160             this(application, Option.<InstallationMode>none());
161         }
162 
163         ModuleRestrict(String application, Option<InstallationMode> mode)
164         {
165             this(application, mode, VersionRange.all());
166         }
167 
168         ModuleRestrict(String application, Option<InstallationMode> mode, VersionRange version)
169         {
170             this.application = checkNotNull(application);
171             this.mode = checkNotNull(mode);
172             this.version = checkNotNull(version);
173         }
174 
175         @Override
176         public String toString()
177         {
178             return Objects.toStringHelper("restrict")
179                     .add("application", application)
180                     .add("mode", mode)
181                     .add("range", version)
182                     .toString();
183         }
184     }
185 
186     private static final class IsNotBlankPredicate implements Predicate<String>
187     {
188         @Override
189         public boolean apply(String input)
190         {
191             return StringUtils.isNotBlank(input);
192         }
193     }
194 
195     private static final class RestrictMatchesApplication implements Predicate<ModuleRestrict>
196     {
197         private final Application app;
198         private final InstallationMode installationMode;
199 
200         public RestrictMatchesApplication(Application app, InstallationMode installationMode)
201         {
202             this.app = checkNotNull(app);
203             this.installationMode = checkNotNull(installationMode);
204         }
205 
206         @Override
207         public boolean apply(ModuleRestrict restrict)
208         {
209             return restrict.application.equals(app.getKey())
210                     && isInstallModeValid(restrict.mode)
211                     && restrict.version.isInRange(app.getVersion());
212         }
213 
214         private boolean isInstallModeValid(Option<InstallationMode> mode)
215         {
216             return mode.fold(alwaysTrue(), new Function<InstallationMode, Boolean>()
217             {
218                 @Override
219                 public Boolean apply(InstallationMode m)
220                 {
221                     return m.equals(installationMode);
222                 }
223             });
224         }
225     }
226 }