001package org.apache.maven.script.ant;
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 org.apache.maven.artifact.Artifact;
023import org.apache.maven.artifact.DependencyResolutionRequiredException;
024import org.apache.maven.execution.MavenSession;
025import org.apache.maven.plugin.AbstractMojo;
026import org.apache.maven.plugin.ContextEnabled;
027import org.apache.maven.plugin.MojoExecution;
028import org.apache.maven.plugin.MojoExecutionException;
029import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
030import org.apache.maven.plugin.descriptor.PluginDescriptor;
031import org.apache.maven.project.MavenProject;
032import org.apache.maven.project.path.PathTranslator;
033import org.apache.tools.ant.Project;
034import org.apache.tools.ant.PropertyHelper;
035import org.apache.tools.ant.types.Path;
036import org.codehaus.plexus.archiver.ArchiverException;
037import org.codehaus.plexus.archiver.UnArchiver;
038import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
039import org.codehaus.plexus.component.MapOrientedComponent;
040import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
041import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
042import org.codehaus.plexus.component.factory.ant.AntComponentExecutionException;
043import org.codehaus.plexus.component.factory.ant.AntScriptInvoker;
044import org.codehaus.plexus.component.repository.ComponentRequirement;
045import org.codehaus.plexus.logging.LogEnabled;
046import org.codehaus.plexus.logging.Logger;
047import org.codehaus.plexus.util.StringUtils;
048
049import java.io.File;
050import java.util.ArrayList;
051import java.util.Collection;
052import java.util.HashMap;
053import java.util.List;
054import java.util.Map;
055
056public class AntMojoWrapper
057    extends AbstractMojo
058    implements ContextEnabled, MapOrientedComponent, LogEnabled
059{
060
061    private Map<String, Object> pluginContext;
062    
063    private final AntScriptInvoker scriptInvoker;
064
065    private Project antProject;
066
067    private MavenProject mavenProject;
068
069    private MojoExecution mojoExecution;
070
071    private MavenSession session;
072    
073    private PathTranslator pathTranslator;
074
075    private Logger logger;
076    
077    private transient List<String> unconstructedParts = new ArrayList<String>();
078
079    public AntMojoWrapper( AntScriptInvoker scriptInvoker )
080    {
081        this.scriptInvoker = scriptInvoker;
082    }
083
084    public void execute()
085        throws MojoExecutionException
086    {
087        if ( antProject == null )
088        {
089            antProject = scriptInvoker.getProject();
090        }
091        
092        Map<String, Object> allConfig = new HashMap<String, Object>();
093        if ( pluginContext != null && !pluginContext.isEmpty() )
094        {
095            allConfig.putAll( pluginContext );
096        }
097        
098        @SuppressWarnings( "unchecked" )
099        Map<String, PathTranslator> refs = scriptInvoker.getReferences();
100        if ( refs != null )
101        {
102            allConfig.putAll( refs );
103            
104            for ( Map.Entry<String, PathTranslator> entry : refs.entrySet() )
105            {
106                if ( entry.getKey().startsWith( PathTranslator.class.getName() ) )
107                {
108                    pathTranslator = entry.getValue();
109                }
110            }
111        }
112
113        mavenProject = (MavenProject) allConfig.get( "project" );
114        
115        mojoExecution = (MojoExecution) allConfig.get( "mojoExecution" );
116        
117        session = (MavenSession) allConfig.get( "session" );
118        
119        unpackFileBasedResources();
120
121        addClasspathReferences();
122        
123        if ( logger.isDebugEnabled() && !unconstructedParts.isEmpty() )
124        {
125            StringBuffer buffer = new StringBuffer();
126            
127            buffer.append( "The following standard Maven Ant-mojo support objects could not be created:\n\n" );
128            
129            for ( String part : unconstructedParts )
130            {
131                buffer.append( "\n-  " ).append( part );
132            }
133            
134            buffer.append( "\n\nMaven project, session, mojo-execution, or path-translation parameter information is " );
135            buffer.append( "\nmissing from this mojo's plugin descriptor." );
136            buffer.append( "\n\nPerhaps this Ant-based mojo depends on maven-script-ant < 2.1.0, " );
137            buffer.append( "or used maven-plugin-tools-ant < 2.2 during release?\n\n" );
138            
139            logger.debug( buffer.toString() );
140        }
141
142        try
143        {
144            scriptInvoker.invoke();
145        }
146        catch ( AntComponentExecutionException e )
147        {
148            throw new MojoExecutionException( "Failed to execute: " + e.getMessage(), e );
149        }
150        
151        unconstructedParts.clear();
152    }
153
154    public void setPluginContext( Map pluginContext )
155    {
156        this.pluginContext = pluginContext;
157    }
158
159    public Map getPluginContext()
160    {
161        return pluginContext;
162    }
163
164    public void addComponentRequirement( ComponentRequirement requirementDescriptor, Object requirementValue )
165        throws ComponentConfigurationException
166    {
167        scriptInvoker.addComponentRequirement( requirementDescriptor, requirementValue );
168    }
169
170    public void setComponentConfiguration( Map componentConfiguration )
171        throws ComponentConfigurationException
172    {
173        scriptInvoker.setComponentConfiguration( componentConfiguration );
174        antProject = scriptInvoker.getProject();
175    }
176
177    private void unpackFileBasedResources()
178        throws MojoExecutionException
179    {
180        if ( mojoExecution == null || mavenProject == null )
181        {
182            unconstructedParts.add( "Unpacked Ant build scripts (in Maven build directory)." );
183            
184            return;
185        }
186        
187        // What we need to write out any resources in the plugin to the target directory of the
188        // mavenProject using the Ant-based plugin:
189        //
190        // 1. Need a reference to the plugin JAR itself
191        // 2. Need a reference to the ${basedir} of the mavenProject
192
193        PluginDescriptor pluginDescriptor = mojoExecution.getMojoDescriptor().getPluginDescriptor();
194        
195        File pluginJar = pluginDescriptor.getPluginArtifact().getFile();
196
197        String resourcesPath = pluginDescriptor.getArtifactId();
198
199        File outputDirectory = new File( mavenProject.getBuild().getDirectory() );
200
201        try
202        {
203            UnArchiver ua = new ZipUnArchiver( pluginJar );
204
205            ua.extract( resourcesPath, outputDirectory );
206        }
207        catch ( ArchiverException e )
208        {
209            throw new MojoExecutionException( "Error extracting resources from your Ant-based plugin.", e );
210        }
211    }
212
213    private void addClasspathReferences()
214        throws MojoExecutionException
215    {
216        try
217        {
218            if ( mavenProject != null && session != null && pathTranslator != null )
219            {
220                ExpressionEvaluator exprEvaluator =
221                    new PluginParameterExpressionEvaluator( session, mojoExecution, pathTranslator, logger, mavenProject,
222                                                            mavenProject.getProperties() );
223                
224                PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper( antProject );
225                propertyHelper.setNext( new AntPropertyHelper( exprEvaluator, mavenProject.getArtifacts(), getLog() ) );
226            }
227            else
228            {
229                unconstructedParts.add( "Maven parameter expression evaluator for Ant properties." );
230            }
231
232            @SuppressWarnings( "unchecked" )
233            Map<String, Object> references = scriptInvoker.getReferences();
234
235            if ( mavenProject != null )
236            {
237
238                // Compile classpath
239                Path p = new Path( antProject );
240
241                p.setPath( StringUtils.join( mavenProject.getCompileClasspathElements().iterator(), File.pathSeparator ) );
242
243                /* maven.dependency.classpath it's deprecated as it's equal to maven.compile.classpath */
244                references.put( "maven.dependency.classpath", p );
245                antProject.addReference( "maven.dependency.classpath", p );
246                
247                references.put( "maven.compile.classpath", p );
248                antProject.addReference( "maven.compile.classpath", p );
249
250                // Runtime classpath
251                p = new Path( antProject );
252
253                p.setPath( StringUtils.join( mavenProject.getRuntimeClasspathElements().iterator(), File.pathSeparator ) );
254
255                references.put( "maven.runtime.classpath", p );
256                antProject.addReference( "maven.runtime.classpath", p );
257
258                // Test classpath
259                p = new Path( antProject );
260
261                p.setPath( StringUtils.join( mavenProject.getTestClasspathElements().iterator(), File.pathSeparator ) );
262
263                references.put( "maven.test.classpath", p );
264                antProject.addReference( "maven.test.classpath", p );
265
266            }
267            else
268            {
269                unconstructedParts.add( "Maven standard project-based classpath references." );
270            }
271            
272            if ( mojoExecution != null )
273            {
274                // Plugin dependency classpath
275
276                Path p = getPathFromArtifacts( mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifacts(), antProject );
277                
278                references.put( "maven.plugin.classpath", p );
279                antProject.addReference( "maven.plugin.classpath", p );
280            }
281            else
282            {
283                unconstructedParts.add( "Maven standard plugin-based classpath references." );
284            }
285        }
286        catch ( DependencyResolutionRequiredException e )
287        {
288            throw new MojoExecutionException( "Error creating classpath references for Ant-based plugin scripts.", e  );
289        }
290    }
291
292    public Path getPathFromArtifacts( Collection<Artifact> artifacts, Project antProject )
293        throws DependencyResolutionRequiredException
294    {
295        List<String> list = new ArrayList<String>( artifacts.size() );
296
297        for ( Artifact a : artifacts )
298        {
299            File file = a.getFile();
300
301            if ( file == null )
302            {
303                throw new DependencyResolutionRequiredException( a );
304            }
305
306            list.add( file.getPath() );
307        }
308
309        Path p = new Path( antProject );
310
311        p.setPath( StringUtils.join( list.iterator(), File.pathSeparator ) );
312
313        return p;
314    }
315
316    public Project getAntProject()
317    {
318        return antProject;
319    }
320
321    public void setAntProject( Project antProject )
322    {
323        this.antProject = antProject;
324    }
325
326    public MavenProject getMavenProject()
327    {
328        return mavenProject;
329    }
330
331    public void setMavenProject( MavenProject mavenProject )
332    {
333        this.mavenProject = mavenProject;
334    }
335
336    public MojoExecution getMojoExecution()
337    {
338        return mojoExecution;
339    }
340
341    public void setMojoExecution( MojoExecution mojoExecution )
342    {
343        this.mojoExecution = mojoExecution;
344    }
345
346    public MavenSession getSession()
347    {
348        return session;
349    }
350
351    public void setSession( MavenSession session )
352    {
353        this.session = session;
354    }
355
356    public PathTranslator getPathTranslator()
357    {
358        return pathTranslator;
359    }
360
361    public void setPathTranslator( PathTranslator pathTranslator )
362    {
363        this.pathTranslator = pathTranslator;
364    }
365
366    public AntScriptInvoker getScriptInvoker()
367    {
368        return scriptInvoker;
369    }
370
371    public void enableLogging( Logger logger )
372    {
373        this.logger = logger;
374    }
375}