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