001package org.apache.maven.plugins.enforcer.utils;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.io.IOException;
024import java.io.Reader;
025import java.util.ArrayList;
026import java.util.List;
027
028import org.apache.maven.artifact.Artifact;
029import org.apache.maven.artifact.factory.ArtifactFactory;
030import org.apache.maven.artifact.repository.ArtifactRepository;
031import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
032import org.apache.maven.artifact.resolver.ArtifactResolutionException;
033import org.apache.maven.artifact.resolver.ArtifactResolver;
034import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
035import org.apache.maven.model.Model;
036import org.apache.maven.model.Parent;
037import org.apache.maven.model.Plugin;
038import org.apache.maven.model.ReportPlugin;
039import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
040import org.apache.maven.plugin.logging.Log;
041import org.apache.maven.project.MavenProject;
042import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
043import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
044import org.codehaus.plexus.util.ReaderFactory;
045import org.codehaus.plexus.util.StringUtils;
046import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
047
048// TODO: Auto-generated Javadoc
049/**
050 * The Class EnforcerRuleUtils.
051 *
052 * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
053 */
054public class EnforcerRuleUtils
055{
056
057    /** The factory. */
058    ArtifactFactory factory;
059
060    /** The resolver. */
061    ArtifactResolver resolver;
062
063    /** The local. */
064    ArtifactRepository local;
065
066    /** The remote repositories. */
067    List<ArtifactRepository> remoteRepositories;
068
069    /** The log. */
070    Log log;
071
072    /** The project. */
073    MavenProject project;
074
075    private EnforcerRuleHelper helper;
076
077    /**
078     * Instantiates a new enforcer rule utils.
079     *
080     * @param theFactory the the factory
081     * @param theResolver the the resolver
082     * @param theLocal the the local
083     * @param theRemoteRepositories the the remote repositories
084     * @param project the project
085     * @param theLog the the log
086     */
087    public EnforcerRuleUtils( ArtifactFactory theFactory, ArtifactResolver theResolver, ArtifactRepository theLocal,
088                              List<ArtifactRepository> theRemoteRepositories, MavenProject project, Log theLog )
089    {
090        super();
091        this.factory = theFactory;
092        this.resolver = theResolver;
093        this.local = theLocal;
094        this.remoteRepositories = theRemoteRepositories;
095        this.log = theLog;
096        this.project = project;
097    }
098
099    /**
100     * Instantiates a new enforcer rule utils.
101     *
102     * @param helper the helper
103     */
104    @SuppressWarnings( "unchecked" )
105    public EnforcerRuleUtils( EnforcerRuleHelper helper )
106    {
107
108        this.helper = helper;
109        // get the various expressions out of the
110        // helper.
111        try
112        {
113            factory = (ArtifactFactory) helper.getComponent( ArtifactFactory.class );
114            resolver = (ArtifactResolver) helper.getComponent( ArtifactResolver.class );
115            local = (ArtifactRepository) helper.evaluate( "${localRepository}" );
116            project = (MavenProject) helper.evaluate( "${project}" );
117            remoteRepositories = project.getRemoteArtifactRepositories();
118        }
119        catch ( ComponentLookupException e )
120        {
121            // TODO Auto-generated catch block
122            e.printStackTrace();
123        }
124        catch ( ExpressionEvaluationException e )
125        {
126            // TODO Auto-generated catch block
127            e.printStackTrace();
128        }
129    }
130
131    /**
132     * Gets the pom model for this file.
133     *
134     * @param pom the pom
135     *
136     * @return the model
137     *
138     * @throws IOException Signals that an I/O exception has occurred.
139     * @throws XmlPullParserException the xml pull parser exception
140     */
141    private Model readModel ( File pom )
142        throws IOException, XmlPullParserException
143    {
144        Reader reader = ReaderFactory.newXmlReader( pom );
145        MavenXpp3Reader xpp3 = new MavenXpp3Reader();
146        Model model = null;
147        try
148        {
149            model = xpp3.read( reader );
150        }
151        finally
152        {
153            reader.close();
154            reader = null;
155        }
156        return model;
157    }
158
159    /**
160     * This method gets the model for the defined artifact.
161     * Looks first in the filesystem, then tries to get it
162     * from the repo.
163     *
164     * @param groupId the group id
165     * @param artifactId the artifact id
166     * @param version the version
167     * @param pom the pom
168     *
169     * @return the pom model
170     *
171     * @throws ArtifactResolutionException the artifact resolution exception
172     * @throws ArtifactNotFoundException the artifact not found exception
173     * @throws XmlPullParserException the xml pull parser exception
174     * @throws IOException Signals that an I/O exception has occurred.
175     */
176    private Model getPomModel ( String groupId, String artifactId, String version, File pom )
177        throws ArtifactResolutionException, ArtifactNotFoundException, IOException, XmlPullParserException
178    {
179        Model model = null;
180
181        // do we want to look in the reactor like the
182        // project builder? Would require @aggregator goal
183        // which causes problems in maven core right now
184        // because we also need dependency resolution in
185        // other
186        // rules. (MNG-2277)
187
188        // look in the location specified by pom first.
189        boolean found = false;
190        try
191        {
192            model = readModel( pom );
193
194            // i found a model, lets make sure it's the one
195            // I want
196            found = checkIfModelMatches( groupId, artifactId, version, model );
197        }
198        catch ( IOException e )
199        {
200            // nothing here, but lets look in the repo
201            // before giving up.
202        }
203        catch ( XmlPullParserException e )
204        {
205            // nothing here, but lets look in the repo
206            // before giving up.
207        }
208
209        // i didn't find it in the local file system, go
210        // look in the repo
211        if ( !found )
212        {
213            Artifact pomArtifact = factory.createArtifact( groupId, artifactId, version, null, "pom" );
214            resolver.resolve( pomArtifact, remoteRepositories, local );
215            model = readModel( pomArtifact.getFile() );
216        }
217
218        return model;
219    }
220
221    /**
222     * This method loops through all the parents, getting
223     * each pom model and then its parent.
224     *
225     * @param groupId the group id
226     * @param artifactId the artifact id
227     * @param version the version
228     * @param pom the pom
229     *
230     * @return the models recursively
231     *
232     * @throws ArtifactResolutionException the artifact resolution exception
233     * @throws ArtifactNotFoundException the artifact not found exception
234     * @throws IOException Signals that an I/O exception has occurred.
235     * @throws XmlPullParserException the xml pull parser exception
236     */
237    public List<Model> getModelsRecursively ( String groupId, String artifactId, String version, File pom )
238        throws ArtifactResolutionException, ArtifactNotFoundException, IOException, XmlPullParserException
239    {
240        List<Model> models = null;
241        Model model = getPomModel( groupId, artifactId, version, pom );
242
243        Parent parent = model.getParent();
244
245        // recurse into the parent
246        if ( parent != null )
247        {
248            // get the relative path
249            String relativePath = parent.getRelativePath();
250            if ( StringUtils.isEmpty( relativePath ) )
251            {
252                relativePath = "../pom.xml";
253            }
254            // calculate the recursive path
255            File parentPom = new File( pom.getParent(), relativePath );
256
257            // if relative path is a directory, append pom.xml
258            if ( parentPom.isDirectory() )
259            {
260                parentPom = new File( parentPom, "pom.xml" );
261            }
262
263            models = getModelsRecursively( parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), parentPom );
264        }
265        else
266        {
267            // only create it here since I'm not at the top
268            models = new ArrayList<Model>();
269        }
270        models.add( model );
271
272        return models;
273    }
274
275    /**
276     * Make sure the model is the one I'm expecting.
277     *
278     * @param groupId the group id
279     * @param artifactId the artifact id
280     * @param version the version
281     * @param model Model being checked.
282     *
283     * @return true, if check if model matches
284     */
285    protected boolean checkIfModelMatches ( String groupId, String artifactId, String version, Model model )
286    {
287        // try these first.
288        String modelGroup = model.getGroupId();
289        String modelArtifactId = model.getArtifactId();
290        String modelVersion = model.getVersion();
291
292        try
293        {
294            if ( StringUtils.isEmpty( modelGroup ) )
295            {
296                modelGroup = model.getParent().getGroupId();
297            }
298            else
299            {
300                // MENFORCER-30, handle cases where the value is a property like ${project.parent.groupId}
301                modelGroup = (String) helper.evaluate( modelGroup );
302            }
303
304            if ( StringUtils.isEmpty( modelVersion ) )
305            {
306                modelVersion = model.getParent().getVersion();
307            }
308            else
309            {
310                // MENFORCER-30, handle cases where the value is a property like ${project.parent.version}
311                modelVersion = (String) helper.evaluate( modelVersion );
312            }
313            
314            // Is this only required for Maven2?
315            modelArtifactId = (String) helper.evaluate( modelArtifactId );
316        }
317        catch ( NullPointerException e )
318        {
319            // this is probably bad. I don't have a valid
320            // group or version and I can't find a
321            // parent????
322            // lets see if it's what we're looking for
323            // anyway.
324        }
325        catch ( ExpressionEvaluationException e )
326        {
327            // as above
328        }
329        return ( StringUtils.equals( groupId, modelGroup ) && StringUtils.equals( version, modelVersion ) && StringUtils
330            .equals( artifactId, modelArtifactId ) );
331    }
332    
333 
334    private void resolve( Plugin plugin )
335    {
336        try
337        {
338            plugin.setGroupId( (String) helper.evaluate( plugin.getGroupId() ) );
339            plugin.setArtifactId( (String) helper.evaluate( plugin.getArtifactId() ) );
340            plugin.setVersion( (String) helper.evaluate( plugin.getVersion() ) );
341        }
342        catch ( ExpressionEvaluationException e )
343        {
344            // this should have gone already before
345        }
346    }
347    
348    private void resolve( ReportPlugin plugin )
349    {
350        try
351        {
352            plugin.setGroupId( (String) helper.evaluate( plugin.getGroupId() ) );
353            plugin.setArtifactId( (String) helper.evaluate( plugin.getArtifactId() ) );
354            plugin.setVersion( (String) helper.evaluate( plugin.getVersion() ) );
355        }
356        catch ( ExpressionEvaluationException e )
357        {
358            // this should have gone already before
359        }
360    }
361    
362    public List<Plugin> resolvePlugins( List<Plugin> plugins )
363    {
364        for ( Plugin plugin : plugins )
365        {
366            resolve( plugin );
367        }
368        return plugins;
369    }
370    
371    public List<ReportPlugin> resolveReportPlugins( List<ReportPlugin> reportPlugins )
372    {
373        for ( ReportPlugin plugin : reportPlugins )
374        {
375            resolve( plugin );
376        }
377        return reportPlugins;
378    }
379
380
381}