View Javadoc
1   package org.apache.maven.plugin.testing;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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  
38  import org.apache.commons.io.input.XmlStreamReader;
39  import org.apache.maven.artifact.Artifact;
40  import org.apache.maven.execution.DefaultMavenExecutionRequest;
41  import org.apache.maven.execution.DefaultMavenExecutionResult;
42  import org.apache.maven.execution.MavenExecutionRequest;
43  import org.apache.maven.execution.MavenExecutionResult;
44  import org.apache.maven.execution.MavenSession;
45  import org.apache.maven.execution.scope.MojoExecutionScoped;
46  import org.apache.maven.execution.scope.internal.MojoExecutionScope;
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.InterpolationFilterReader;
77  import org.codehaus.plexus.util.ReaderFactory;
78  import org.codehaus.plexus.util.ReflectionUtils;
79  import org.codehaus.plexus.util.StringUtils;
80  import org.codehaus.plexus.util.xml.Xpp3Dom;
81  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
82  
83  import com.google.inject.AbstractModule;
84  import com.google.inject.Module;
85  
86  /**
87   * TODO: add a way to use the plugin POM for the lookup so that the user doesn't have to provide the a:g:v:goal
88   * as the role hint for the mojo lookup.
89   * TODO: standardize the execution of the mojo and looking at the results, but could simply have a template method
90   * for verifying the state of the mojo post execution
91   * TODO: need a way to look at the state of the mojo without adding getters, this could be where we finally specify
92   * the expressions which extract values from the mojo.
93   * TODO: create a standard directory structure for picking up POMs to make this even easier, we really just need a testing
94   * descriptor and make this entirely declarative!
95   *
96   * @author jesse
97   * @version $Id$
98   */
99  public abstract class AbstractMojoTestCase
100     extends PlexusTestCase
101 {
102     private ComponentConfigurator configurator;
103 
104     private PlexusContainer container;
105 
106     private Map<String, MojoDescriptor> mojoDescriptors;
107     
108     /*
109      * for the harness I think we have decided against going the route of using the maven project builder.
110      * instead I think we are going to try and make an instance of the localrespository and assign that
111      * to either the project stub or into the mojo directly with injection...not sure yet though.
112      */
113     //private MavenProjectBuilder projectBuilder;
114 
115     protected void setUp()
116         throws Exception
117     {
118         configurator = getContainer().lookup( ComponentConfigurator.class, "basic" );
119 
120         InputStream is = getClass().getResourceAsStream( "/" + getPluginDescriptorLocation() );
121 
122         XmlStreamReader reader = new XmlStreamReader( is );
123 
124         InterpolationFilterReader interpolationFilterReader =
125             new InterpolationFilterReader( new BufferedReader( reader ), container.getContext().getContextData() );
126 
127         PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build( interpolationFilterReader );
128 
129         Artifact artifact =
130             lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(),
131                                                              pluginDescriptor.getArtifactId(),
132                                                              pluginDescriptor.getVersion(), ".jar" );
133 
134         artifact.setFile( getPluginArtifactFile() );
135         pluginDescriptor.setPluginArtifact( artifact );
136         pluginDescriptor.setArtifacts( Arrays.asList( artifact ) );
137 
138         for ( ComponentDescriptor<?> desc : pluginDescriptor.getComponents() )
139         {
140             getContainer().addComponentDescriptor( desc );
141         }
142 
143         mojoDescriptors = new HashMap<String, MojoDescriptor>();
144         for ( MojoDescriptor mojoDescriptor : pluginDescriptor.getMojos() )
145         {
146             mojoDescriptors.put( mojoDescriptor.getGoal(), mojoDescriptor );
147         }
148     }
149 
150     /**
151      * Returns best-effort plugin artifact file.
152      * <p>
153      * First, attempts to determine parent directory of META-INF directory holding the plugin descriptor. If META-INF
154      * parent directory cannot be determined, falls back to test basedir.
155      */
156     private File getPluginArtifactFile()
157         throws IOException
158     {
159         final String pluginDescriptorLocation = getPluginDescriptorLocation();
160         final URL resource = getClass().getResource( "/" + pluginDescriptorLocation );
161 
162         File file = null;
163 
164         // attempt to resolve relative to META-INF/maven/plugin.xml first
165         if ( resource != null )
166         {
167             if ( "file".equalsIgnoreCase( resource.getProtocol() ) )
168             {
169                 String path = resource.getPath();
170                 if ( path.endsWith( pluginDescriptorLocation ) )
171                 {
172                     file = new File( path.substring( 0, path.length() - pluginDescriptorLocation.length() ) );
173                 }
174             }
175             else if ( "jar".equalsIgnoreCase( resource.getProtocol() ) )
176             {
177                 // TODO is there a helper for this somewhere?
178                 try
179                 {
180                     URL jarfile = new URL( resource.getPath() );
181                     if ( "file".equalsIgnoreCase( jarfile.getProtocol() ) )
182                     {
183                         String path = jarfile.getPath();
184                         if ( path.endsWith( pluginDescriptorLocation ) )
185                         {
186                             file =
187                                 new File( path.substring( 0, path.length() - pluginDescriptorLocation.length() - 2 ) );
188                         }
189                     }
190                 }
191                 catch ( MalformedURLException e )
192                 {
193                     // not jar:file:/ URL, too bad
194                 }
195             }
196         }
197 
198         // fallback to test project basedir if couldn't resolve relative to META-INF/maven/plugin.xml
199         if ( file == null || ! file.exists() )
200         {
201             file = new File( getBasedir() );
202         }
203 
204         return file.getCanonicalFile();
205     }
206 
207     protected InputStream getPublicDescriptorStream()
208         throws Exception
209     {
210         return new FileInputStream( new File( getPluginDescriptorPath() ) );
211     }
212 
213     protected String getPluginDescriptorPath()
214     {
215         return getBasedir() + "/target/classes/META-INF/maven/plugin.xml";
216     }
217 
218     protected String getPluginDescriptorLocation()
219     {
220         return "META-INF/maven/plugin.xml";
221     }
222 
223     protected void setupContainer()
224     {
225         ContainerConfiguration cc = setupContainerConfiguration();
226         try
227         {
228             List<Module> modules = new ArrayList<Module>();
229             modules.add( new AbstractModule()
230             {
231                 @Override
232                 protected void configure()
233                 {
234                     // execution scope bindings (core binds these in plugin realm injector only)
235                     MojoExecutionScope executionScope = new MojoExecutionScope();
236                     bindScope( MojoExecutionScoped.class, executionScope );
237                     bind( MojoExecutionScope.class ).toInstance( executionScope );
238                     bind( MavenProject.class ).toProvider( MojoExecutionScope.<MavenProject> seededKeyProvider() ).in( executionScope );
239                     bind( MojoExecution.class ).toProvider( MojoExecutionScope.<MojoExecution> seededKeyProvider() ).in( executionScope );
240                 }
241             } );
242             addGuiceModules( modules );
243             container = new DefaultPlexusContainer( cc, modules.toArray( new Module[modules.size()] ) );
244         }
245         catch ( PlexusContainerException e )
246         {
247             e.printStackTrace();
248             fail( "Failed to create plexus container." );
249         }   
250     }
251 
252     /**
253      * @since 3.0.0
254      */
255     protected void addGuiceModules( List<Module> modules )
256     {
257         // no custom guice modules by default
258     }
259 
260     protected ContainerConfiguration setupContainerConfiguration()
261     {
262         ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
263 
264         ContainerConfiguration cc = new DefaultContainerConfiguration()
265           .setClassWorld( classWorld )
266           .setClassPathScanning( PlexusConstants.SCANNING_INDEX )
267           .setAutoWiring( true )
268           .setName( "maven" );      
269 
270         return cc;
271     }
272     
273     protected PlexusContainer getContainer()
274     {
275         if ( container == null )
276         {
277             setupContainer();
278         }
279 
280         return container;
281     }    
282     
283     /**
284      * Lookup the mojo leveraging the subproject pom
285      *
286      * @param goal
287      * @param pluginPom
288      * @return a Mojo instance
289      * @throws Exception
290      */
291     protected Mojo lookupMojo( String goal, String pluginPom )
292         throws Exception
293     {
294         return lookupMojo( goal, new File( pluginPom ) );
295     }
296 
297     /**
298      * Lookup an empty mojo
299      *
300      * @param goal
301      * @param pluginPom
302      * @return a Mojo instance
303      * @throws Exception
304      */
305     protected Mojo lookupEmptyMojo( String goal, String pluginPom )
306         throws Exception
307     {
308         return lookupEmptyMojo( goal, new File( pluginPom ) );
309     }
310 
311     /**
312      * Lookup the mojo leveraging the actual subprojects pom
313      *
314      * @param goal
315      * @param pom
316      * @return a Mojo instance
317      * @throws Exception
318      */
319     protected Mojo lookupMojo( String goal, File pom )
320         throws Exception
321     {
322         File pluginPom = new File( getBasedir(), "pom.xml" );
323 
324         Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
325 
326         String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
327 
328         String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
329 
330         String version = resolveFromRootThenParent( pluginPomDom, "version" );
331 
332         PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
333 
334         return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
335     }
336 
337     /**
338      * Lookup the mojo leveraging the actual subprojects pom
339      *
340      * @param goal
341      * @param pom
342      * @return a Mojo instance
343      * @throws Exception
344      */
345     protected Mojo lookupEmptyMojo( String goal, File pom )
346         throws Exception
347     {
348         File pluginPom = new File( getBasedir(), "pom.xml" );
349 
350         Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
351 
352         String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
353 
354         String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
355 
356         String version = resolveFromRootThenParent( pluginPomDom, "version" );
357 
358         return lookupMojo( groupId, artifactId, version, goal, null );
359     }
360 
361     /*
362      protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal, File pom )
363      throws Exception
364      {
365      PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
366 
367      return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
368      }
369      */
370     /**
371      * lookup the mojo while we have all of the relavent information
372      *
373      * @param groupId
374      * @param artifactId
375      * @param version
376      * @param goal
377      * @param pluginConfiguration
378      * @return a Mojo instance
379      * @throws Exception
380      */
381     protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal,
382                                PlexusConfiguration pluginConfiguration )
383         throws Exception
384     {
385         validateContainerStatus();
386 
387         // pluginkey = groupId : artifactId : version : goal
388 
389         Mojo mojo = (Mojo) lookup( Mojo.ROLE, groupId + ":" + artifactId + ":" + version + ":" + goal );
390 
391         LoggerManager loggerManager = (LoggerManager) getContainer().lookup( LoggerManager.class );
392         
393         Log mojoLogger = new DefaultLog( loggerManager.getLoggerForComponent( Mojo.ROLE ) );
394 
395         mojo.setLog( mojoLogger );
396 
397         if ( pluginConfiguration != null )
398         {
399             /* requires v10 of plexus container for lookup on expression evaluator
400              ExpressionEvaluator evaluator = (ExpressionEvaluator) getContainer().lookup( ExpressionEvaluator.ROLE,
401                                                                                          "stub-evaluator" );
402              */
403             ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
404 
405             configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
406         }
407 
408         return mojo;
409     }
410 
411     /**
412      * 
413      * @param project
414      * @param goal
415      * @return
416      * @throws Exception
417      * @since 2.0
418      */
419     protected Mojo lookupConfiguredMojo( MavenProject project, String goal )
420         throws Exception
421     {
422         return lookupConfiguredMojo( newMavenSession( project ), newMojoExecution( goal ) );
423     }
424 
425     /**
426      * 
427      * @param session
428      * @param execution
429      * @return
430      * @throws Exception
431      * @throws ComponentConfigurationException
432      * @since 2.0
433      */
434     protected Mojo lookupConfiguredMojo( MavenSession session, MojoExecution execution )
435         throws Exception, ComponentConfigurationException
436     {
437         MavenProject project = session.getCurrentProject();
438         MojoDescriptor mojoDescriptor = execution.getMojoDescriptor();
439 
440         Mojo mojo = (Mojo) lookup( mojoDescriptor.getRole(), mojoDescriptor.getRoleHint() );
441 
442         ExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator( session, execution );
443 
444         Xpp3Dom configuration = null;
445         Plugin plugin = project.getPlugin( mojoDescriptor.getPluginDescriptor().getPluginLookupKey() );
446         if ( plugin != null )
447         {
448             configuration = (Xpp3Dom) plugin.getConfiguration();
449         }
450         if ( configuration == null )
451         {
452             configuration = new Xpp3Dom( "configuration" );
453         }
454         configuration = Xpp3Dom.mergeXpp3Dom( configuration, execution.getConfiguration() );
455 
456         PlexusConfiguration pluginConfiguration = new XmlPlexusConfiguration( configuration );
457 
458         if ( mojoDescriptor.getComponentConfigurator() != null )
459         {
460             configurator = getContainer().lookup( ComponentConfigurator.class, mojoDescriptor.getComponentConfigurator() );
461         }        
462         
463         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
464 
465         return mojo;
466     }
467 
468     /**
469      * 
470      * @param project
471      * @return
472      * @since 2.0
473      */
474     protected MavenSession newMavenSession( MavenProject project )
475     {
476         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
477         MavenExecutionResult result = new DefaultMavenExecutionResult();
478 
479         MavenSession session = new MavenSession( container, MavenRepositorySystemUtils.newSession(), request, result );
480         session.setCurrentProject( project );
481         session.setProjects( Arrays.asList( project ) );
482         return session;
483     }
484 
485     /**
486      * 
487      * @param goal
488      * @return
489      * @since 2.0
490      */
491     protected MojoExecution newMojoExecution( String goal )
492     {
493         MojoDescriptor mojoDescriptor = mojoDescriptors.get( goal );
494         assertNotNull(String.format("The MojoDescriptor for the goal %s cannot be null.", goal),  mojoDescriptor );
495         MojoExecution execution = new MojoExecution( mojoDescriptor );
496         finalizeMojoConfiguration( execution );
497         return execution;
498     }
499 
500     // copy&paste from org.apache.maven.lifecycle.internal.DefaultLifecycleExecutionPlanCalculator.finalizeMojoConfiguration(MojoExecution)
501     private void finalizeMojoConfiguration( MojoExecution mojoExecution )
502     {
503         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
504 
505         Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
506         if ( executionConfiguration == null )
507         {
508             executionConfiguration = new Xpp3Dom( "configuration" );
509         }
510 
511         Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert( mojoDescriptor );;
512 
513         Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
514 
515         if ( mojoDescriptor.getParameters() != null )
516         {
517             for ( Parameter parameter : mojoDescriptor.getParameters() )
518             {
519                 Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
520 
521                 if ( parameterConfiguration == null )
522                 {
523                     parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
524                 }
525 
526                 Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
527 
528                 parameterConfiguration = Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults, Boolean.TRUE );
529 
530                 if ( parameterConfiguration != null )
531                 {
532                     parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
533 
534                     if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
535                         && StringUtils.isNotEmpty( parameter.getImplementation() ) )
536                     {
537                         parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
538                     }
539 
540                     finalConfiguration.addChild( parameterConfiguration );
541                 }
542             }
543         }
544 
545         mojoExecution.setConfiguration( finalConfiguration );
546     }
547 
548     /**
549      * @param artifactId
550      * @param pom
551      * @return the plexus configuration
552      * @throws Exception
553      */
554     protected PlexusConfiguration extractPluginConfiguration( String artifactId, File pom )
555         throws Exception
556     {
557         Reader reader = ReaderFactory.newXmlReader( pom );
558 
559         Xpp3Dom pomDom = Xpp3DomBuilder.build( reader );
560 
561         return extractPluginConfiguration( artifactId, pomDom );
562     }
563 
564     /**
565      * @param artifactId
566      * @param pomDom
567      * @return the plexus configuration
568      * @throws Exception
569      */
570     protected PlexusConfiguration extractPluginConfiguration( String artifactId, Xpp3Dom pomDom )
571         throws Exception
572     {
573         Xpp3Dom pluginConfigurationElement = null;
574 
575         Xpp3Dom buildElement = pomDom.getChild( "build" );
576         if ( buildElement != null )
577         {
578             Xpp3Dom pluginsRootElement = buildElement.getChild( "plugins" );
579 
580             if ( pluginsRootElement != null )
581             {
582                 Xpp3Dom[] pluginElements = pluginsRootElement.getChildren();
583 
584                 for ( Xpp3Dom pluginElement : pluginElements )
585                 {
586                     String pluginElementArtifactId = pluginElement.getChild( "artifactId" ).getValue();
587 
588                     if ( pluginElementArtifactId.equals( artifactId ) )
589                     {
590                         pluginConfigurationElement = pluginElement.getChild( "configuration" );
591 
592                         break;
593                     }
594                 }
595 
596                 if ( pluginConfigurationElement == null )
597                 {
598                     throw new ConfigurationException( "Cannot find a configuration element for a plugin with an "
599                         + "artifactId of " + artifactId + "." );
600                 }
601             }
602         }
603 
604         if ( pluginConfigurationElement == null )
605         {
606             throw new ConfigurationException( "Cannot find a configuration element for a plugin with an artifactId of "
607                 + artifactId + "." );
608         }
609 
610         return new XmlPlexusConfiguration( pluginConfigurationElement );
611     }
612 
613     /**
614      * Configure the mojo
615      *
616      * @param mojo
617      * @param artifactId
618      * @param pom
619      * @return a Mojo instance
620      * @throws Exception
621      */
622     protected Mojo configureMojo( Mojo mojo, String artifactId, File pom )
623         throws Exception
624     {
625         validateContainerStatus();
626 
627         PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
628 
629         ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
630 
631         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
632 
633         return mojo;
634     }
635 
636     /**
637      * Configure the mojo with the given plexus configuration
638      *
639      * @param mojo
640      * @param pluginConfiguration
641      * @return a Mojo instance
642      * @throws Exception
643      */
644     protected Mojo configureMojo( Mojo mojo, PlexusConfiguration pluginConfiguration )
645         throws Exception
646     {
647         validateContainerStatus();
648 
649         ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
650 
651         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
652 
653         return mojo;
654     }
655 
656     /**
657      * Convenience method to obtain the value of a variable on a mojo that might not have a getter.
658      *
659      * NOTE: the caller is responsible for casting to to what the desired type is.
660      *
661      * @param object
662      * @param variable
663      * @return object value of variable
664      * @throws IllegalArgumentException
665      */
666     protected Object getVariableValueFromObject( Object object, String variable )
667         throws IllegalAccessException
668     {
669         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
670 
671         field.setAccessible( true );
672 
673         return field.get( object );
674     }
675 
676     /**
677      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
678      *
679      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
680      *
681      * @param object
682      * @return map of variable names and values
683      */
684     protected Map<String, Object> getVariablesAndValuesFromObject( Object object )
685         throws IllegalAccessException
686     {
687         return getVariablesAndValuesFromObject( object.getClass(), object );
688     }
689 
690     /**
691      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
692      *
693      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
694      *
695      * @param clazz
696      * @param object
697      * @return map of variable names and values
698      */
699     protected Map<String, Object> getVariablesAndValuesFromObject( Class<?> clazz, Object object )
700         throws IllegalAccessException
701     {
702         Map<String, Object> map = new HashMap<String, Object>();
703 
704         Field[] fields = clazz.getDeclaredFields();
705 
706         AccessibleObject.setAccessible( fields, true );
707 
708         for ( Field field : fields )
709         {
710             map.put( field.getName(), field.get( object ) );
711         }
712 
713         Class<?> superclass = clazz.getSuperclass();
714 
715         if ( !Object.class.equals( superclass ) )
716         {
717             map.putAll( getVariablesAndValuesFromObject( superclass, object ) );
718         }
719 
720         return map;
721     }
722 
723     /**
724      * Convenience method to set values to variables in objects that don't have setters
725      *
726      * @param object
727      * @param variable
728      * @param value
729      * @throws IllegalAccessException
730      */
731     protected void setVariableValueToObject( Object object, String variable, Object value )
732         throws IllegalAccessException
733     {
734         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
735 
736         field.setAccessible( true );
737 
738         field.set( object, value );
739     }
740 
741     /**
742      * sometimes the parent element might contain the correct value so generalize that access
743      *
744      * TODO find out where this is probably done elsewhere
745      *
746      * @param pluginPomDom
747      * @param element
748      * @return
749      * @throws Exception
750      */
751     private String resolveFromRootThenParent( Xpp3Dom pluginPomDom, String element )
752         throws Exception
753     {
754         Xpp3Dom elementDom = pluginPomDom.getChild( element );
755 
756         // parent might have the group Id so resolve it
757         if ( elementDom == null )
758         {
759             Xpp3Dom pluginParentDom = pluginPomDom.getChild( "parent" );
760 
761             if ( pluginParentDom != null )
762             {
763                 elementDom = pluginParentDom.getChild( element );
764 
765                 if ( elementDom == null )
766                 {
767                     throw new Exception( "unable to determine " + element );
768                 }
769 
770                 return elementDom.getValue();
771             }
772 
773             throw new Exception( "unable to determine " + element );
774         }
775 
776         return elementDom.getValue();
777     }
778 
779     /**
780      * We should make sure this is called in each method that makes use of the container,
781      * otherwise we throw ugly NPE's
782      *
783      * crops up when the subclassing code defines the setUp method but doesn't call super.setUp()
784      *
785      * @throws Exception
786      */
787     private void validateContainerStatus()
788         throws Exception
789     {
790         if ( getContainer() != null )
791         {
792             return;
793         }
794 
795         throw new Exception( "container is null, make sure super.setUp() is called" );
796     }    
797 }