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
26
27
28
29
30
31
32
33
34
35
36 final class ModuleRestricts {
37 final Iterable<ModuleRestrict> restricts;
38
39 private ModuleRestricts() {
40 this(ImmutableList.<ModuleRestrict>of());
41 }
42
43 private ModuleRestricts(Iterable<ModuleRestrict> restricts) {
44 this.restricts = ImmutableList.copyOf(restricts);
45 }
46
47 static ModuleRestricts parse(Element moduleElement) {
48 final String applicationKeys = moduleElement.attributeValue("application");
49 if (applicationKeys != null) {
50 return parseApplicationsFromAttribute(applicationKeys);
51 } else if (!moduleElement.elements("restrict").isEmpty()) {
52 @SuppressWarnings("unchecked")
53 final List<Element> restrict = moduleElement.elements("restrict");
54 return parseApplicationsFromRestrictElements(restrict);
55 } else {
56 return new ModuleRestricts();
57 }
58 }
59
60 private static ModuleRestricts parseApplicationsFromRestrictElements(List<Element> restrictElements) {
61 return new ModuleRestricts(Iterables.transform(restrictElements, new Function<Element, ModuleRestrict>() {
62 @Override
63 public ModuleRestrict apply(Element restrictElement) {
64 final String application = restrictElement.attributeValue("application");
65 checkState(application != null, "No application defined for 'restrict' element.");
66 return new ModuleRestrict(application, parseInstallationMode(restrictElement), parseVersionRange(restrictElement));
67 }
68 }));
69 }
70
71 private static Option<InstallationMode> parseInstallationMode(Element restrictElement) {
72 return InstallationMode.of(restrictElement.attributeValue("mode"));
73 }
74
75 private static VersionRange parseVersionRange(Element restrictElement) {
76 final String version = restrictElement.attributeValue("version");
77 if (version != null) {
78 return VersionRange.parse(version);
79 } else {
80 final List<Element> versionElements = restrictElement.elements("version");
81 if (!versionElements.isEmpty()) {
82 VersionRange range = VersionRange.empty();
83 for (Element versionElement : versionElements) {
84 range = range.or(VersionRange.parse(versionElement.getText()));
85 }
86 return range;
87 } else {
88 return VersionRange.all();
89 }
90 }
91 }
92
93 private static ModuleRestricts parseApplicationsFromAttribute(String applicationKeys) {
94 final String[] keys = applicationKeys.split("\\s*,[,\\s]*");
95 final Iterable<ModuleRestrict> restricts = transform(filter(newArrayList(keys), new IsNotBlankPredicate()), new Function<String, ModuleRestrict>() {
96 @Override
97 public ModuleRestrict apply(String app) {
98 return new ModuleRestrict(app);
99 }
100 });
101
102 return new ModuleRestricts(restricts);
103 }
104
105 public boolean isValidFor(Set<Application> applications, InstallationMode mode) {
106 if (Iterables.isEmpty(restricts)) {
107 return true;
108 }
109
110 for (Application application : applications) {
111 if (Iterables.any(restricts, new RestrictMatchesApplication(application, mode))) {
112 return true;
113 }
114 }
115 return false;
116 }
117
118 @Override
119 public String toString() {
120 return restricts.toString();
121 }
122
123 static final class ModuleRestrict {
124 final String application;
125 final Option<InstallationMode> mode;
126 final VersionRange version;
127
128 ModuleRestrict(String application) {
129 this(application, Option.<InstallationMode>none());
130 }
131
132 ModuleRestrict(String application, Option<InstallationMode> mode) {
133 this(application, mode, VersionRange.all());
134 }
135
136 ModuleRestrict(String application, Option<InstallationMode> mode, VersionRange version) {
137 this.application = checkNotNull(application);
138 this.mode = checkNotNull(mode);
139 this.version = checkNotNull(version);
140 }
141
142 @Override
143 public String toString() {
144 return Objects.toStringHelper("restrict")
145 .add("application", application)
146 .add("mode", mode)
147 .add("range", version)
148 .toString();
149 }
150 }
151
152 private static final class IsNotBlankPredicate implements Predicate<String> {
153 @Override
154 public boolean apply(String input) {
155 return StringUtils.isNotBlank(input);
156 }
157 }
158
159 private static final class RestrictMatchesApplication implements Predicate<ModuleRestrict> {
160 private final Application app;
161 private final InstallationMode installationMode;
162
163 public RestrictMatchesApplication(Application app, InstallationMode installationMode) {
164 this.app = checkNotNull(app);
165 this.installationMode = checkNotNull(installationMode);
166 }
167
168 @Override
169 public boolean apply(ModuleRestrict restrict) {
170 return restrict.application.equals(app.getKey())
171 && isInstallModeValid(restrict.mode)
172 && restrict.version.isInRange(app.getVersion());
173 }
174
175 private boolean isInstallModeValid(Option<InstallationMode> mode) {
176 return mode.fold(alwaysTrue(), new Function<InstallationMode, Boolean>() {
177 @Override
178 public Boolean apply(InstallationMode m) {
179 return m.equals(installationMode);
180 }
181 });
182 }
183 }
184 }