1 package com.atlassian.plugin.validation;
2
3
4 import com.atlassian.fugue.Either;
5 import com.atlassian.plugin.Application;
6 import com.atlassian.plugin.InstallationMode;
7 import com.atlassian.plugin.parsers.ModuleReader;
8 import com.atlassian.plugin.parsers.PluginDescriptorReader;
9 import com.google.common.annotations.VisibleForTesting;
10 import com.google.common.base.Function;
11 import com.google.common.base.Predicate;
12 import com.google.common.collect.Iterables;
13 import com.google.common.collect.Sets;
14 import com.google.common.io.InputSupplier;
15
16 import java.io.Reader;
17 import java.util.Map;
18 import java.util.Set;
19
20 import static com.atlassian.plugin.validation.Dom4jUtils.readDocument;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.collect.ImmutableSet.copyOf;
23 import static com.google.common.collect.Iterables.concat;
24 import static com.google.common.collect.Iterables.filter;
25 import static com.google.common.collect.Iterables.transform;
26
27
28
29
30
31
32
33 public final class DescriptorValidator
34 {
35 private static final String REMOTE_PLUGIN_CONTAINER_MODULE_NAME = "remote-plugin-container";
36
37 private final PluginDescriptorReader descriptorReader;
38 private final SchemaReader schemaReader;
39
40 public DescriptorValidator(InputSupplier<? extends Reader> descriptor, InputSupplier<? extends Reader> schema, Set<Application> applications)
41 {
42 descriptorReader = new PluginDescriptorReader(readDocument(descriptor), copyOf(checkNotNull(applications)));
43 schemaReader = new SchemaReader(readDocument(schema));
44 }
45
46 public Either<ValidationError, ValidationSuccess> validate(InstallationMode installationMode)
47 {
48 final Set<String> allowedPermissions = schemaReader.getAllowedPermissions();
49 final Set<String> askedPermissions = descriptorReader.getPluginInformationReader().getPermissions(installationMode);
50
51 final Sets.SetView<String> invalidPermissions = Sets.difference(askedPermissions, allowedPermissions);
52
53 final Set<String> requiredPermissions = getRequiredPermissions(installationMode);
54 final Sets.SetView<String> notAskedPermissions = Sets.difference(requiredPermissions, askedPermissions);
55
56 if (!invalidPermissions.isEmpty() || (!descriptorReader.getPluginInformationReader().hasAllPermissions() && !notAskedPermissions.isEmpty()))
57 {
58 return Either.left(new ValidationError(invalidPermissions, notAskedPermissions));
59 }
60 else
61 {
62 return Either.right(new ValidationSuccess(isRemotable(installationMode)));
63 }
64 }
65
66 private boolean isRemotable(InstallationMode installationMode)
67 {
68 final ModuleReader remotePluginContainerModuleReader = Iterables.find(descriptorReader.getModuleReaders(installationMode), new Predicate<ModuleReader>()
69 {
70 @Override
71 public boolean apply(ModuleReader moduleReader)
72 {
73 return moduleReader.getType().equals(REMOTE_PLUGIN_CONTAINER_MODULE_NAME);
74 }
75 }, null);
76
77 return remotePluginContainerModuleReader != null;
78 }
79
80 @VisibleForTesting
81 Set<String> getRequiredPermissions(InstallationMode installationMode)
82 {
83 final Set<String> moduleKeys = getModuleKeys(installationMode);
84 final Map<String, Set<String>> modulesRequiredPermissions = schemaReader.getModulesRequiredPermissions();
85
86 return copyOf(concat(transform(filter(
87 modulesRequiredPermissions.entrySet(),
88 new Predicate<Map.Entry<String, Set<String>>>()
89 {
90 @Override
91 public boolean apply(Map.Entry<String, Set<String>> entry)
92 {
93 return moduleKeys.contains(entry.getKey());
94 }
95 }),
96 GetEntryValue.<String, Set<String>>newGetEntryValue())));
97 }
98
99 private Set<String> getModuleKeys(InstallationMode installationMode)
100 {
101 return copyOf(transform(descriptorReader.getModuleReaders(installationMode), new Function<ModuleReader, String>()
102 {
103 @Override
104 public String apply(ModuleReader moduleReader)
105 {
106 return moduleReader.getType();
107 }
108 }));
109 }
110
111 public static final class ValidationError
112 {
113 private final Set<String> nonValidPermissions;
114 private final Set<String> notAskedPermissions;
115
116 private ValidationError(Sets.SetView<String> nonValidPermissions, Sets.SetView<String> notAskedPermissions)
117 {
118 this.nonValidPermissions = nonValidPermissions.immutableCopy();
119 this.notAskedPermissions = notAskedPermissions.immutableCopy();
120 }
121
122 public Set<String> getNonValidPermissions()
123 {
124 return nonValidPermissions;
125 }
126
127 public Set<String> getNotAskedPermissions()
128 {
129 return notAskedPermissions;
130 }
131 }
132
133 public static final class ValidationSuccess
134 {
135 private final boolean remotable;
136
137 private ValidationSuccess(boolean remotable)
138 {
139 this.remotable = remotable;
140 }
141
142 public boolean isRemotable()
143 {
144 return remotable;
145 }
146 }
147
148 private static final class GetEntryValue<K, V> implements Function<Map.Entry<K, V>, V>
149 {
150 private GetEntryValue()
151 {
152 }
153
154 static <K, V> GetEntryValue<K, V> newGetEntryValue()
155 {
156 return new GetEntryValue<K, V>();
157 }
158
159 @Override
160 public V apply(Map.Entry<K, V> entry)
161 {
162 return entry.getValue();
163 }
164 }
165 }