View Javadoc

1   package org.codehaus.mojo.fitnesse;
2   
3   /*
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, version 2.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU General Public License for more details.
12   *
13   * You should have received a copy of the GNU General Public License
14   * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
15   */
16  
17  import java.io.File;
18  import java.io.FileInputStream;
19  import java.io.FileNotFoundException;
20  import java.io.FileWriter;
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Set;
27  import java.util.StringTokenizer;
28  import java.util.logging.Level;
29  
30  import org.apache.maven.artifact.Artifact;
31  import org.apache.maven.artifact.factory.ArtifactFactory;
32  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
33  import org.apache.maven.artifact.repository.ArtifactRepository;
34  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
35  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
36  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
37  import org.apache.maven.artifact.resolver.ArtifactResolver;
38  import org.apache.maven.plugin.MojoExecutionException;
39  import org.apache.maven.plugin.MojoFailureException;
40  import org.apache.maven.project.MavenProject;
41  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
42  import org.apache.maven.project.artifact.MavenMetadataSource;
43  import org.apache.maven.reporting.MavenReportException;
44  import org.codehaus.mojo.fitnesse.log.FileConsumer;
45  import org.codehaus.mojo.fitnesse.log.FitnesseStreamConsumer;
46  import org.codehaus.mojo.fitnesse.log.LogConsumer;
47  import org.codehaus.mojo.fitnesse.log.MultipleConsumer;
48  import org.codehaus.mojo.fitnesse.plexus.FCommandLineException;
49  import org.codehaus.mojo.fitnesse.plexus.FCommandLineUtils;
50  import org.codehaus.mojo.fitnesse.plexus.FCommandline;
51  import org.codehaus.mojo.fitnesse.runner.ClassPathBuilder;
52  
53  /**
54   * This goal uses the <code>fitnesse.runner.TestRunner</code> class for calling a remote FitNesse web page and
55   * executes the <i>tests</i> or <i>suites</i> locally into a forked JVM. It's possible to define several pages and/or
56   * servers.
57   * 
58   * @goal run
59   * @requiresDependencyResolution runtime
60   * @aggregator
61   */
62  public class FitnesseRunnerMojo
63      extends FitnesseAbstractMojo
64  {
65      /**
66       * This property defines how the plugin will create the classpath for running fixtures. It accepts a couple of
67       * value: "fitnesse" (default) or "maven".<BR/> With "fitnesse" mode, the classpath is downloaded from the FitNesse
68       * server page. Then classpath of the plugin is appended (for providing the good FitNesse implementation).<BR/>
69       * With "maven" mode the classpath is only defined with the one of the project (POM).
70       * 
71       * @parameter default-value="fitnesse"
72       */
73      private String classPathProvider;
74  
75      /**
76       * @component
77       * @readonly
78       */
79      private ArtifactMetadataSource metadataSource;
80  
81      /**
82       * @parameter expression="${project.remoteArtifactRepositories}"
83       * @readonly
84       */
85      private List remoteRepositories;
86  
87      /**
88       * The Maven project instance for the executing project.
89       * <p>
90       * Note: This is passed by Maven and must not be configured by the user.
91       * </p>
92       * 
93       * @parameter expression="${project}"
94       * @readonly
95       * @required
96       */
97      private MavenProject project;
98  
99      /**
100      * Use shorter classpath. On Windows, the Win32 api doesn't allow to create a process via CMD.EXE that contains more
101      * than 8192 chars. When fitnesse-maven-plugin calls the page, the classpath that refers to the maven repository may
102      * easilly contains more than 8192 chars. <a
103      * href="http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx">see article</a> Activating this property
104      * ask the plugin to copy all the dependency in the target folder. This may create an overhead but decrease the
105      * classpath size. For exemple the string
106      * [E:/Maven/repository/org/springframework/spring-beans/1.2.8/spring-beans-1.2.8.jar] (81 chars) became
107      * [lib/spring-beans-1.2.8.jar] (26 chars). That doesn't solve the problems but allows to use bigger classpath.
108      * 
109      * @parameter default-value="false"
110      */
111     boolean copyDependencies;
112 
113     /**
114      * List of all artifacts for this plugin provided by Maven. This is used internally to get the FitnesseRunner.
115      * <p>
116      * Note: This is passed by Maven and must not be configured by the user.
117      * </p>
118      * 
119      * @parameter expression="${plugin.artifacts}"
120      * @readonly
121      * @required
122      */
123     private List pluginArtifacts;
124 
125     /**
126      * The set of dependencies required by the project
127      * 
128      * @parameter default-value="${project.dependencies}"
129      * @required
130      * @readonly
131      */
132     private java.util.List dependencies;
133 
134     /**
135      * @parameter expression="${component.org.apache.maven.artifact.factory.ArtifactFactory}"
136      * @required
137      * @readonly
138      */
139     private ArtifactFactory artifactFactory;
140 
141     /**
142      * Artifact resolver used to find clovered artifacts (artifacts with a clover classifier).
143      * 
144      * @component role="org.apache.maven.artifact.resolver.ArtifactResolver"
145      * @required
146      * @readonly
147      */
148     private ArtifactResolver artifactResolver;
149 
150     /**
151      * Local maven repository.
152      * 
153      * @parameter expression="${localRepository}"
154      * @required
155      * @readonly
156      */
157     private ArtifactRepository localRepository;
158 
159     /**
160      * @parameter expression="${plugin.artifactId}"
161      * @required
162      * @readonly
163      */
164     private String pluginArtifactId;
165 
166     /**
167      * @parameter expression="${plugin.groupId}"
168      * @required
169      * @readonly
170      */
171     private String pluginGroupId;
172 
173     /**
174      * @parameter expression="${plugin.version}"
175      * @required
176      * @readonly
177      */
178     private String pluginVersion;
179 
180     /**
181      * Java executable.
182      * 
183      * @parameter default-value="java"
184      */
185     private String jdk;
186 
187     /**
188      * Jvm arguments.
189      * 
190      * @parameter default-value=""
191      */
192     private String jdkOpts;
193 
194     /**
195      * Redirect FitNesse output into Maven2 log.
196      * 
197      * @parameter default-value=false
198      */
199     private boolean displayOutput;
200 
201     /**
202      * Run FitnesseRunner with debug option.
203      * 
204      * @parameter default-value="false"
205      */
206     private boolean debug;
207 
208     /**
209      * Fitnesse runner class.
210      * 
211      * @parameter default-value="fitnesse.runner.TestRunner"
212      */
213     private String fitnesseRunnerClass;
214 
215     /**
216      * List of Classpath substitution. Substitutions allow to change the FitNesse class path.<BR/> It should be usefull
217      * when the server classpath is in a Unix syntaxe, or when libs are not located in the same folder on the server and
218      * on the developer desktop.<BR/> The order of substitutions is guaranteed to be the same than the definition.
219      * <BR/> The substitutions use String replacements (not patterns). <code>
220      * &lt;classPathSubstitutions&gt;<BR/>
221      * &#160;&#160;&lt;classPathSubstitution&gt;<BR/>
222      * &#160;&#160;&#160;&#160;&lt;search&gt;The key that will be replace&lt;/search&gt;<BR/>
223      * &#160;&#160;&#160;&#160;&lt;replaceWith&gt;The value that should use to replace the key&lt;/replaceWith&gt;<BR/>
224      * &#160;&#160;&lt;/classPathSubstitution&gt;<BR/>
225      * &#160;&#160;... <BR/>
226      * &lt;/classPathSubstitutions&gt;:<BR/>
227      * </code>
228      * This parameter can only be use if param <i>classPathProvider</i> has <i>fitnesse</i> value.
229      * 
230      * @parameter
231      */
232     private List classPathSubstitutions = new ArrayList();
233 
234     /**
235      * Command for the execution of the FitRunner
236      */
237     private FCommandline mCmd = new FCommandline();
238 
239     /** Technical Maven resources. */
240     private Artifact pluginArtifact;
241 
242     /**
243      * Main Mojo method.
244      * 
245      * @throws MojoExecutionException If the method can't be executed.
246      * @throws MojoFailureException If there is fitnesse tests failures.
247      */
248     public void execute()
249         throws MojoExecutionException, MojoFailureException
250     {
251         new File( this.workingDir ).mkdirs();
252         checkConfiguration();
253 
254         try
255         {
256             FitnesseReportMojo.copyAllResources( new File( this.workingDir ), getLog(), getClass().getClassLoader() );
257         }
258         catch ( MavenReportException e )
259         {
260             throw new MojoExecutionException( "Unable to copy resources", e.getCause() );
261         }
262 
263         getLog().info( "Found " + getFitnesseSize() + " Fitnesse configuration." );
264         for ( int i = 0; i < getFitnesseSize(); i++ )
265         {
266             Fitnesse tServer = getFitnesse( i );
267             callFitnesse( tServer );
268             transformResultPage( tServer );
269         }
270     }
271 
272     /*******************************************************************************************************************
273      * Change the fitnesse result page to a Maven site format.
274      * 
275      * @param pServer FitNesse server configuration.
276      * @throws MojoExecutionException If the result page can't be found.
277      */
278     void transformResultPage( Fitnesse pServer )
279         throws MojoExecutionException
280     {
281         FileInputStream tIn = null;
282         try
283         {
284             String tSrcFile = getTmpFileName( pServer );
285             tIn = new FileInputStream( tSrcFile );
286             File tDestFile = new File( getFinalFileName( pServer ) );
287             if ( tDestFile.exists() )
288             {
289                 tDestFile.delete();
290             }
291             FileWriter tWriter = new FileWriter( tDestFile );
292             FitnessePage tResult = new FitnessePage( new File( tSrcFile ) );
293             transformHtml( tIn, tWriter, getOutputUrl( pServer ), tResult.getStatus() );
294             tIn.close();
295             tIn = null;
296             if ( !new File( tSrcFile ).delete() )
297             {
298                 getLog().error( "Unable to delete tmp file [" + tSrcFile + "]" );
299             }
300         }
301         catch ( FileNotFoundException e )
302         {
303             throw new MojoExecutionException( "Unable to tranform html", e );
304         }
305         catch ( IOException e )
306         {
307             throw new MojoExecutionException( "Unable to tranform html", e );
308         }
309         finally
310         {
311             if ( tIn != null )
312             {
313                 try
314                 {
315                     tIn.close();
316                 }
317                 catch ( IOException e )
318                 {
319                     throw new MojoExecutionException( "Unable to close tmp file stream", e );
320                 }
321             }
322         }
323 
324     }
325 
326     /**
327      * Get the classpath to use for running the fitnesse tests. The classpath is found using the fitnesse
328      * <code>path</code> property or using Maven dependancies, according to the POM configuration. The classpath is
329      * adapted to the local server configuration depending on the local folders.
330      * 
331      * @param tServer The FitNesse configuration.
332      * @return The ClassPath to use.
333      * @throws MojoExecutionException If the classpath can't be found.
334      */
335     private String getClassPath( Fitnesse tServer )
336         throws MojoExecutionException
337     {
338         String tResult;
339         if ( "fitnesse".equals( classPathProvider ) )
340         {
341             StringBuffer tBuffer = new StringBuffer();
342             ClassPathBuilder tBuilder =
343                 new ClassPathBuilder( tServer.getHostName(), tServer.getPort(), tServer.getPageName(), getLog() );
344             tBuffer.append( tBuilder.getPath( classPathSubstitutions, getLog() ) );
345             Artifact curArt;
346             for ( Iterator tIt = pluginArtifacts.iterator(); tIt.hasNext(); )
347             {
348                 curArt = (Artifact) tIt.next();
349                 if ( !curArt.getScope().equals( Artifact.SCOPE_PROVIDED )
350                     && !curArt.getScope().equals( Artifact.SCOPE_TEST ) )
351                 {
352                     tBuffer.append( File.pathSeparatorChar ).append( curArt.getFile().getAbsolutePath() );
353                 }
354             }
355             tBuffer.append( File.pathSeparatorChar ).append( resolvePlugin().getFile().getAbsolutePath() );
356             getLog().info( "Try to download classpath from FitNesse server..." );
357             tResult = tBuffer.toString();
358         }
359         else
360         {
361             tResult = getMavenClassPath();
362         }
363         if ( copyDependencies )
364         {
365             tResult = copyDependenciesLocally( tResult );
366         }
367 
368         return tResult;
369     }
370 
371     /**
372      * Copy all the jar in a local folder. That allows to have a lot of dependencies on a Windows plateform. On Windows
373      * the Command Line can't be longer than 8192 character. With that mecanism, the local path are shorter than the
374      * full one. For example: "lib/myJar-1.0.jar" is shorter than "d:\maven\repo\com\myCompany\myJar\1.0\myJar-1.0.jar".
375      * The method copy the jar and compute the new classpath using these local jars.
376      * 
377      * @param pClasspath The absolute classpath provided by Maven or FitNesse.
378      * @return The new local classpath.
379      * @throws MojoExecutionException If the classpath can't be found.
380      */
381     String copyDependenciesLocally( String pClasspath )
382         throws MojoExecutionException
383     {
384         String tPathSep = System.getProperty( "path.separator" );
385         String tFileSep = System.getProperty( "file.separator" );
386         File tFolder = new File( workingDir + tFileSep + "lib" );
387         if ( !tFolder.exists() )
388         {
389             tFolder.mkdirs();
390         }
391         StringTokenizer tToken = new StringTokenizer( pClasspath, tPathSep );
392         String tFileName, tShortFileName;
393         File tFile;
394         FileInputStream tFileInput;
395         StringBuffer tBuffer = new StringBuffer();
396         File tResultFile;
397         try
398         {
399             while ( tToken.hasMoreTokens() )
400             {
401                 tFileName = tToken.nextToken();
402                 tFile = new File( tFileName );
403                 if ( tFile.exists() )
404                 {
405                     tFileInput = new FileInputStream( tFile );
406                     int tIndex = tFileName.lastIndexOf( tFileSep );
407                     tShortFileName = tFileName.substring( tIndex + 1 );
408                     tResultFile = new File( workingDir + tFileSep + "lib" + tFileSep + tShortFileName );
409                     FitnesseReportMojo.copyFile( getLog(), tFileInput, tResultFile );
410                     tBuffer.append( "lib" + tFileSep + tShortFileName + tPathSep );
411                 }
412                 else
413                 {
414                     getLog().warn( "Unable to find the file [" + tFileName + "], skipping this file" );
415                 }
416             }
417         }
418         catch ( FileNotFoundException e )
419         {
420             throw new MojoExecutionException( "File not found", e );
421         }
422         catch ( MavenReportException e )
423         {
424             throw new MojoExecutionException( "File not found", e );
425         }
426         return tBuffer.toString();
427     }
428 
429     /**
430      * Get the Maven classpath using the POM dependencies.
431      * 
432      * @return The classpath.
433      * @throws MojoExecutionException If the classpath can't be found.
434      */
435     String getMavenClassPath()
436         throws MojoExecutionException
437     {
438         getLog().error( "PKE MavenClassPath" );
439         StringBuffer tBuffer = new StringBuffer();
440         Set tArtifacts = transitivelyResolvePomDependencies();
441         if ( tArtifacts != null && !tArtifacts.isEmpty() )
442         {
443             for ( Iterator it = tArtifacts.iterator(); it.hasNext(); )
444             {
445                 Artifact curArtififact = (Artifact) it.next();
446                 tBuffer.append( curArtififact.getFile().getAbsolutePath() ).append( File.pathSeparatorChar );
447             }
448         }
449 
450         tBuffer.append( project.getBuild().getOutputDirectory() ).append( File.pathSeparatorChar );
451         tBuffer.append( project.getBuild().getTestOutputDirectory() ).append( File.pathSeparatorChar );
452         getLog().error( "PKE " + tBuffer );
453         return tBuffer.toString();
454     }
455 
456     /**
457      * Create the transitive classpath.
458      * 
459      * @return The dependent artifacts.
460      * @throws MojoExecutionException If the classpath can't be found.
461      */
462     public Set transitivelyResolvePomDependencies()
463         throws MojoExecutionException
464     {
465         // make Artifacts of all the dependencies
466         Set dependencyArtifacts;
467         try
468         {
469             dependencyArtifacts = MavenMetadataSource.createArtifacts( artifactFactory, dependencies, null, null, null );
470         }
471         catch ( InvalidDependencyVersionException e )
472         {
473             throw new MojoExecutionException( "Invalid dependency", e );
474         }
475 
476         // not forgetting the Artifact of the project itself
477         dependencyArtifacts.add( project.getArtifact() );
478 
479         List listeners = Collections.EMPTY_LIST;
480 
481         // resolve all dependencies transitively to obtain a comprehensive list
482         // of jars
483         ArtifactResolutionResult result;
484         try
485         {
486             result =
487                 artifactResolver.resolveTransitively( dependencyArtifacts, project.getArtifact(),
488                                                       Collections.EMPTY_MAP, localRepository, remoteRepositories,
489                                                       metadataSource, null, listeners );
490         }
491         catch ( ArtifactResolutionException e )
492         {
493             throw new MojoExecutionException( "Unable to resolve Artifact.", e );
494         }
495         catch ( ArtifactNotFoundException e )
496         {
497             throw new MojoExecutionException( "Unable to resolve Artifact.", e );
498         }
499 
500         return result.getArtifacts();
501     }
502 
503     /**
504      * Call a Fitnesse server page.
505      * 
506      * @param pServer The Fitnesse configuration.
507      * @throws MojoFailureException If a failure occurs.
508      * @throws MojoExecutionException If an error occurs.
509      */
510     void callFitnesse( Fitnesse pServer )
511         throws MojoFailureException, MojoExecutionException
512     {
513         getLog().info( "Call result of the server," + pServer );
514         FCommandline tCmd = prepareCommandLine( pServer, getClassPath( pServer ) );
515         executeCommand( pServer, tCmd );
516     }
517 
518     /**
519      * Run locally the FitNesse tests for one configuration.
520      * 
521      * @param pServer The FitNesse configuration.
522      * @param pCmd The Command.
523      * @throws MojoFailureException If the is a FitNesse failure.
524      * @throws MojoExecutionException If the FitNesse tests can't be runned.
525      */
526     void executeCommand( Fitnesse pServer, FCommandline pCmd )
527         throws MojoFailureException, MojoExecutionException
528     {
529         FitnesseStreamConsumer tInfoConsumer = null;
530         int tResult;
531         try
532         {
533             tInfoConsumer = getStandardConsumer( pServer );
534             tResult = FCommandLineUtils.executeCommandLine( pCmd, tInfoConsumer, getErrorConsumer( tInfoConsumer ) );
535         }
536         catch ( FCommandLineException e )
537         {
538             getLog().error( "Unable to start fitnesse [" + pCmd.toString() + "]", e );
539             throw new MojoExecutionException( "Unable to start fitnesse [" + pCmd.toString() + "]", e );
540         }
541         finally
542         {
543             if ( tInfoConsumer != null )
544             {
545                 closeConsumer( tInfoConsumer );
546             }
547         }
548         if ( tResult != 0 )
549         {
550             if ( tInfoConsumer.hasGeneratedResultFile() )
551             {
552                 if ( isFailOnError() )
553                 {
554                     throw new MojoFailureException( "Fitnesse command ended with errors, exit code:" + tResult );
555                 }
556                 else
557                 {
558                     getLog().info(
559                                    "Fitnesse command ended with errors, exit code:" + tResult
560                                        + ", but failOnError is configure to \"false\""
561                                        + " change your configuration if you want to fail your build" );
562                 }
563             }
564             else
565             {
566                 throw new MojoExecutionException( "Unable to run Fitnesse, exit code [" + tResult + "]" );
567             }
568         }
569         getLog().info( "Fitnesse invocation ended with result code [" + tResult + "]" );
570     }
571 
572     /**
573      * Close reserved resources.
574      * 
575      * @param pInfoConsumer The resource to release.
576      */
577     private void closeConsumer( FitnesseStreamConsumer pInfoConsumer )
578     {
579         if ( pInfoConsumer instanceof MultipleConsumer )
580         {
581             ( (MultipleConsumer) pInfoConsumer ).getFileConsumer().close();
582         }
583         else
584         {
585             ( (FileConsumer) pInfoConsumer ).close();
586         }
587 
588     }
589 
590     /**
591      * Get the error stream of the external Process.
592      * 
593      * @param pConsumer The resources associated to the external process.
594      * @return The error stream.
595      */
596     FitnesseStreamConsumer getErrorConsumer( FitnesseStreamConsumer pConsumer )
597     {
598 
599         if ( displayOutput )
600         {
601             MultipleConsumer tMultiConsumer = (MultipleConsumer) pConsumer;
602             return new MultipleConsumer( new LogConsumer( getLog(), Level.SEVERE ), tMultiConsumer.getFileConsumer() );
603         }
604         else
605         {
606             return (FileConsumer) pConsumer;
607         }
608     }
609 
610     /**
611      * Get the standard stream of the external Process.
612      * 
613      * @param pServer The FitNesse configuration.
614      * @return The standard stream.
615      */
616     FitnesseStreamConsumer getStandardConsumer( Fitnesse pServer )
617     {
618         File tOutputFile = new File( getOutputFileName( pServer ) );
619         if ( tOutputFile.exists() )
620         {
621             tOutputFile.delete();
622         }
623         FileConsumer tFileConsumer = new FileConsumer( tOutputFile );
624 
625         if ( displayOutput )
626         {
627             return new MultipleConsumer( new LogConsumer( getLog(), Level.INFO ), tFileConsumer );
628         }
629         else
630         {
631             return tFileConsumer;
632         }
633     }
634 
635     /**
636      * Check the whole configuration of this Mojo.
637      * @throws MojoExecutionException If an error occurs.
638      */
639     void checkConfiguration()
640         throws MojoExecutionException
641     {
642         super.checkConfiguration();
643         try
644         {
645             Class tClass = Class.forName( fitnesseRunnerClass );
646             tClass.getMethod( "main", new Class[] { String[].class } );
647         }
648         catch ( ClassNotFoundException e )
649         {
650             throw new MojoExecutionException( "The class [" + fitnesseRunnerClass
651                 + "] could not be found, check your maven-fitnesse-plugin configuration and the plugin documentation." );
652         }
653         catch ( SecurityException e )
654         {
655             throw new MojoExecutionException( "The class [" + fitnesseRunnerClass
656                 + "] doesn't have a \"main\" accessible method.", e );
657         }
658         catch ( NoSuchMethodException e )
659         {
660             throw new MojoExecutionException( "The class [" + fitnesseRunnerClass
661                 + "] doesn't have a \"main\" accessible method.", e );
662         }
663         if ( ( !"fitnesse".equals( classPathProvider ) ) && ( !"maven".equals( classPathProvider ) ) )
664         {
665             throw new MojoExecutionException( "classPathProvider accepts only \"fitnesse\" ou \"maven\" values. ["
666                 + classPathProvider + "] is not valid." );
667         }
668     }
669 
670     /**
671      * Create the Command object fot running the tests locally.
672      * 
673      * @param pServer The fitnesse configuration.
674      * @param pClassPath The classpath.
675      * @return A ready to use command object.
676      */
677     FCommandline prepareCommandLine( Fitnesse pServer, String pClassPath )
678     {
679         mCmd.clear();
680 
681         mCmd.setExecutable( jdk );
682         if ( jdkOpts != null && jdkOpts.length() > 0 )
683         {
684             StringTokenizer tTok = new StringTokenizer( jdkOpts, " " );
685             while ( tTok.hasMoreTokens() )
686             {
687                 mCmd.createArgument().setValue( tTok.nextToken() );
688             }
689         }
690         mCmd.createArgument().setValue( "-cp" );
691         mCmd.createArgument().setValue( pClassPath );
692         mCmd.createArgument().setValue( fitnesseRunnerClass );
693         mCmd.createArgument().setValue( "-v" );
694         if ( debug )
695         {
696             mCmd.createArgument().setValue( "-debug" );
697         }
698         mCmd.createArgument().setValue( "-html" );
699         String tFileName = getTmpFileName( pServer );
700         File tFile = new File( tFileName );
701         if ( tFile.exists() )
702         {
703             tFile.delete();
704         }
705         mCmd.createArgument().setValue( tFileName );
706         mCmd.createArgument().setValue( "-nopath" );
707         mCmd.createArgument().setValue( pServer.getHostName() );
708 
709         mCmd.createArgument().setValue( "" + pServer.getPort() );
710         mCmd.createArgument().setValue( pServer.getPageName() );
711         mCmd.setWorkingDirectory( workingDir );
712         getLog().info( "Execute =" + mCmd.toString() );
713         getLog().info( "From =" + mCmd.getWorkingDirectory() );
714         return mCmd;
715     }
716 
717     /**
718      * Accessor.
719      * 
720      * @param pFitnesseRunnerClass The main class fot running FitNesse.
721      */
722     public void setFitnesseRunnerClass( String pFitnesseRunnerClass )
723     {
724         fitnesseRunnerClass = pFitnesseRunnerClass;
725     }
726 
727     /**
728      * Accessor.
729      * 
730      * @param pJdk The Jdk path.
731      */
732     public void setJdk( String pJdk )
733     {
734         jdk = pJdk;
735     }
736 
737     /**
738      * Accessor.
739      * 
740      * @param pWorkingDir The working directory fot the fitnesse execution.
741      */
742     public void setWorkingDir( String pWorkingDir )
743     {
744         workingDir = pWorkingDir;
745     }
746 
747     /**
748      * Accessor.
749      * 
750      * @param pDebug The debug level.
751      */
752     void setDebug( boolean pDebug )
753     {
754         debug = pDebug;
755     }
756 
757     /**
758      * Accessor.
759      * 
760      * @param pCmd The commandLine for running FitNesse.
761      */
762     void setCmd( FCommandline pCmd )
763     {
764         this.mCmd = pCmd;
765     }
766 
767     /**
768      * Accessor.
769      * 
770      * @param jdkOpts The Jsk options to use when runinng fitnesse tests.
771      */
772     void setJdkOpts( String jdkOpts )
773     {
774         this.jdkOpts = jdkOpts;
775     }
776 
777     /**
778      * Accessor.
779      * 
780      * @param pluginArtifacts The Maven resource.
781      */
782     public void setPluginArtifacts( List pluginArtifacts )
783     {
784         this.pluginArtifacts = pluginArtifacts;
785     }
786 
787     /**
788      * Resolve plugin artifacts.
789      * 
790      * @return The plugin.
791      * @throws MojoExecutionException If the plun gin can't be found.
792      */
793     public Artifact resolvePlugin()
794         throws MojoExecutionException
795     {
796         if ( pluginArtifact == null )
797         {
798             Artifact tPluginArtifact =
799                 this.artifactFactory.createArtifactWithClassifier( pluginGroupId, pluginArtifactId, pluginVersion,
800                                                                    "maven-plugin", "" );
801             try
802             {
803                 this.artifactResolver.resolve( tPluginArtifact, new ArrayList(), localRepository );
804             }
805             catch ( ArtifactResolutionException e )
806             {
807                 throw new MojoExecutionException( "Unable to resolve artificat", e );
808             }
809             catch ( ArtifactNotFoundException e )
810             {
811                 throw new MojoExecutionException( "Unable to resolve artificat", e );
812             }
813             return tPluginArtifact;
814         }
815         else
816         {
817             return pluginArtifact;
818         }
819     }
820 
821     /**
822      * For testing purpose. Record plugin information for the {@link FitnesseRunnerMojo#resolvePlugin()}.
823      * 
824      * @param pGroupId The groupId of the plugin.
825      * @param pArtifactId The artifactI of the plugin.
826      * @param pVersion The version of the plugin.
827      */
828     void setPluginArtifactInfo( String pGroupId, String pArtifactId, String pVersion )
829     {
830         pluginGroupId = pGroupId;
831         pluginArtifactId = pArtifactId;
832         pluginVersion = pVersion;
833     }
834 
835     /**
836      * For testing purpose
837      */
838     public void setPluginArtifact( Artifact pArtifact )
839     {
840         this.pluginArtifact = pArtifact;
841     }
842 
843     public void setClassPathSubstitions( List classPathSubstitions )
844     {
845         this.classPathSubstitutions = classPathSubstitions;
846     }
847 
848     public void setClassPathProvider( String classPathProvider )
849     {
850         this.classPathProvider = classPathProvider;
851     }
852 
853     public void setDisplayOutput( boolean displayOutput )
854     {
855         this.displayOutput = displayOutput;
856     }
857 
858     String getOutputFileName( Fitnesse pServer )
859     {
860         return getResultFileName( pServer, FitnesseAbstractMojo.OUTPUT_EXTENSION, "txt" );
861     }
862 
863     String getOutputUrl( Fitnesse pServer )
864     {
865         return FITNESSE_RESULT_PREFIX + "_" + pServer.getHostName() + "_" + pServer.getPageName() + "_output.txt";
866     }
867 
868     public void setCopyDependencies( boolean copyDependencies )
869     {
870         this.copyDependencies = copyDependencies;
871     }
872 
873 }