View Javadoc

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   * A simple validator that given a descriptor and a schema will check that the permissions set in the plugin are valid
29   * and all required have been asked.
30   *
31   * @since 3.0.0
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 }