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