001    /*
002     * Copyright (C) 2006-2007 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.codehaus.gmaven.plugin;
018    
019    import org.apache.maven.artifact.Artifact;
020    import org.apache.maven.artifact.DependencyResolutionRequiredException;
021    import org.apache.maven.artifact.factory.ArtifactFactory;
022    import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
023    import org.apache.maven.artifact.repository.ArtifactRepository;
024    import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
025    import org.apache.maven.artifact.resolver.ArtifactResolutionException;
026    import org.apache.maven.artifact.resolver.ArtifactResolver;
027    import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
028    import org.apache.maven.artifact.versioning.VersionRange;
029    import org.apache.maven.model.Dependency;
030    import org.apache.maven.plugin.AbstractMojo;
031    import org.apache.maven.plugin.MojoExecutionException;
032    import org.apache.maven.plugin.MojoFailureException;
033    import org.apache.maven.project.MavenProject;
034    import org.codehaus.gmaven.common.ArtifactItem;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    
038    import java.io.File;
039    import java.net.URL;
040    import java.util.ArrayList;
041    import java.util.Collections;
042    import java.util.List;
043    
044    /**
045     * Support for Mojo implementations.
046     *
047     * @version $Id: MojoSupport.java 76 2009-12-05 12:04:30Z user57 $
048     * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
049     */
050    public abstract class MojoSupport
051        extends AbstractMojo
052    {
053        protected final Logger log = LoggerFactory.getLogger(getClass());
054        
055        /**
056         * @parameter expression="${project}"
057         * @required
058         * @readonly
059         *
060         * @noinspection UnusedDeclaration
061         */
062        protected MavenProject project;
063    
064        /**
065         * Main Mojo execution hook.  Sub-class should use {@link #doExecute} instead.
066         */
067        public void execute() throws MojoExecutionException, MojoFailureException {
068            try {
069                doExecute();
070            }
071            catch (Exception e) {
072                //
073                // NOTE: Wrap to avoid truncating the stacktrace
074                //
075    
076                if (e instanceof MojoExecutionException) {
077                    throw new MojoExecutionException(e.getMessage(), e);
078                }
079                else if (e instanceof MojoFailureException) {
080                    MojoFailureException x = new MojoFailureException(e.getMessage());
081                    x.initCause(e);
082                    throw x;
083                }
084                else {
085                    throw new MojoExecutionException(e.getMessage(), e);
086                }
087            }
088        }
089    
090        protected abstract void doExecute() throws Exception;
091    
092        //
093        // Classpath Muck
094        //
095    
096        protected List getProjectClasspathElements() throws DependencyResolutionRequiredException {
097            return Collections.EMPTY_LIST;
098        }
099    
100        protected ArtifactItem[] getUserClassspathElements() {
101            return new ArtifactItem[0];
102        }
103    
104        protected URL[] createClassPath() throws Exception {
105            List list = new ArrayList();
106    
107            // Add the projects dependencies
108            List files = getProjectClasspathElements();
109            if (files != null) {
110                log.debug("Project Classpath:");
111    
112                for (int i = 0; i < files.size(); ++i) {
113                    URL url = new File((String)files.get(i)).toURI().toURL();
114                    list.add(url);
115                    log.debug("    {}", url);
116                }
117            }
118    
119            // Add user dependencies (if there are any)
120            ArtifactItem[] items = getUserClassspathElements();
121    
122            if (items != null) {
123                log.debug("User Classpath:");
124    
125                for (int i=0; i < items.length; i++) {
126                    Artifact artifact = getArtifact(items[i]);
127                    URL url = artifact.getFile().toURI().toURL();
128                    list.add(url);
129                    log.debug("    {}", url);
130                }
131            }
132    
133            return (URL[])list.toArray(new URL[list.size()]);
134        }
135    
136        //
137        // Artifact Muck
138        //
139    
140        /**
141         * @component
142         * @readonly
143         * @required
144         *
145         * @noinspection UnusedDeclaration
146         */
147        protected ArtifactFactory artifactFactory;
148    
149        /**
150         * @component
151         * @readonly
152         * @required
153         *
154         * @noinspection UnusedDeclaration
155         */
156        protected ArtifactResolver artifactResolver;
157    
158        /**
159         * @component
160         * @readonly
161         * @required
162         *
163         * @noinspection UnusedDeclaration
164         */
165        protected ArtifactMetadataSource artifactMetadataSource;
166    
167        /**
168         * @parameter expression="${localRepository}"
169         * @readonly
170         * @required
171         *
172         * @noinspection UnusedDeclaration
173         */
174        protected ArtifactRepository artifactRepository;
175        
176        /**
177         * @parameter expression="${project.pluginArtifactRepositories}"
178         * @required
179         * @readonly
180         *
181         * @noinspection UnusedDeclaration
182         */
183        protected List remoteRepositories;
184        
185        /**
186         * Create a new artifact. If no version is specified, it will be retrieved from the dependency
187         * list or from the DependencyManagement section of the pom.
188         *
189         * @param item  The item to create an artifact for
190         * @return      An unresolved artifact for the given item.
191         *
192         * @throws MojoExecutionException   Failed to create artifact
193         */
194        protected Artifact createArtifact(final ArtifactItem item) throws MojoExecutionException {
195            assert item != null;
196    
197            if (item.getVersion() == null) {
198                fillMissingArtifactVersion(item);
199    
200                if (item.getVersion() == null) {
201                    throw new MojoExecutionException("Unable to find artifact version of " + item.getGroupId()
202                        + ":" + item.getArtifactId() + " in either dependency list or in project's dependency management.");
203                }
204            }
205    
206            // Convert the string version to a range
207            VersionRange range;
208            try {
209                range = VersionRange.createFromVersionSpec(item.getVersion());
210                log.trace("Using version range: {}", range);
211            }
212            catch (InvalidVersionSpecificationException e) {
213                throw new MojoExecutionException("Could not create range for version: " + item.getVersion(), e);
214            }
215    
216            return artifactFactory.createDependencyArtifact(
217                item.getGroupId(),
218                item.getArtifactId(),
219                range,
220                item.getType(),
221                item.getClassifier(),
222                Artifact.SCOPE_PROVIDED);
223        }
224    
225        /**
226         * Resolves the Artifact from the remote repository if necessary. If no version is specified, it will
227         * be retrieved from the dependency list or from the DependencyManagement section of the pom.
228         *
229         *
230         * @param item  The item to create an artifact for; must not be null
231         * @return      The artifact for the given item
232         *
233         * @throws MojoExecutionException   Failed to create artifact
234         */
235        protected Artifact getArtifact(final ArtifactItem item) throws MojoExecutionException {
236            assert item != null;
237    
238            Artifact artifact = createArtifact(item);
239    
240            return resolveArtifact(artifact, false);
241        }
242    
243        /**
244         * Resolves the Artifact from the remote repository if necessary. If no version is specified, it will
245         * be retrieved from the dependency list or from the DependencyManagement section of the pom.
246         *
247         * @param artifact      The artifact to be resolved; must not be null
248         * @param transitive    True to resolve the artifact transitively
249         * @return              The resolved artifact; never null
250         *
251         * @throws MojoExecutionException   Failed to resolve artifact
252         */
253        protected Artifact resolveArtifact(final Artifact artifact, final boolean transitive) throws MojoExecutionException {
254            assert artifact != null;
255    
256            try {
257                if (transitive) {
258                    artifactResolver.resolveTransitively(
259                            Collections.singleton(artifact),
260                            project.getArtifact(),
261                            project.getRemoteArtifactRepositories(),
262                            artifactRepository,
263                            artifactMetadataSource);
264                }
265                else {
266                    artifactResolver.resolve(
267                            artifact,
268                            project.getRemoteArtifactRepositories(),
269                            artifactRepository);
270                }
271            }
272            catch (ArtifactResolutionException e) {
273                throw new MojoExecutionException("Unable to resolve artifact", e);
274            }
275            catch (ArtifactNotFoundException e) {
276                throw new MojoExecutionException("Unable to find artifact", e);
277            }
278    
279            return artifact;
280        }
281    
282        /**
283         * Tries to find missing version from dependency list and dependency management.
284         * If found, the artifact is updated with the correct version.
285         *
286         * @param item  The item to fill in missing version details into
287         */
288        private void fillMissingArtifactVersion(final ArtifactItem item) {
289            log.trace("Attempting to find missing version in {}:{}", item.getGroupId() , item.getArtifactId());
290    
291            List list = project.getDependencies();
292    
293            for (int i = 0; i < list.size(); ++i) {
294                Dependency dependency = (Dependency) list.get(i);
295    
296                if (dependency.getGroupId().equals(item.getGroupId())
297                    && dependency.getArtifactId().equals(item.getArtifactId())
298                    && dependency.getType().equals(item.getType()))
299                {
300                    log.trace("Found missing version: {} in dependency list", dependency.getVersion());
301    
302                    item.setVersion(dependency.getVersion());
303    
304                    return;
305                }
306            }
307    
308            list = project.getDependencyManagement().getDependencies();
309    
310            for (int i = 0; i < list.size(); i++) {
311                Dependency dependency = (Dependency) list.get(i);
312    
313                if (dependency.getGroupId().equals(item.getGroupId())
314                    && dependency.getArtifactId().equals(item.getArtifactId())
315                    && dependency.getType().equals(item.getType()))
316                {
317                    log.trace("Found missing version: {} in dependency management list", dependency.getVersion());
318    
319                    item.setVersion(dependency.getVersion());
320                }
321            }
322        }
323    }