001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.kernel.config; 018 019 import java.util.List; 020 import java.util.Collection; 021 import java.util.ArrayList; 022 import java.util.Iterator; 023 import java.util.LinkedHashSet; 024 import java.util.Collections; 025 import java.util.Set; 026 import java.util.Stack; 027 import java.io.File; 028 import java.net.MalformedURLException; 029 030 import org.apache.geronimo.kernel.repository.ArtifactResolver; 031 import org.apache.geronimo.kernel.repository.MissingDependencyException; 032 import org.apache.geronimo.kernel.repository.Dependency; 033 import org.apache.geronimo.kernel.repository.Artifact; 034 import org.apache.geronimo.kernel.repository.Repository; 035 import org.apache.geronimo.kernel.repository.ImportType; 036 037 /** 038 * @version $Rev: 517813 $ $Date: 2007-03-13 14:37:38 -0400 (Tue, 13 Mar 2007) $ 039 */ 040 public class ConfigurationResolver { 041 private final Artifact configurationId; 042 private final ArtifactResolver artifactResolver; 043 private final Collection repositories; 044 045 /** 046 * file or configstore used to resolve classpath parts 047 */ 048 private final File baseDir; 049 private final ConfigurationStore configurationStore; 050 051 /** 052 * For nested configurations, the module name will be non-null. 053 */ 054 private final String moduleName; 055 056 057 public ConfigurationResolver(Artifact configurationId, File baseDir) { 058 if (configurationId == null) throw new NullPointerException("configurationId is null"); 059 060 this.configurationId = configurationId; 061 this.baseDir = baseDir; 062 artifactResolver = null; 063 repositories = Collections.EMPTY_SET; 064 configurationStore = null; 065 moduleName = null; 066 } 067 068 public ConfigurationResolver(ConfigurationData configurationData, Collection repositories, ArtifactResolver artifactResolver) { 069 if (configurationData == null) throw new NullPointerException("configurationData is null"); 070 if (repositories == null) repositories = Collections.EMPTY_SET; 071 072 configurationId = configurationData.getId(); 073 this.artifactResolver = artifactResolver; 074 this.repositories = repositories; 075 configurationStore = configurationData.getConfigurationStore(); 076 if (null != configurationData.getInPlaceConfigurationDir()) { 077 baseDir = configurationData.getInPlaceConfigurationDir(); 078 } else { 079 baseDir = configurationData.getConfigurationDir(); 080 } 081 moduleName = null; 082 } 083 084 private ConfigurationResolver(Artifact configurationId, ArtifactResolver artifactResolver, Collection repositories, File baseDir, ConfigurationStore configurationStore, String moduleName) { 085 this.configurationId = configurationId; 086 this.artifactResolver = artifactResolver; 087 this.repositories = repositories; 088 this.baseDir = baseDir; 089 this.configurationStore = configurationStore; 090 this.moduleName = moduleName; 091 } 092 093 public ConfigurationResolver createChildResolver(String moduleName) { 094 if (moduleName == null) throw new NullPointerException("moduleName is null"); 095 if (this.moduleName != null) { 096 moduleName = this.moduleName + '/' + moduleName; 097 } 098 099 File childBaseDir = null; 100 if (baseDir != null) { 101 childBaseDir = new File(baseDir, moduleName); 102 } 103 return new ConfigurationResolver(configurationId, artifactResolver, repositories, childBaseDir, configurationStore, moduleName); 104 } 105 106 public File resolve(Artifact artifact) throws MissingDependencyException { 107 for (Iterator j = repositories.iterator(); j.hasNext();) { 108 Repository repository = (Repository) j.next(); 109 if (repository.contains(artifact)) { 110 File file = repository.getLocation(artifact); 111 return file; 112 } 113 } 114 throw new MissingDependencyException("Unable to resolve dependency " + artifact); 115 } 116 117 public Set resolve(String pattern) throws MalformedURLException, NoSuchConfigException { 118 if (configurationStore != null) { 119 Set matches = configurationStore.resolve(configurationId, moduleName, pattern); 120 return matches; 121 } else if (baseDir != null) { 122 Set matches = IOUtil.search(baseDir, pattern); 123 return matches; 124 } else { 125 throw new IllegalStateException("No configurationStore or baseDir supplied so paths can not be resolved"); 126 } 127 } 128 129 public List resolveTransitiveDependencies(Collection parents, List dependencies) throws MissingDependencyException { 130 Stack<Dependency> parentStack = new Stack<Dependency>(); 131 return internalResolveTransitiveDependencies(parents, dependencies, parentStack); 132 } 133 134 private List internalResolveTransitiveDependencies(Collection parents, List dependencies, Stack parentStack) throws MissingDependencyException { 135 List resolvedDependencies = new ArrayList(); 136 for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) { 137 Dependency dependency = resolveDependency(parents, (Dependency) iterator.next(), parentStack); 138 139 if (!resolvedDependencies.contains(dependency)) { 140 resolvedDependencies.add(dependency); 141 142 List childDependencies = getChildDependencies(dependency); 143 if (!childDependencies.isEmpty()) { 144 parentStack.push(dependency); 145 childDependencies = internalResolveTransitiveDependencies(parents, childDependencies, parentStack); 146 parentStack.pop(); 147 resolvedDependencies.addAll(childDependencies); 148 } 149 } 150 } 151 return resolvedDependencies; 152 } 153 154 private Dependency resolveDependency(Collection parents, Dependency dependency, Stack<Dependency> parentStack) throws MissingDependencyException { 155 Artifact artifact = dependency.getArtifact(); 156 157 // if it is already resolved we are done 158 if (artifact.isResolved()) { 159 return dependency; 160 } 161 162 // we need an artifact resolver at this point 163 if (artifactResolver == null) { 164 throw new MissingDependencyException("Artifact is not resolved and there no artifact resolver available: " + artifact); 165 } 166 167 // resolve the artifact 168 try { 169 artifact = artifactResolver.resolveInClassLoader(artifact, parents); 170 } catch (MissingDependencyException e) { 171 // I'm throwing away the original error as the new message is lost on the stack as 172 // most folks will drill down to the message on the bottom of the stack. 173 StringBuffer sb = new StringBuffer(); 174 sb.append(e.getMessage().trim()+"\n"+" Parent stack:\n"); 175 boolean first = true; 176 for (Dependency d : parentStack) { 177 sb.append(" "+d.getArtifact().toString().trim()+(first?" (top)":"")+"\n"); 178 first = false; 179 } 180 throw new MissingDependencyException(sb.toString()); 181 } 182 183 // build a new dependency object to contain the resolved artifact 184 Dependency resolvedDependency = new Dependency(artifact, dependency.getImportType()); 185 return resolvedDependency; 186 } 187 188 private ArrayList getChildDependencies(Dependency dependency) { 189 ArrayList childDependencies = new ArrayList(); 190 for (Iterator repositoryIterator = repositories.iterator(); repositoryIterator.hasNext();) { 191 Repository repository = (Repository) repositoryIterator.next(); 192 if (repository.contains(dependency.getArtifact())) { 193 // get the child artifacts 194 LinkedHashSet childArtifacts = repository.getDependencies(dependency.getArtifact()); 195 for (Iterator artifactIterator = childArtifacts.iterator(); artifactIterator.hasNext();) { 196 Artifact artifact = (Artifact) artifactIterator.next(); 197 // add each child as a classes-only dependency 198 childDependencies.add(new Dependency(artifact, ImportType.CLASSES)); 199 } 200 } 201 } 202 return childDependencies; 203 } 204 }