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.repository;
018
019 import java.util.Collection;
020 import java.util.Collections;
021 import java.util.LinkedHashSet;
022 import java.util.Map;
023 import java.util.SortedSet;
024 import java.util.TreeSet;
025 import java.util.concurrent.ConcurrentHashMap;
026
027 import org.apache.geronimo.gbean.GBeanInfo;
028 import org.apache.geronimo.gbean.GBeanInfoBuilder;
029 import org.apache.geronimo.kernel.config.Configuration;
030
031 /**
032 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
033 */
034 public class DefaultArtifactResolver implements ArtifactResolver {
035 private final ArtifactManager artifactManager;
036 private final Collection<? extends ListableRepository> repositories;
037 private final Map<Artifact, Artifact> explicitResolution = new ConcurrentHashMap<Artifact, Artifact>();
038
039 public DefaultArtifactResolver(ArtifactManager artifactManager, ListableRepository repository) {
040 this.artifactManager = artifactManager;
041 this.repositories = Collections.singleton(repository);
042 }
043
044 public DefaultArtifactResolver(ArtifactManager artifactManager, Collection<? extends ListableRepository> repositories, Map<Artifact, Artifact> explicitResolution) {
045 this.artifactManager = artifactManager;
046 this.repositories = repositories;
047 if (explicitResolution != null) {
048 this.explicitResolution.putAll(explicitResolution);
049 }
050 }
051
052 protected Map<Artifact, Artifact> getExplicitResolution() {
053 return explicitResolution;
054 }
055
056 public Artifact generateArtifact(Artifact source, String defaultType) {
057 if(source.isResolved()) {
058 Artifact deAliased = explicitResolution.get(source);
059 if (deAliased != null) {
060 return deAliased;
061 }
062 return source;
063 }
064 String groupId = source.getGroupId() == null ? Artifact.DEFAULT_GROUP_ID : source.getGroupId();
065 String artifactId = source.getArtifactId();
066 String type = source.getType() == null ? defaultType : source.getType();
067 Version version = source.getVersion() == null ? new Version(Long.toString(System.currentTimeMillis())) : source.getVersion();
068
069 return new Artifact(groupId, artifactId, version, type);
070 }
071
072 public Artifact queryArtifact(Artifact artifact) throws MultipleMatchesException {
073 Artifact[] all = queryArtifacts(artifact);
074 if(all.length > 1) {
075 throw new MultipleMatchesException(artifact);
076 }
077 return all.length == 0 ? null : all[0];
078 }
079
080 public Artifact[] queryArtifacts(Artifact artifact) {
081 //see if there is an explicit resolution for this artifact.
082 Artifact deAliased = explicitResolution.get(artifact);
083 if (deAliased != null) {
084 artifact = deAliased;
085 }
086 LinkedHashSet<Artifact> set = new LinkedHashSet<Artifact>();
087 for (ListableRepository repository : repositories) {
088 set.addAll(repository.list(artifact));
089 }
090 return set.toArray(new Artifact[set.size()]);
091 }
092
093 public LinkedHashSet<Artifact> resolveInClassLoader(Collection<Artifact> artifacts) throws MissingDependencyException {
094 return resolveInClassLoader(artifacts, Collections.<Configuration>emptySet());
095 }
096
097 public LinkedHashSet<Artifact> resolveInClassLoader(Collection<Artifact> artifacts, Collection<Configuration> parentConfigurations) throws MissingDependencyException {
098 LinkedHashSet<Artifact> resolvedArtifacts = new LinkedHashSet<Artifact>();
099 for (Artifact artifact : artifacts) {
100 if (!artifact.isResolved()) {
101 artifact = resolveInClassLoader(artifact, parentConfigurations);
102 }
103 resolvedArtifacts.add(artifact);
104 }
105 return resolvedArtifacts;
106 }
107
108 public Artifact resolveInClassLoader(Artifact source) throws MissingDependencyException {
109 return resolveInClassLoader(source, Collections.<Configuration>emptySet());
110 }
111
112 public Artifact resolveInClassLoader(Artifact source, Collection<Configuration> parentConfigurations) throws MissingDependencyException {
113 Artifact working = resolveVersion(parentConfigurations, source);
114 if (working == null || !working.isResolved()) {
115 //todo can parentConfigurations be included?
116 throw new MissingDependencyException(source);
117 }
118
119 return working;
120 }
121
122 private Artifact resolveVersion(Collection<Configuration> parentConfigurations, Artifact working) {
123 //see if there is an explicit resolution for this artifact.
124 Artifact deAliased = explicitResolution.get(working);
125 if (deAliased != null) {
126 working = deAliased;
127 }
128 if (working.isResolved()) {
129 return working;
130 }
131 SortedSet existingArtifacts;
132 if (artifactManager != null) {
133 existingArtifacts = artifactManager.getLoadedArtifacts(working);
134 } else {
135 existingArtifacts = new TreeSet();
136 }
137
138 // if we have exactly one artifact loaded use its' version
139 if (existingArtifacts.size() == 1) {
140 return (Artifact) existingArtifacts.first();
141 }
142
143
144 // if we have no existing loaded artifacts grab the highest version from the repository
145 if (existingArtifacts.size() == 0) {
146 SortedSet<Artifact> list = new TreeSet<Artifact>();
147 for (ListableRepository repository : repositories) {
148 list.addAll(repository.list(working));
149 }
150
151 if (list.isEmpty()) {
152 if ("xbean-naming".equals(working.getArtifactId())) {
153 return new Artifact("org.apache.xbean", "xbean-naming", "2.8", "jar");
154 } else {
155 return null;
156 }
157 }
158 return list.last();
159 }
160
161 // more than one version of the artifact was loaded...
162
163 // if one of parents already loaded the artifact, use that version
164 Artifact artifact = searchParents(parentConfigurations, working);
165 if (artifact != null) {
166 return artifact;
167 }
168
169 // it wasn't declared by the parent so just use the highest verstion already loaded
170 return (Artifact) existingArtifacts.last();
171 }
172
173 private Artifact searchParents(Collection<Configuration> parentConfigurations, Artifact working) {
174 for (Configuration configuration : parentConfigurations) {
175
176 // check if this parent matches the groupId, artifactId, and type
177 if (matches(configuration.getId(), working)) {
178 return configuration.getId();
179 }
180
181 Environment environment = configuration.getEnvironment();
182 if (environment.isInverseClassLoading()) {
183 // Search dependencies of the configuration before searching the parents
184 Artifact artifact = getArtifactVersion(configuration.getDependencies(), working);
185 if (artifact != null) {
186 return artifact;
187 }
188
189 // wasn't declared in the dependencies, so search the parents of the configuration
190 artifact = searchParents(configuration.getClassParents(), working);
191 if (artifact != null) {
192 return artifact;
193 }
194
195 } else {
196 // Search the parents before the dependencies of the configuration
197 Artifact artifact = searchParents(configuration.getClassParents(), working);
198 if (artifact != null) {
199 return artifact;
200 }
201
202 // wasn't declared in a parent check the dependencies of the configuration
203 artifact = getArtifactVersion(configuration.getDependencies(), working);
204 if (artifact != null) {
205 return artifact;
206 }
207 }
208 }
209 return null;
210 }
211
212 private Artifact getArtifactVersion(Collection<Artifact> artifacts, Artifact query) {
213 for (Artifact artifact : artifacts) {
214 if (matches(artifact, query)) {
215 return artifact;
216 }
217 }
218 return null;
219 }
220
221 private boolean matches(Artifact candidate, Artifact query) {
222 return query.matches(candidate);
223 }
224
225 public static final GBeanInfo GBEAN_INFO;
226
227 static {
228 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(DefaultArtifactResolver.class, "ArtifactResolver");
229 infoFactory.addAttribute("explicitResolution", Map.class, true, true);
230 infoFactory.addReference("ArtifactManager", ArtifactManager.class, "ArtifactManager");
231 infoFactory.addReference("Repositories", ListableRepository.class, "Repository");
232 infoFactory.addInterface(ArtifactResolver.class);
233
234 infoFactory.setConstructor(new String[]{
235 "ArtifactManager",
236 "Repositories",
237 "explicitResolution"
238 });
239
240
241 GBEAN_INFO = infoFactory.getBeanInfo();
242 }
243
244 public static GBeanInfo getGBeanInfo() {
245 return GBEAN_INFO;
246 }
247 }