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 }