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: 487175 $ $Date: 2006-12-14 03:10:31 -0800 (Thu, 14 Dec 2006) $
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                    return null;
158                }
159                return (Artifact) list.last();
160            }
161    
162            // more than one version of the artifact was loaded...
163    
164            // if one of parents already loaded the artifact, use that version
165            Artifact artifact = searchParents(parentConfigurations, working);
166            if (artifact != null) {
167                return artifact;
168            }
169    
170            // it wasn't declared by the parent so just use the highest verstion already loaded
171            return (Artifact) existingArtifacts.last();
172        }
173    
174        private Artifact searchParents(Collection parentConfigurations, Artifact working) {
175            for (Iterator iterator = parentConfigurations.iterator(); iterator.hasNext();) {
176                Configuration configuration = (Configuration) iterator.next();
177    
178                // check if this parent matches the groupId, artifactId, and type
179                if (matches(configuration.getId(), working)) {
180                    return configuration.getId();
181                }
182    
183                Environment environment = configuration.getEnvironment();
184                if (environment.isInverseClassLoading()) {
185                    // Search dependencies of the configuration before searching the parents
186                    Artifact artifact = getArtifactVersion(configuration.getDependencies(), working);
187                    if (artifact != null) {
188                        return artifact;
189                    }
190    
191                    // wasn't declared in the dependencies, so search the parents of the configuration
192                    artifact = searchParents(configuration.getClassParents(), working);
193                    if (artifact != null) {
194                        return artifact;
195                    }
196    
197                } else {
198                    // Search the parents before the dependencies of the configuration
199                    Artifact artifact = searchParents(configuration.getClassParents(), working);
200                    if (artifact != null) {
201                        return artifact;
202                    }
203    
204                    // wasn't declared in a parent check the dependencies of the configuration
205                    artifact = getArtifactVersion(configuration.getDependencies(), working);
206                    if (artifact != null) {
207                        return artifact;
208                    }
209                }
210            }
211            return null;
212        }
213    
214        private Artifact getArtifactVersion(Collection artifacts, Artifact query) {
215            for (Iterator iterator = artifacts.iterator(); iterator.hasNext();) {
216                Artifact artifact = (Artifact) iterator.next();
217                if (matches(artifact, query)) {
218                    return artifact;
219                }
220            }
221            return null;
222        }
223    
224        private boolean matches(Artifact candidate, Artifact query) {
225            return query.matches(candidate);
226        }
227    
228        public static final GBeanInfo GBEAN_INFO;
229    
230        static {
231            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(DefaultArtifactResolver.class, "ArtifactResolver");
232            infoFactory.addAttribute("explicitResolution", Map.class, true, true);
233            infoFactory.addReference("ArtifactManager", ArtifactManager.class, "ArtifactManager");
234            infoFactory.addReference("Repositories", ListableRepository.class, "Repository");
235            infoFactory.addInterface(ArtifactResolver.class);
236    
237            infoFactory.setConstructor(new String[]{
238                    "ArtifactManager",
239                    "Repositories",
240                    "explicitResolution"
241            });
242    
243    
244            GBEAN_INFO = infoFactory.getBeanInfo();
245        }
246    
247        public static GBeanInfo getGBeanInfo() {
248            return GBEAN_INFO;
249        }
250    }