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