001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.kernel.repository;
019    
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.Iterator;
023    import java.util.LinkedHashSet;
024    import java.util.SortedSet;
025    import java.util.TreeSet;
026    import java.util.Map;
027    
028    import org.apache.geronimo.gbean.GBeanInfo;
029    import org.apache.geronimo.gbean.GBeanInfoBuilder;
030    import org.apache.geronimo.kernel.config.Configuration;
031    
032    /**
033     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
034     */
035    public class DefaultArtifactResolver implements ArtifactResolver {
036        private final ArtifactManager artifactManager;
037        private final Collection repositories;
038        private final Map explicitResolution;
039    
040        public DefaultArtifactResolver(ArtifactManager artifactManager, ListableRepository repository) {
041            this.artifactManager = artifactManager;
042            this.repositories = Collections.singleton(repository);
043            this.explicitResolution = Collections.EMPTY_MAP;
044        }
045    
046        public DefaultArtifactResolver(ArtifactManager artifactManager, Collection repositories, Map explicitResolution) {
047            this.artifactManager = artifactManager;
048            this.repositories = repositories;
049            this.explicitResolution = explicitResolution == null? Collections.EMPTY_MAP: explicitResolution;
050        }
051    
052    
053        public Artifact generateArtifact(Artifact source, String defaultType) {
054            if(source.isResolved()) {
055                Artifact deAliased = (Artifact) explicitResolution.get(source);
056                if (deAliased !=  null) {
057                    return deAliased;
058                }
059                return source;
060            }
061            String groupId = source.getGroupId() == null ? Artifact.DEFAULT_GROUP_ID : source.getGroupId();
062            String artifactId = source.getArtifactId();
063            String type = source.getType() == null ? defaultType : source.getType();
064            Version version = source.getVersion() == null ? new Version(Long.toString(System.currentTimeMillis())) : source.getVersion();
065    
066            return new Artifact(groupId, artifactId, version, type);
067        }
068    
069        public Artifact queryArtifact(Artifact artifact) throws MultipleMatchesException {
070            Artifact[] all = queryArtifacts(artifact);
071            if(all.length > 1) {
072                throw new MultipleMatchesException(artifact);
073            }
074            return all.length == 0 ? null : all[0];
075        }
076    
077        public Artifact[] queryArtifacts(Artifact artifact) {
078            LinkedHashSet set = new LinkedHashSet();
079            for (Iterator iterator = repositories.iterator(); iterator.hasNext();) {
080                ListableRepository repository = (ListableRepository) iterator.next();
081                set.addAll(repository.list(artifact));
082            }
083            return (Artifact[]) set.toArray(new Artifact[set.size()]);
084        }
085    
086        public LinkedHashSet resolveInClassLoader(Collection artifacts) throws MissingDependencyException {
087            return resolveInClassLoader(artifacts, Collections.EMPTY_SET);
088        }
089    
090        public LinkedHashSet resolveInClassLoader(Collection artifacts, Collection parentConfigurations) throws MissingDependencyException {
091            LinkedHashSet resolvedArtifacts = new LinkedHashSet();
092            for (Iterator iterator = artifacts.iterator(); iterator.hasNext();) {
093                Artifact artifact = (Artifact) iterator.next();
094                if (!artifact.isResolved()) {
095                    artifact = resolveInClassLoader(artifact, parentConfigurations);
096                }
097                resolvedArtifacts.add(artifact);
098            }
099            return resolvedArtifacts;
100        }
101    
102        public Artifact resolveInClassLoader(Artifact source) throws MissingDependencyException {
103            return resolveInClassLoader(source, Collections.EMPTY_SET);
104        }
105    
106        public Artifact resolveInClassLoader(Artifact source, Collection parentConfigurations) throws MissingDependencyException {
107            // Some tests break if we acntually try to search for fully-resolved artifacts
108            if(source.isResolved()) {
109                return source;
110            }
111    //        if (artifact.getType() == null) {
112    //            throw new IllegalArgumentException("Type not set " + artifact);
113    //        }
114    //
115    //        String groupId = source.getGroupId();
116    //        if (groupId == null) {
117    //            groupId = Artifact.DEFAULT_GROUP_ID;
118    //        }
119    
120    //        Version version = source.getVersion();
121    
122            Artifact working = resolveVersion(parentConfigurations, source);
123            if (working == null || !working.isResolved()) {
124                throw new MissingDependencyException("Unable to resolve dependency " + source);
125            }
126    
127            return working;
128        }
129    
130        private Artifact resolveVersion(Collection parentConfigurations, Artifact working) {
131            //see if there is an explicit resolution for this artifact.
132            Artifact deAliased = (Artifact) explicitResolution.get(working);
133            if (deAliased != null) {
134                working = deAliased;
135            }
136            SortedSet existingArtifacts;
137            if (artifactManager != null) {
138                existingArtifacts = artifactManager.getLoadedArtifacts(working);
139            } else {
140                existingArtifacts = new TreeSet();
141            }
142    
143            // if we have exactly one artifact loaded use its' version
144            if (existingArtifacts.size() == 1) {
145                return (Artifact) existingArtifacts.first();
146            }
147    
148    
149            // if we have no existing loaded artifacts grab the highest version from the repository
150            if (existingArtifacts.size() == 0) {
151                SortedSet list = new TreeSet();
152                for (Iterator iterator = repositories.iterator(); iterator.hasNext();) {
153                    ListableRepository repository = (ListableRepository) iterator.next();
154                    list.addAll(repository.list(working));
155                }
156    
157                if (list.isEmpty()) {
158                    return null;
159                }
160                return (Artifact) list.last();
161            }
162    
163            // more than one version of the artifact was loaded...
164    
165            // if one of parents already loaded the artifact, use that version
166            Artifact artifact = searchParents(parentConfigurations, working);
167            if (artifact != null) {
168                return artifact;
169            }
170    
171            // it wasn't declared by the parent so just use the highest verstion already loaded
172            return (Artifact) existingArtifacts.last();
173        }
174    
175        private Artifact searchParents(Collection parentConfigurations, Artifact working) {
176            for (Iterator iterator = parentConfigurations.iterator(); iterator.hasNext();) {
177                Configuration configuration = (Configuration) iterator.next();
178    
179                // check if this parent matches the groupId, artifactId, and type
180                if (matches(configuration.getId(), working)) {
181                    return configuration.getId();
182                }
183    
184                Environment environment = configuration.getEnvironment();
185                if (environment.isInverseClassLoading()) {
186                    // Search dependencies of the configuration before searching the parents
187                    Artifact artifact = getArtifactVersion(configuration.getDependencies(), working);
188                    if (artifact != null) {
189                        return artifact;
190                    }
191    
192                    // wasn't declared in the dependencies, so search the parents of the configuration
193                    artifact = searchParents(configuration.getClassParents(), working);
194                    if (artifact != null) {
195                        return artifact;
196                    }
197    
198                } else {
199                    // Search the parents before the dependencies of the configuration
200                    Artifact artifact = searchParents(configuration.getClassParents(), working);
201                    if (artifact != null) {
202                        return artifact;
203                    }
204    
205                    // wasn't declared in a parent check the dependencies of the configuration
206                    artifact = getArtifactVersion(configuration.getDependencies(), working);
207                    if (artifact != null) {
208                        return artifact;
209                    }
210                }
211            }
212            return null;
213        }
214    
215        private Artifact getArtifactVersion(Collection artifacts, Artifact query) {
216            for (Iterator iterator = artifacts.iterator(); iterator.hasNext();) {
217                Artifact artifact = (Artifact) iterator.next();
218                if (matches(artifact, query)) {
219                    return artifact;
220                }
221            }
222            return null;
223        }
224    
225        private boolean matches(Artifact candidate, Artifact query) {
226            return query.matches(candidate);
227        }
228    
229        public static final GBeanInfo GBEAN_INFO;
230    
231        static {
232            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(DefaultArtifactResolver.class, "ArtifactResolver");
233            infoFactory.addAttribute("explicitResolution", Map.class, true, true);
234            infoFactory.addReference("ArtifactManager", ArtifactManager.class, "ArtifactManager");
235            infoFactory.addReference("Repositories", ListableRepository.class, "Repository");
236            infoFactory.addInterface(ArtifactResolver.class);
237    
238            infoFactory.setConstructor(new String[]{
239                    "ArtifactManager",
240                    "Repositories",
241                    "explicitResolution"
242            });
243    
244    
245            GBEAN_INFO = infoFactory.getBeanInfo();
246        }
247    
248        public static GBeanInfo getGBeanInfo() {
249            return GBEAN_INFO;
250        }
251    }