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