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