1 /* Copyright 2004-2005 the original author or authors. 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 package org.codehaus.groovy.grails.resolve; 16 17 import java.util.Arrays; 18 import java.util.Collection; 19 import java.util.HashMap; 20 import java.util.HashSet; 21 import java.util.List; 22 import java.util.Map; 23 import java.util.Set; 24 import java.util.concurrent.ConcurrentHashMap; 25 26 import org.apache.ivy.core.module.descriptor.Configuration; 27 import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; 28 import org.apache.ivy.core.module.descriptor.DependencyDescriptor; 29 import org.apache.ivy.core.module.descriptor.ExcludeRule; 30 import org.apache.ivy.core.module.descriptor.ModuleDescriptor; 31 import org.apache.ivy.core.module.id.ArtifactId; 32 import org.apache.ivy.core.module.id.ModuleId; 33 import org.apache.ivy.core.module.id.ModuleRevisionId; 34 import org.apache.ivy.plugins.matcher.PatternMatcher; 35 36 /** 37 * Base class for IvyDependencyManager with some logic implemented in Java. 38 * 39 * @author Graeme Rocher 40 * @since 1.3 41 */ 42 @SuppressWarnings("serial") 43 public abstract class AbstractIvyDependencyManager { 44 45 /* 46 * Out of the box Ivy configurations are: 47 * 48 * - build: Dependencies for the build system only 49 * - compile: Dependencies for the compile step 50 * - runtime: Dependencies needed at runtime but not for compilation (see above) 51 * - test: Dependencies needed for testing but not at runtime (see above) 52 * - provided: Dependencies needed at development time, but not during WAR deployment 53 */ 54 public static Configuration BUILD_CONFIGURATION = new Configuration("build", 55 Configuration.Visibility.PUBLIC, 56 "Build system dependencies", 57 new String[]{"default"}, 58 true, null); 59 60 public static Configuration COMPILE_CONFIGURATION = new Configuration("compile", 61 Configuration.Visibility.PUBLIC, 62 "Compile time dependencies", 63 new String[]{"default" }, 64 true, null); 65 66 public static Configuration RUNTIME_CONFIGURATION = new Configuration("runtime", 67 Configuration.Visibility.PUBLIC, 68 "Runtime time dependencies", 69 new String[]{"compile"}, 70 true, null); 71 72 public static Configuration TEST_CONFIGURATION = new Configuration("test", 73 Configuration.Visibility.PUBLIC, 74 "Testing dependencies", 75 new String[]{"runtime"}, 76 true, null); 77 78 public static Configuration PROVIDED_CONFIGURATION = new Configuration("provided", 79 Configuration.Visibility.PUBLIC, 80 "Dependencies provided by the container", 81 new String[]{"default"}, 82 true, null); 83 84 public static Configuration DOCS_CONFIGURATION = new Configuration("docs", 85 Configuration.Visibility.PUBLIC, 86 "Dependencies for the documenation engine", 87 new String[]{"build"}, 88 true, null); 89 90 public static List<Configuration> ALL_CONFIGURATIONS = Arrays.asList( 91 BUILD_CONFIGURATION, 92 COMPILE_CONFIGURATION, 93 RUNTIME_CONFIGURATION, 94 TEST_CONFIGURATION, 95 PROVIDED_CONFIGURATION, 96 DOCS_CONFIGURATION); 97 98 Map<String, List<String>> configurationMappings = new HashMap<String, List<String>>() {{ 99 put("runtime", Arrays.asList("default")); 100 put("build", Arrays.asList("default")); 101 put("compile", Arrays.asList("default")); 102 put("provided", Arrays.asList("default")); 103 put("docs", Arrays.asList("default")); 104 put("test", Arrays.asList("default")); 105 }}; 106 107 protected String[] configurationNames = configurationMappings.keySet().toArray( 108 new String[configurationMappings.size()]); 109 protected Set<ModuleId> modules = new HashSet<ModuleId>(); 110 protected Set<ModuleRevisionId> dependencies = new HashSet<ModuleRevisionId>(); 111 protected Set<DependencyDescriptor> dependencyDescriptors = new HashSet<DependencyDescriptor>(); 112 protected Set<DependencyDescriptor> pluginDependencyDescriptors = new HashSet<DependencyDescriptor>(); 113 protected Set<String> pluginDependencyNames = new HashSet<String>(); 114 protected Set<String> metadataRegisteredPluginNames = new HashSet<String>(); 115 protected Map<String, Collection<ModuleRevisionId>> orgToDepMap = new HashMap<String, Collection<ModuleRevisionId>>(); 116 117 protected Map<String, DependencyDescriptor> pluginNameToDescriptorMap = 118 new ConcurrentHashMap<String, DependencyDescriptor>(); 119 protected String applicationName; 120 protected String applicationVersion; 121 122 /** 123 * Obtains a set of dependency descriptors defined in the project 124 */ getDependencyDescriptors()125 Set<DependencyDescriptor> getDependencyDescriptors() { 126 return dependencyDescriptors; 127 } 128 getMetadataRegisteredPluginNames()129 public Set<String> getMetadataRegisteredPluginNames() { 130 return metadataRegisteredPluginNames; 131 } 132 setMetadataRegisteredPluginNames(Set<String> metadataRegisteredPluginNames)133 public void setMetadataRegisteredPluginNames(Set<String> metadataRegisteredPluginNames) { 134 this.metadataRegisteredPluginNames = metadataRegisteredPluginNames; 135 } 136 137 /** 138 * Obtains a set of plugin dependency descriptors defined in the project 139 */ getPluginDependencyDescriptors()140 Set<DependencyDescriptor> getPluginDependencyDescriptors() { 141 return pluginDependencyDescriptors; 142 } 143 144 /** 145 * Obtains a particular DependencyDescriptor by the plugin name 146 * @param pluginName The plugin name 147 * @return A DependencyDescriptor or null 148 */ getPluginDependencyDescriptor(String pluginName)149 public DependencyDescriptor getPluginDependencyDescriptor(String pluginName) { 150 return pluginNameToDescriptorMap.get(pluginName); 151 } 152 153 /** 154 * Obtains a set of plugins this application is dependent onb 155 * @return A set of plugins names 156 */ getPluginDependencyNames()157 public Set<String> getPluginDependencyNames() { return pluginDependencyNames; } 158 159 /** 160 * Obtains a list of dependencies defined in the project 161 */ getDependencies()162 public Set<ModuleRevisionId> getDependencies() { return this.dependencies; } 163 getApplicationName()164 public String getApplicationName() { 165 return applicationName; 166 } 167 setApplicationName(String applicationName)168 public void setApplicationName(String applicationName) { 169 this.applicationName = applicationName; 170 } 171 getApplicationVersion()172 public String getApplicationVersion() { 173 return applicationVersion; 174 } 175 setApplicationVersion(String applicationVersion)176 public void setApplicationVersion(String applicationVersion) { 177 this.applicationVersion = applicationVersion; 178 } 179 getConfigurationNames()180 public String[] getConfigurationNames() { 181 return configurationNames; 182 } 183 getConfigurationMappings()184 public Map<String, List<String>> getConfigurationMappings() { 185 return configurationMappings; 186 } 187 188 /** 189 * Returns whether a plugin is transitive 190 * 191 * @param pluginName The name of the plugin 192 * @return True if the plugin is transitive 193 */ isPluginTransitive(String pluginName)194 public boolean isPluginTransitive(String pluginName) { 195 DependencyDescriptor dd = pluginNameToDescriptorMap.get(pluginName); 196 return dd == null || dd.isTransitive(); 197 } 198 199 /** 200 * Adds a dependency to the project 201 * 202 * @param revisionId The ModuleRevisionId instance 203 */ addDependency(ModuleRevisionId revisionId)204 public void addDependency(ModuleRevisionId revisionId) { 205 modules.add(revisionId.getModuleId()); 206 dependencies.add(revisionId); 207 final String org = revisionId.getOrganisation(); 208 if (orgToDepMap.containsKey(org)) { 209 orgToDepMap.get(org).add(revisionId); 210 } 211 else { 212 Collection<ModuleRevisionId> deps = new HashSet<ModuleRevisionId>(); 213 deps.add(revisionId); 214 orgToDepMap.put(org, deps); 215 } 216 } 217 createExcludeArtifactId(String excludeName)218 protected ArtifactId createExcludeArtifactId(String excludeName) { 219 return createExcludeArtifactId(excludeName, PatternMatcher.ANY_EXPRESSION); 220 } 221 createExcludeArtifactId(String excludeName, String group)222 protected ArtifactId createExcludeArtifactId(String excludeName, String group) { 223 ModuleId mid = ModuleId.newInstance(group, excludeName); 224 return new ArtifactId( 225 mid, PatternMatcher.ANY_EXPRESSION, 226 PatternMatcher.ANY_EXPRESSION, 227 PatternMatcher.ANY_EXPRESSION); 228 } 229 230 /** 231 * Adds a dependency descriptor to the project 232 * @param dd The DependencyDescriptor instance 233 */ addDependencyDescriptor(DependencyDescriptor dd)234 public void addDependencyDescriptor(DependencyDescriptor dd) { 235 if (dd != null) { 236 dependencyDescriptors.add(dd); 237 addDependency(dd.getDependencyRevisionId()); 238 } 239 } 240 createModuleDescriptor()241 public ModuleDescriptor createModuleDescriptor() { 242 // This is a blatant hack: we use an organisation that is highly 243 // unlikely to conflict with the project's dependencies. The 244 // truth is, the dependency manager doesn't really care what the 245 // organisation is. See: 246 // 247 // http://jira.codehaus.org/browse/GRAILS-6270 248 // 249 DefaultModuleDescriptor moduleDescriptor = 250 DefaultModuleDescriptor.newDefaultInstance(ModuleRevisionId.newInstance("org.grails.internal", applicationName, applicationVersion)); 251 252 // TODO: make configurations extensible 253 moduleDescriptor.addConfiguration(BUILD_CONFIGURATION); 254 moduleDescriptor.addConfiguration(COMPILE_CONFIGURATION); 255 moduleDescriptor.addConfiguration(RUNTIME_CONFIGURATION); 256 moduleDescriptor.addConfiguration(TEST_CONFIGURATION); 257 moduleDescriptor.addConfiguration(PROVIDED_CONFIGURATION); 258 moduleDescriptor.addConfiguration(DOCS_CONFIGURATION); 259 return moduleDescriptor; 260 } 261 isExcludedFromPlugin(String plugin, String dependencyName)262 public boolean isExcludedFromPlugin(String plugin, String dependencyName) { 263 DependencyDescriptor dd = pluginNameToDescriptorMap.get(plugin); 264 if (dd == null) { 265 return false; 266 } 267 268 if (!dd.isTransitive()) { 269 return true; 270 } 271 272 273 ArtifactId aid = createExcludeArtifactId(dependencyName); 274 return isExcludedFromPlugin(dd, aid); 275 } 276 isExcludedFromPlugin(DependencyDescriptor currentPlugin, ArtifactId dependency)277 public boolean isExcludedFromPlugin(DependencyDescriptor currentPlugin, ArtifactId dependency) { 278 return currentPlugin != null && currentPlugin.doesExclude(configurationNames, dependency); 279 } 280 getPluginExcludes(String plugin)281 public Set<String> getPluginExcludes(String plugin) { 282 Set<String> excludes = new HashSet<String>(); 283 DependencyDescriptor dd = pluginNameToDescriptorMap.get(plugin); 284 if (dd != null) { 285 for (ExcludeRule er : dd.getAllExcludeRules()) { 286 excludes.add(er.getId().getName()); 287 } 288 } 289 return excludes; 290 } 291 } 292