1   package org.apache.maven.plugin.testing;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  import java.io.BufferedReader;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.Reader;
28  import java.lang.reflect.AccessibleObject;
29  import java.lang.reflect.Field;
30  import java.net.MalformedURLException;
31  import java.net.URL;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.HashMap;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.Properties;
38  
39  import org.apache.commons.io.input.XmlStreamReader;
40  import org.apache.maven.artifact.Artifact;
41  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
42  import org.apache.maven.execution.DefaultMavenExecutionRequest;
43  import org.apache.maven.execution.DefaultMavenExecutionResult;
44  import org.apache.maven.execution.MavenExecutionRequest;
45  import org.apache.maven.execution.MavenExecutionResult;
46  import org.apache.maven.execution.MavenSession;
47  import org.apache.maven.lifecycle.internal.MojoDescriptorCreator;
48  import org.apache.maven.model.Plugin;
49  import org.apache.maven.monitor.logging.DefaultLog;
50  import org.apache.maven.plugin.Mojo;
51  import org.apache.maven.plugin.MojoExecution;
52  import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
53  import org.apache.maven.plugin.descriptor.MojoDescriptor;
54  import org.apache.maven.plugin.descriptor.Parameter;
55  import org.apache.maven.plugin.descriptor.PluginDescriptor;
56  import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
57  import org.apache.maven.plugin.logging.Log;
58  import org.apache.maven.project.MavenProject;
59  import org.apache.maven.repository.RepositorySystem;
60  import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
61  import org.codehaus.plexus.ContainerConfiguration;
62  import org.codehaus.plexus.DefaultContainerConfiguration;
63  import org.codehaus.plexus.DefaultPlexusContainer;
64  import org.codehaus.plexus.PlexusConstants;
65  import org.codehaus.plexus.PlexusContainer;
66  import org.codehaus.plexus.PlexusContainerException;
67  import org.codehaus.plexus.PlexusTestCase;
68  import org.codehaus.plexus.classworlds.ClassWorld;
69  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
70  import org.codehaus.plexus.component.configurator.ComponentConfigurator;
71  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
72  import org.codehaus.plexus.component.repository.ComponentDescriptor;
73  import org.codehaus.plexus.configuration.PlexusConfiguration;
74  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
75  import org.codehaus.plexus.logging.LoggerManager;
76  import org.codehaus.plexus.util.IOUtil;
77  import org.codehaus.plexus.util.InterpolationFilterReader;
78  import org.codehaus.plexus.util.ReaderFactory;
79  import org.codehaus.plexus.util.ReflectionUtils;
80  import org.codehaus.plexus.util.StringUtils;
81  import org.codehaus.plexus.util.xml.Xpp3Dom;
82  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
83  
84  import com.google.inject.Module;
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  public abstract class AbstractMojoTestCase
100     extends PlexusTestCase
101 {
102     private static final DefaultArtifactVersion MAVEN_VERSION;
103 
104     static
105     {
106         DefaultArtifactVersion version = null;
107         String path = "/META-INF/maven/org.apache.maven/maven-core/pom.properties";
108         InputStream is = AbstractMojoTestCase.class.getResourceAsStream( path );
109         try
110         {
111             Properties properties = new Properties();
112             if ( is != null )
113             {
114                 properties.load( is );
115             }
116             String property = properties.getProperty( "version" );
117             if ( property != null )
118             {
119                 version = new DefaultArtifactVersion( property );
120             }
121         }
122         catch ( IOException e )
123         {
124             
125         }
126         finally
127         {
128             IOUtil.close( is );
129         }
130         MAVEN_VERSION = version;
131     }
132 
133     private ComponentConfigurator configurator;
134 
135     private PlexusContainer container;
136 
137     private Map<String, MojoDescriptor> mojoDescriptors;
138     
139     
140 
141 
142 
143 
144     
145 
146     protected void setUp()
147         throws Exception
148     {
149         assertTrue( "Maven 3.2.4 or better is required",
150                     MAVEN_VERSION == null || new DefaultArtifactVersion( "3.2.3" ).compareTo( MAVEN_VERSION ) < 0 );
151 
152         configurator = getContainer().lookup( ComponentConfigurator.class, "basic" );
153 
154         InputStream is = getClass().getResourceAsStream( "/" + getPluginDescriptorLocation() );
155 
156         XmlStreamReader reader = new XmlStreamReader( is );
157 
158         InterpolationFilterReader interpolationFilterReader =
159             new InterpolationFilterReader( new BufferedReader( reader ), container.getContext().getContextData() );
160 
161         PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build( interpolationFilterReader );
162 
163         Artifact artifact =
164             lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(),
165                                                              pluginDescriptor.getArtifactId(),
166                                                              pluginDescriptor.getVersion(), ".jar" );
167 
168         artifact.setFile( getPluginArtifactFile() );
169         pluginDescriptor.setPluginArtifact( artifact );
170         pluginDescriptor.setArtifacts( Arrays.asList( artifact ) );
171 
172         for ( ComponentDescriptor<?> desc : pluginDescriptor.getComponents() )
173         {
174             getContainer().addComponentDescriptor( desc );
175         }
176 
177         mojoDescriptors = new HashMap<String, MojoDescriptor>();
178         for ( MojoDescriptor mojoDescriptor : pluginDescriptor.getMojos() )
179         {
180             mojoDescriptors.put( mojoDescriptor.getGoal(), mojoDescriptor );
181         }
182     }
183 
184     
185 
186 
187 
188 
189 
190     private File getPluginArtifactFile()
191         throws IOException
192     {
193         final String pluginDescriptorLocation = getPluginDescriptorLocation();
194         final URL resource = getClass().getResource( "/" + pluginDescriptorLocation );
195 
196         File file = null;
197 
198         
199         if ( resource != null )
200         {
201             if ( "file".equalsIgnoreCase( resource.getProtocol() ) )
202             {
203                 String path = resource.getPath();
204                 if ( path.endsWith( pluginDescriptorLocation ) )
205                 {
206                     file = new File( path.substring( 0, path.length() - pluginDescriptorLocation.length() ) );
207                 }
208             }
209             else if ( "jar".equalsIgnoreCase( resource.getProtocol() ) )
210             {
211                 
212                 try
213                 {
214                     URL jarfile = new URL( resource.getPath() );
215                     if ( "file".equalsIgnoreCase( jarfile.getProtocol() ) )
216                     {
217                         String path = jarfile.getPath();
218                         if ( path.endsWith( pluginDescriptorLocation ) )
219                         {
220                             file =
221                                 new File( path.substring( 0, path.length() - pluginDescriptorLocation.length() - 2 ) );
222                         }
223                     }
224                 }
225                 catch ( MalformedURLException e )
226                 {
227                     
228                 }
229             }
230         }
231 
232         
233         if ( file == null || ! file.exists() )
234         {
235             file = new File( getBasedir() );
236         }
237 
238         return file.getCanonicalFile();
239     }
240 
241     protected InputStream getPublicDescriptorStream()
242         throws Exception
243     {
244         return new FileInputStream( new File( getPluginDescriptorPath() ) );
245     }
246 
247     protected String getPluginDescriptorPath()
248     {
249         return getBasedir() + "/target/classes/META-INF/maven/plugin.xml";
250     }
251 
252     protected String getPluginDescriptorLocation()
253     {
254         return "META-INF/maven/plugin.xml";
255     }
256 
257     protected void setupContainer()
258     {
259         ContainerConfiguration cc = setupContainerConfiguration();
260         try
261         {
262             List<Module> modules = new ArrayList<Module>();
263             addGuiceModules( modules );
264             container = new DefaultPlexusContainer( cc, modules.toArray( new Module[modules.size()] ) );
265         }
266         catch ( PlexusContainerException e )
267         {
268             e.printStackTrace();
269             fail( "Failed to create plexus container." );
270         }   
271     }
272 
273     
274 
275 
276     protected void addGuiceModules( List<Module> modules )
277     {
278         
279     }
280 
281     protected ContainerConfiguration setupContainerConfiguration()
282     {
283         ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
284 
285         ContainerConfiguration cc = new DefaultContainerConfiguration()
286           .setClassWorld( classWorld )
287           .setClassPathScanning( PlexusConstants.SCANNING_INDEX )
288           .setAutoWiring( true )
289           .setName( "maven" );      
290 
291         return cc;
292     }
293     
294     protected PlexusContainer getContainer()
295     {
296         if ( container == null )
297         {
298             setupContainer();
299         }
300 
301         return container;
302     }    
303     
304     
305 
306 
307 
308 
309 
310 
311 
312     protected Mojo lookupMojo( String goal, String pluginPom )
313         throws Exception
314     {
315         return lookupMojo( goal, new File( pluginPom ) );
316     }
317 
318     
319 
320 
321 
322 
323 
324 
325 
326     protected Mojo lookupEmptyMojo( String goal, String pluginPom )
327         throws Exception
328     {
329         return lookupEmptyMojo( goal, new File( pluginPom ) );
330     }
331 
332     
333 
334 
335 
336 
337 
338 
339 
340     protected Mojo lookupMojo( String goal, File pom )
341         throws Exception
342     {
343         File pluginPom = new File( getBasedir(), "pom.xml" );
344 
345         Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
346 
347         String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
348 
349         String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
350 
351         String version = resolveFromRootThenParent( pluginPomDom, "version" );
352 
353         PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
354 
355         return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
356     }
357 
358     
359 
360 
361 
362 
363 
364 
365 
366     protected Mojo lookupEmptyMojo( String goal, File pom )
367         throws Exception
368     {
369         File pluginPom = new File( getBasedir(), "pom.xml" );
370 
371         Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
372 
373         String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
374 
375         String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
376 
377         String version = resolveFromRootThenParent( pluginPomDom, "version" );
378 
379         return lookupMojo( groupId, artifactId, version, goal, null );
380     }
381 
382     
383 
384 
385 
386 
387 
388 
389 
390 
391     
392 
393 
394 
395 
396 
397 
398 
399 
400 
401 
402     protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal,
403                                PlexusConfiguration pluginConfiguration )
404         throws Exception
405     {
406         validateContainerStatus();
407 
408         
409 
410         Mojo mojo = (Mojo) lookup( Mojo.ROLE, groupId + ":" + artifactId + ":" + version + ":" + goal );
411 
412         LoggerManager loggerManager = (LoggerManager) getContainer().lookup( LoggerManager.class );
413         
414         Log mojoLogger = new DefaultLog( loggerManager.getLoggerForComponent( Mojo.ROLE ) );
415 
416         mojo.setLog( mojoLogger );
417 
418         if ( pluginConfiguration != null )
419         {
420             
421 
422 
423 
424             ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
425 
426             configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
427         }
428 
429         return mojo;
430     }
431 
432     
433 
434 
435 
436 
437 
438 
439 
440     protected Mojo lookupConfiguredMojo( MavenProject project, String goal )
441         throws Exception
442     {
443         return lookupConfiguredMojo( newMavenSession( project ), newMojoExecution( goal ) );
444     }
445 
446     
447 
448 
449 
450 
451 
452 
453 
454 
455     protected Mojo lookupConfiguredMojo( MavenSession session, MojoExecution execution )
456         throws Exception, ComponentConfigurationException
457     {
458         MavenProject project = session.getCurrentProject();
459         MojoDescriptor mojoDescriptor = execution.getMojoDescriptor();
460 
461         Mojo mojo = (Mojo) lookup( mojoDescriptor.getRole(), mojoDescriptor.getRoleHint() );
462 
463         ExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator( session, execution );
464 
465         Xpp3Dom configuration = null;
466         Plugin plugin = project.getPlugin( mojoDescriptor.getPluginDescriptor().getPluginLookupKey() );
467         if ( plugin != null )
468         {
469             configuration = (Xpp3Dom) plugin.getConfiguration();
470         }
471         if ( configuration == null )
472         {
473             configuration = new Xpp3Dom( "configuration" );
474         }
475         configuration = Xpp3Dom.mergeXpp3Dom( configuration, execution.getConfiguration() );
476 
477         PlexusConfiguration pluginConfiguration = new XmlPlexusConfiguration( configuration );
478 
479         if ( mojoDescriptor.getComponentConfigurator() != null )
480         {
481             configurator = getContainer().lookup( ComponentConfigurator.class, mojoDescriptor.getComponentConfigurator() );
482         }        
483         
484         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
485 
486         return mojo;
487     }
488 
489     
490 
491 
492 
493 
494 
495     protected MavenSession newMavenSession( MavenProject project )
496     {
497         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
498         MavenExecutionResult result = new DefaultMavenExecutionResult();
499 
500         MavenSession session = new MavenSession( container, MavenRepositorySystemUtils.newSession(), request, result );
501         session.setCurrentProject( project );
502         session.setProjects( Arrays.asList( project ) );
503         return session;
504     }
505 
506     
507 
508 
509 
510 
511 
512     protected MojoExecution newMojoExecution( String goal )
513     {
514         MojoDescriptor mojoDescriptor = mojoDescriptors.get( goal );
515         assertNotNull(String.format("The MojoDescriptor for the goal %s cannot be null.", goal),  mojoDescriptor );
516         MojoExecution execution = new MojoExecution( mojoDescriptor );
517         finalizeMojoConfiguration( execution );
518         return execution;
519     }
520 
521     
522     private void finalizeMojoConfiguration( MojoExecution mojoExecution )
523     {
524         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
525 
526         Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
527         if ( executionConfiguration == null )
528         {
529             executionConfiguration = new Xpp3Dom( "configuration" );
530         }
531 
532         Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert( mojoDescriptor );;
533 
534         Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
535 
536         if ( mojoDescriptor.getParameters() != null )
537         {
538             for ( Parameter parameter : mojoDescriptor.getParameters() )
539             {
540                 Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
541 
542                 if ( parameterConfiguration == null )
543                 {
544                     parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
545                 }
546 
547                 Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
548 
549                 parameterConfiguration = Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults, Boolean.TRUE );
550 
551                 if ( parameterConfiguration != null )
552                 {
553                     parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
554 
555                     if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
556                         && StringUtils.isNotEmpty( parameter.getImplementation() ) )
557                     {
558                         parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
559                     }
560 
561                     finalConfiguration.addChild( parameterConfiguration );
562                 }
563             }
564         }
565 
566         mojoExecution.setConfiguration( finalConfiguration );
567     }
568 
569     
570 
571 
572 
573 
574 
575     protected PlexusConfiguration extractPluginConfiguration( String artifactId, File pom )
576         throws Exception
577     {
578         Reader reader = ReaderFactory.newXmlReader( pom );
579 
580         Xpp3Dom pomDom = Xpp3DomBuilder.build( reader );
581 
582         return extractPluginConfiguration( artifactId, pomDom );
583     }
584 
585     
586 
587 
588 
589 
590 
591     protected PlexusConfiguration extractPluginConfiguration( String artifactId, Xpp3Dom pomDom )
592         throws Exception
593     {
594         Xpp3Dom pluginConfigurationElement = null;
595 
596         Xpp3Dom buildElement = pomDom.getChild( "build" );
597         if ( buildElement != null )
598         {
599             Xpp3Dom pluginsRootElement = buildElement.getChild( "plugins" );
600 
601             if ( pluginsRootElement != null )
602             {
603                 Xpp3Dom[] pluginElements = pluginsRootElement.getChildren();
604 
605                 for ( Xpp3Dom pluginElement : pluginElements )
606                 {
607                     String pluginElementArtifactId = pluginElement.getChild( "artifactId" ).getValue();
608 
609                     if ( pluginElementArtifactId.equals( artifactId ) )
610                     {
611                         pluginConfigurationElement = pluginElement.getChild( "configuration" );
612 
613                         break;
614                     }
615                 }
616 
617                 if ( pluginConfigurationElement == null )
618                 {
619                     throw new ConfigurationException( "Cannot find a configuration element for a plugin with an "
620                         + "artifactId of " + artifactId + "." );
621                 }
622             }
623         }
624 
625         if ( pluginConfigurationElement == null )
626         {
627             throw new ConfigurationException( "Cannot find a configuration element for a plugin with an artifactId of "
628                 + artifactId + "." );
629         }
630 
631         return new XmlPlexusConfiguration( pluginConfigurationElement );
632     }
633 
634     
635 
636 
637 
638 
639 
640 
641 
642 
643     protected Mojo configureMojo( Mojo mojo, String artifactId, File pom )
644         throws Exception
645     {
646         validateContainerStatus();
647 
648         PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
649 
650         ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
651 
652         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
653 
654         return mojo;
655     }
656 
657     
658 
659 
660 
661 
662 
663 
664 
665     protected Mojo configureMojo( Mojo mojo, PlexusConfiguration pluginConfiguration )
666         throws Exception
667     {
668         validateContainerStatus();
669 
670         ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
671 
672         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
673 
674         return mojo;
675     }
676 
677     
678 
679 
680 
681 
682 
683 
684 
685 
686 
687     protected Object getVariableValueFromObject( Object object, String variable )
688         throws IllegalAccessException
689     {
690         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
691 
692         field.setAccessible( true );
693 
694         return field.get( object );
695     }
696 
697     
698 
699 
700 
701 
702 
703 
704 
705     protected Map<String, Object> getVariablesAndValuesFromObject( Object object )
706         throws IllegalAccessException
707     {
708         return getVariablesAndValuesFromObject( object.getClass(), object );
709     }
710 
711     
712 
713 
714 
715 
716 
717 
718 
719 
720     protected Map<String, Object> getVariablesAndValuesFromObject( Class<?> clazz, Object object )
721         throws IllegalAccessException
722     {
723         Map<String, Object> map = new HashMap<String, Object>();
724 
725         Field[] fields = clazz.getDeclaredFields();
726 
727         AccessibleObject.setAccessible( fields, true );
728 
729         for ( Field field : fields )
730         {
731             map.put( field.getName(), field.get( object ) );
732         }
733 
734         Class<?> superclass = clazz.getSuperclass();
735 
736         if ( !Object.class.equals( superclass ) )
737         {
738             map.putAll( getVariablesAndValuesFromObject( superclass, object ) );
739         }
740 
741         return map;
742     }
743 
744     
745 
746 
747 
748 
749 
750 
751 
752     protected void setVariableValueToObject( Object object, String variable, Object value )
753         throws IllegalAccessException
754     {
755         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
756 
757         field.setAccessible( true );
758 
759         field.set( object, value );
760     }
761 
762     
763 
764 
765 
766 
767 
768 
769 
770 
771 
772     private String resolveFromRootThenParent( Xpp3Dom pluginPomDom, String element )
773         throws Exception
774     {
775         Xpp3Dom elementDom = pluginPomDom.getChild( element );
776 
777         
778         if ( elementDom == null )
779         {
780             Xpp3Dom pluginParentDom = pluginPomDom.getChild( "parent" );
781 
782             if ( pluginParentDom != null )
783             {
784                 elementDom = pluginParentDom.getChild( element );
785 
786                 if ( elementDom == null )
787                 {
788                     throw new Exception( "unable to determine " + element );
789                 }
790 
791                 return elementDom.getValue();
792             }
793 
794             throw new Exception( "unable to determine " + element );
795         }
796 
797         return elementDom.getValue();
798     }
799 
800     
801 
802 
803 
804 
805 
806 
807 
808     private void validateContainerStatus()
809         throws Exception
810     {
811         if ( getContainer() != null )
812         {
813             return;
814         }
815 
816         throw new Exception( "container is null, make sure super.setUp() is called" );
817     }    
818 }