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