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 }