Coverage Report - org.codehaus.mojo.exec.ExecJavaMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
ExecJavaMojo
0%
0/189
0%
0/78
4.412
ExecJavaMojo$1
0%
0/12
0%
0/2
4.412
ExecJavaMojo$IsolatedThreadGroup
0%
0/15
0%
0/6
4.412
 
 1  
 package org.codehaus.mojo.exec;
 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 org.apache.maven.artifact.Artifact;
 23  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 24  
 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
 25  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 26  
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
 27  
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 28  
 import org.apache.maven.plugin.MojoExecutionException;
 29  
 import org.apache.maven.plugin.MojoFailureException;
 30  
 import org.apache.maven.project.MavenProject;
 31  
 import org.apache.maven.project.MavenProjectBuilder;
 32  
 import org.apache.maven.project.artifact.MavenMetadataSource;
 33  
 
 34  
 import java.io.File;
 35  
 import java.lang.reflect.Method;
 36  
 import java.net.MalformedURLException;
 37  
 import java.net.URL;
 38  
 import java.net.URLClassLoader;
 39  
 import java.util.ArrayList;
 40  
 import java.util.Collection;
 41  
 import java.util.Collections;
 42  
 import java.util.HashSet;
 43  
 import java.util.Iterator;
 44  
 import java.util.List;
 45  
 import java.util.Properties;
 46  
 import java.util.Set;
 47  
 
 48  
 /**
 49  
  * Executes the supplied java class in the current VM with the enclosing project's
 50  
  * dependencies as classpath.
 51  
  *
 52  
  * @author <a href="mailto:kaare.nilsen@gmail.com">Kaare Nilsen</a>, <a href="mailto:dsmiley@mitre.org">David Smiley</a>
 53  
  * @goal java
 54  
  * @requiresDependencyResolution test
 55  
  * @execute phase="validate"
 56  
  * @since 1.0
 57  
  */
 58  0
 public class ExecJavaMojo
 59  
     extends AbstractExecMojo
 60  
 {
 61  
     /**
 62  
      * @component
 63  
      */
 64  
     private ArtifactResolver artifactResolver;
 65  
 
 66  
     /**
 67  
      * @component
 68  
      */
 69  
     private ArtifactFactory artifactFactory;
 70  
 
 71  
     /**
 72  
      * @component
 73  
      */
 74  
     private ArtifactMetadataSource metadataSource;
 75  
 
 76  
     /**
 77  
      * @parameter expression="${localRepository}"
 78  
      * @required
 79  
      * @readonly
 80  
      * @since 1.0
 81  
      */
 82  
     private ArtifactRepository localRepository;
 83  
 
 84  
     /**
 85  
      * @parameter expression="${project.remoteArtifactRepositories}"
 86  
      * @required
 87  
      * @readonly
 88  
      * @since 1.1-beta-1
 89  
      */
 90  
     private List remoteRepositories;
 91  
 
 92  
     /**
 93  
      * @component
 94  
      * @since 1.0
 95  
      */
 96  
     private MavenProjectBuilder projectBuilder;
 97  
 
 98  
     /**
 99  
      * @parameter expression="${plugin.artifacts}"
 100  
      * @readonly
 101  
      * @since 1.1-beta-1
 102  
      */
 103  
     private List pluginDependencies;
 104  
 
 105  
     /**
 106  
      * The main class to execute.
 107  
      *
 108  
      * @parameter expression="${exec.mainClass}"
 109  
      * @required
 110  
      * @since 1.0
 111  
      */
 112  
     private String mainClass;
 113  
 
 114  
     /**
 115  
      * The class arguments.
 116  
      *
 117  
      * @parameter expression="${exec.arguments}"
 118  
      * @since 1.0
 119  
      */
 120  
     private String[] arguments;
 121  
 
 122  
     /**
 123  
      * A list of system properties to be passed. Note: as the execution is not forked, some system properties
 124  
      * required by the JVM cannot be passed here. Use MAVEN_OPTS or the exec:exec instead. See the user guide for
 125  
      * more information.
 126  
      *
 127  
      * @parameter
 128  
      * @since 1.0
 129  
      */
 130  
     private Property[] systemProperties;
 131  
 
 132  
     /**
 133  
      * Indicates if mojo should be kept running after the mainclass terminates.
 134  
      * Usefull for serverlike apps with deamonthreads.
 135  
      *
 136  
      * @parameter expression="${exec.keepAlive}" default-value="false"
 137  
      * @deprecated since 1.1-alpha-1
 138  
      * @since 1.0
 139  
      */
 140  
     private boolean keepAlive;
 141  
 
 142  
     /**
 143  
      * Indicates if the project dependencies should be used when executing
 144  
      * the main class.
 145  
      *
 146  
      * @parameter expression="${exec.includeProjectDependencies}" default-value="true"
 147  
      * @since 1.1-beta-1
 148  
      */
 149  
     private boolean includeProjectDependencies;
 150  
 
 151  
     /**
 152  
      * Indicates if this plugin's dependencies should be used when executing
 153  
      * the main class.
 154  
      * <p/>
 155  
      * This is useful when project dependencies are not appropriate.  Using only
 156  
      * the plugin dependencies can be particularly useful when the project is
 157  
      * not a java project.  For example a mvn project using the csharp plugins
 158  
      * only expects to see dotnet libraries as dependencies.
 159  
      *
 160  
      * @parameter expression="${exec.includePluginDependencies}" default-value="false"
 161  
      * @since 1.1-beta-1
 162  
      */
 163  
     private boolean includePluginDependencies;
 164  
 
 165  
     /**
 166  
      * If provided the ExecutableDependency identifies which of the plugin dependencies
 167  
      * contains the executable class.  This will have the affect of only including
 168  
      * plugin dependencies required by the identified ExecutableDependency.
 169  
      * <p/>
 170  
      * If includeProjectDependencies is set to <code>true</code>, all of the project dependencies
 171  
      * will be included on the executable's classpath.  Whether a particular project
 172  
      * dependency is a dependency of the identified ExecutableDependency will be
 173  
      * irrelevant to its inclusion in the classpath.
 174  
      *
 175  
      * @parameter
 176  
      * @optional
 177  
      * @since 1.1-beta-1
 178  
      */
 179  
     private ExecutableDependency executableDependency;
 180  
 
 181  
     /**
 182  
      * Wether to interrupt/join and possibly stop the daemon threads upon quitting. <br/> If this is <code>false</code>,
 183  
      *  maven does nothing about the daemon threads.  When maven has no more work to do, the VM will normally terminate
 184  
      *  any remaining daemon threads.
 185  
      * <p>
 186  
      * In certain cases (in particular if maven is embedded),
 187  
      *  you might need to keep this enabled to make sure threads are properly cleaned up to ensure they don't interfere
 188  
      * with subsequent activity.
 189  
      * In that case, see {@link #daemonThreadJoinTimeout} and
 190  
      * {@link #stopUnresponsiveDaemonThreads} for further tuning.
 191  
      * </p>
 192  
      * @parameter expression="${exec.cleanupDaemonThreads} default-value="true"
 193  
      * @since 1.1-beta-1
 194  
      */
 195  
      private boolean cleanupDaemonThreads;
 196  
 
 197  
      /**
 198  
      * This defines the number of milliseconds to wait for daemon threads to quit following their interruption.<br/>
 199  
      * This is only taken into account if {@link #cleanupDaemonThreads} is <code>true</code>.
 200  
      * A value &lt;=0 means to not timeout (i.e. wait indefinitely for threads to finish). Following a timeout, a
 201  
      * warning will be logged.
 202  
      * <p>Note: properly coded threads <i>should</i> terminate upon interruption but some threads may prove
 203  
      * problematic:  as the VM does interrupt daemon threads, some code may not have been written to handle
 204  
      * interruption properly. For example java.util.Timer is known to not handle interruptions in JDK &lt;= 1.6.
 205  
      * So it is not possible for us to infinitely wait by default otherwise maven could hang. A  sensible default 
 206  
      * value has been chosen, but this default value <i>may change</i> in the future based on user feedback.</p>
 207  
      * @parameter expression="${exec.daemonThreadJoinTimeout}" default-value="15000"
 208  
      * @since 1.1-beta-1
 209  
      */
 210  
     private long daemonThreadJoinTimeout;
 211  
 
 212  
     /**
 213  
      * Wether to call {@link Thread#stop()} following a timing out of waiting for an interrupted thread to finish.
 214  
      * This is only taken into account if {@link #cleanupDaemonThreads} is <code>true</code>
 215  
      * and the {@link #daemonThreadJoinTimeout} threshold has been reached for an uncooperative thread.
 216  
      * If this is <code>false</code>, or if {@link Thread#stop()} fails to get the thread to stop, then
 217  
      * a warning is logged and Maven will continue on while the affected threads (and related objects in memory)
 218  
      * linger on.  Consider setting this to <code>true</code> if you are invoking problematic code that you can't fix. 
 219  
      * An example is {@link java.util.Timer} which doesn't respond to interruption.  To have <code>Timer</code>
 220  
      * fixed, vote for <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6336543">this bug</a>.
 221  
      * @parameter expression="${exec.stopUnresponsiveDaemonThreads} default-value="false"
 222  
      * @since 1.1-beta-1
 223  
      */
 224  
     private boolean stopUnresponsiveDaemonThreads;
 225  
 
 226  
     /**
 227  
      * Deprecated this is not needed anymore.
 228  
      *
 229  
      * @parameter expression="${exec.killAfter}" default-value="-1"
 230  
      * @deprecated since 1.1-alpha-1
 231  
      * @since 1.0
 232  
      */
 233  
     private long killAfter;
 234  
         
 235  
     private Properties originalSystemProperties;
 236  
 
 237  
     /**
 238  
      * Execute goal.
 239  
      * @throws MojoExecutionException execution of the main class or one of the threads it generated failed.
 240  
      * @throws MojoFailureException something bad happened...
 241  
      */
 242  
     public void execute()
 243  
         throws MojoExecutionException, MojoFailureException
 244  
     {
 245  0
         if ( isSkip() )
 246  
         {
 247  0
             getLog().info( "skipping execute as per configuraion" );
 248  0
             return;
 249  
         }
 250  0
         if ( killAfter != -1 )
 251  
         {
 252  0
             getLog().warn( "Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6." );
 253  
         }
 254  
 
 255  0
         if ( null == arguments )
 256  
         {
 257  0
             arguments = new String[0];
 258  
         }
 259  
 
 260  0
         if ( getLog().isDebugEnabled() )
 261  
         {
 262  0
             StringBuffer msg = new StringBuffer( "Invoking : " );
 263  0
             msg.append( mainClass );
 264  0
             msg.append( ".main(" );
 265  0
             for ( int i = 0; i < arguments.length; i++ )
 266  
             {
 267  0
                 if ( i > 0 )
 268  
                 {
 269  0
                     msg.append( ", " );
 270  
                 }
 271  0
                 msg.append( arguments[i] );
 272  
             }
 273  0
             msg.append( ")" );
 274  0
             getLog().debug(  msg );
 275  
         }
 276  
 
 277  0
         IsolatedThreadGroup threadGroup = new IsolatedThreadGroup( mainClass /*name*/ );
 278  0
         Thread bootstrapThread = new Thread( threadGroup, new Runnable()
 279  0
         {
 280  
             public void run()
 281  
             {
 282  
                 try
 283  
                 {
 284  0
                     Method main = Thread.currentThread().getContextClassLoader().loadClass( mainClass )
 285  
                         .getMethod( "main", new Class[]{ String[].class } );
 286  0
                     if ( ! main.isAccessible() )
 287  
                     {
 288  0
                         getLog().debug( "Setting accessibility to true in order to invoke main()." );
 289  0
                         main.setAccessible( true );
 290  
                     }
 291  0
                     main.invoke( main, new Object[]{arguments} );
 292  
                 }
 293  0
                 catch ( NoSuchMethodException e )
 294  
                 {   // just pass it on
 295  0
                     Thread.currentThread().getThreadGroup().uncaughtException( Thread.currentThread(), 
 296  
                           new Exception( 
 297  
                                "The specified mainClass doesn't contain a main method with appropriate signature.", e
 298  
                           )
 299  
                        );
 300  
                 }
 301  0
                 catch ( Exception e )
 302  
                 {   // just pass it on
 303  0
                     Thread.currentThread().getThreadGroup().uncaughtException( Thread.currentThread(), e );
 304  0
                 }
 305  0
             }
 306  
         }, mainClass + ".main()" );
 307  0
         bootstrapThread.setContextClassLoader( getClassLoader() );
 308  0
         setSystemProperties();
 309  
 
 310  0
         bootstrapThread.start();
 311  0
         joinNonDaemonThreads( threadGroup );
 312  
         // It's plausible that spontaneously a non-daemon thread might be created as we try and shut down,
 313  
         // but it's too late since the termination condition (only daemon threads) has been triggered.
 314  0
         if ( keepAlive )
 315  
         {
 316  0
             getLog().warn(
 317  
                 "Warning: keepAlive is now deprecated and obsolete. Do you need it? Please comment on MEXEC-6." );
 318  0
             waitFor( 0 );
 319  
         }
 320  
 
 321  0
         if ( cleanupDaemonThreads )
 322  
         {
 323  
         
 324  0
             terminateThreads( threadGroup );
 325  
             
 326  
             try
 327  
             {
 328  0
                 threadGroup.destroy();
 329  
             }
 330  0
             catch ( IllegalThreadStateException e )
 331  
             {
 332  0
                 getLog().warn( "Couldn't destroy threadgroup " + threadGroup, e );
 333  0
             }
 334  
         }
 335  
         
 336  
 
 337  0
         if ( originalSystemProperties != null )
 338  
         {
 339  0
             System.setProperties( originalSystemProperties );
 340  
         }
 341  
 
 342  0
         synchronized ( threadGroup )
 343  
         {
 344  0
             if ( threadGroup.uncaughtException != null )
 345  
             {
 346  0
                 throw new MojoExecutionException( "An exception occured while executing the Java class. " 
 347  
                                                   + threadGroup.uncaughtException.getMessage(),
 348  
                                                   threadGroup.uncaughtException );
 349  
             }
 350  0
         }
 351  
 
 352  0
         registerSourceRoots();
 353  0
     }
 354  
 
 355  
     /**
 356  
      * a ThreadGroup to isolate execution and collect exceptions.
 357  
      */
 358  0
     class IsolatedThreadGroup extends ThreadGroup
 359  
     {
 360  
         private Throwable uncaughtException; // synchronize access to this
 361  
 
 362  
         public IsolatedThreadGroup( String name )
 363  0
         {
 364  0
             super( name );
 365  0
         }
 366  
 
 367  
         public void uncaughtException( Thread thread, Throwable throwable )
 368  
         {
 369  0
             if ( throwable instanceof ThreadDeath )
 370  
             {
 371  0
                 return; //harmless
 372  
             }
 373  0
             boolean doLog = false;
 374  0
             synchronized ( this )
 375  
             {
 376  0
                 if ( uncaughtException == null ) // only remember the first one
 377  
                 {
 378  0
                     uncaughtException = throwable; // will be reported eventually
 379  
                 }
 380  
                 else
 381  
                 {
 382  0
                     doLog = true;
 383  
                 }
 384  0
             }
 385  0
             if ( doLog )
 386  
             {
 387  0
                 getLog().warn( "an additional exception was thrown", throwable );
 388  
             }
 389  0
         }
 390  
     }
 391  
 
 392  
     private void joinNonDaemonThreads( ThreadGroup threadGroup )
 393  
     {
 394  
         boolean foundNonDaemon;
 395  
         do
 396  
         {
 397  0
             foundNonDaemon = false;
 398  0
             Collection threads = getActiveThreads( threadGroup );
 399  0
             for ( Iterator iter = threads.iterator(); iter.hasNext(); )
 400  
             {
 401  0
                 Thread thread = (Thread) iter.next();
 402  0
                 if ( thread.isDaemon() )
 403  
                 {
 404  0
                     continue;
 405  
                 }
 406  0
                 foundNonDaemon = true;   //try again; maybe more threads were created while we were busy
 407  0
                 joinThread( thread, 0 );
 408  0
             }
 409  0
         } while ( foundNonDaemon );
 410  0
     }
 411  
 
 412  
     private void joinThread( Thread thread, long timeoutMsecs )
 413  
     {
 414  
         try
 415  
         {
 416  0
             getLog().debug( "joining on thread " + thread );
 417  0
             thread.join( timeoutMsecs );
 418  
         }
 419  0
         catch ( InterruptedException e )
 420  
         {
 421  0
             Thread.currentThread().interrupt();   // good practice if don't throw
 422  0
             getLog().warn( "interrupted while joining against thread " + thread, e );   // not expected!
 423  0
         }
 424  0
         if ( thread.isAlive() ) //generally abnormal
 425  
         {
 426  0
             getLog().warn( "thread " + thread + " was interrupted but is still alive after waiting at least "
 427  
                 + timeoutMsecs + "msecs" );
 428  
         }
 429  0
     }
 430  
 
 431  
     private void terminateThreads( ThreadGroup threadGroup )
 432  
     {
 433  0
         long startTime = System.currentTimeMillis();
 434  0
         Set uncooperativeThreads = new HashSet(); // these were not responsive to interruption
 435  0
         for ( Collection threads = getActiveThreads( threadGroup ); !threads.isEmpty();
 436  0
               threads = getActiveThreads( threadGroup ), threads.removeAll( uncooperativeThreads ) )
 437  
         {
 438  
             // Interrupt all threads we know about as of this instant (harmless if spuriously went dead (! isAlive())
 439  
             //   or if something else interrupted it ( isInterrupted() ).
 440  0
             for ( Iterator iter = threads.iterator(); iter.hasNext(); )
 441  
             {
 442  0
                 Thread thread = (Thread) iter.next();
 443  0
                 getLog().debug( "interrupting thread " + thread );
 444  0
                 thread.interrupt();
 445  0
             }
 446  
             // Now join with a timeout and call stop() (assuming flags are set right)
 447  0
             for ( Iterator iter = threads.iterator(); iter.hasNext(); )
 448  
             {
 449  0
                 Thread thread = (Thread) iter.next();
 450  0
                 if ( ! thread.isAlive() )
 451  
                 {
 452  0
                     continue; //and, presumably it won't show up in getActiveThreads() next iteration
 453  
                 }
 454  0
                 if ( daemonThreadJoinTimeout <= 0 )
 455  
                 {
 456  0
                     joinThread( thread, 0 ); //waits until not alive; no timeout
 457  0
                     continue;
 458  
                 }
 459  0
                 long timeout = daemonThreadJoinTimeout 
 460  
                                - ( System.currentTimeMillis() - startTime );
 461  0
                 if ( timeout > 0 )
 462  
                 {
 463  0
                     joinThread( thread, timeout );
 464  
                 }
 465  0
                 if ( ! thread.isAlive() )
 466  
                 {
 467  0
                     continue;
 468  
                 }
 469  0
                 uncooperativeThreads.add( thread ); // ensure we don't process again
 470  0
                 if ( stopUnresponsiveDaemonThreads )
 471  
                 {
 472  0
                     getLog().warn( "thread " + thread + " will be Thread.stop()'ed" );
 473  0
                     thread.stop();
 474  
                 }
 475  
                 else
 476  
                 {
 477  0
                     getLog().warn( "thread " + thread + " will linger despite being asked to die via interruption" );
 478  
                 }
 479  0
             }
 480  
         }
 481  0
         if ( ! uncooperativeThreads.isEmpty() )
 482  
         {
 483  0
             getLog().warn( "NOTE: " + uncooperativeThreads.size() + " thread(s) did not finish despite being asked to "
 484  
                 + " via interruption. This is not a problem with exec:java, it is a problem with the running code."
 485  
                 + " Although not serious, it should be remedied." );
 486  
         }
 487  
         else
 488  
         {
 489  0
             int activeCount = threadGroup.activeCount();
 490  0
             if ( activeCount != 0 )
 491  
             {
 492  
                 // TODO this may be nothing; continue on anyway; perhaps don't even log in future
 493  0
                 Thread[] threadsArray = new Thread[1];
 494  0
                 threadGroup.enumerate( threadsArray );
 495  0
                 getLog().debug( "strange; " + activeCount
 496  
                         + " thread(s) still active in the group " + threadGroup + " such as " + threadsArray[0] );
 497  
             }
 498  
         }
 499  0
     }
 500  
 
 501  
     private Collection getActiveThreads( ThreadGroup threadGroup )
 502  
     {
 503  0
         Thread[] threads = new Thread[ threadGroup.activeCount() ];
 504  0
         int numThreads = threadGroup.enumerate( threads );
 505  0
         Collection result = new ArrayList( numThreads );
 506  0
         for ( int i = 0; i < threads.length && threads[i] != null; i++ )
 507  
         {
 508  0
             result.add( threads[i] );
 509  
         }
 510  0
         return result; //note: result should be modifiable
 511  
     }
 512  
 
 513  
     /**
 514  
      * Pass any given system properties to the java system properties.
 515  
      */
 516  
     private void setSystemProperties()
 517  
     {
 518  0
         if ( systemProperties != null )
 519  
         {
 520  0
             originalSystemProperties = System.getProperties();
 521  0
             for ( int i = 0; i < systemProperties.length; i++ )
 522  
             {
 523  0
                 Property systemProperty = systemProperties[i];
 524  0
                 String value = systemProperty.getValue();
 525  0
                 System.setProperty( systemProperty.getKey(), value == null ? "" : value );
 526  
             }
 527  
         }
 528  0
     }
 529  
 
 530  
     /**
 531  
      * Set up a classloader for the execution of the main class.
 532  
      *
 533  
      * @return the classloader
 534  
      * @throws MojoExecutionException if a problem happens
 535  
      */
 536  
     private ClassLoader getClassLoader()
 537  
         throws MojoExecutionException
 538  
     {
 539  0
         List classpathURLs = new ArrayList();
 540  0
         this.addRelevantPluginDependenciesToClasspath( classpathURLs );
 541  0
         this.addRelevantProjectDependenciesToClasspath( classpathURLs );
 542  0
         return new URLClassLoader( ( URL[] ) classpathURLs.toArray( new URL[ classpathURLs.size() ] ) );
 543  
     }
 544  
 
 545  
     /**
 546  
      * Add any relevant project dependencies to the classpath.
 547  
      * Indirectly takes includePluginDependencies and ExecutableDependency into consideration.
 548  
      *
 549  
      * @param path classpath of {@link java.net.URL} objects
 550  
      * @throws MojoExecutionException if a problem happens
 551  
      */
 552  
     private void addRelevantPluginDependenciesToClasspath( List path )
 553  
         throws MojoExecutionException
 554  
     {
 555  0
         if ( hasCommandlineArgs() )
 556  
         {
 557  0
             arguments = parseCommandlineArgs();
 558  
         }
 559  
 
 560  
         try
 561  
         {
 562  0
             Iterator iter = this.determineRelevantPluginDependencies().iterator();
 563  0
             while ( iter.hasNext() )
 564  
             {
 565  0
                 Artifact classPathElement = (Artifact) iter.next();
 566  0
                 getLog().debug(
 567  
                     "Adding plugin dependency artifact: " + classPathElement.getArtifactId() + " to classpath" );
 568  0
                 path.add( classPathElement.getFile().toURI().toURL() );
 569  0
             }
 570  
         }
 571  0
         catch ( MalformedURLException e )
 572  
         {
 573  0
             throw new MojoExecutionException( "Error during setting up classpath", e );
 574  0
         }
 575  
 
 576  0
     }
 577  
 
 578  
     /**
 579  
      * Add any relevant project dependencies to the classpath.
 580  
      * Takes includeProjectDependencies into consideration.
 581  
      *
 582  
      * @param path classpath of {@link java.net.URL} objects
 583  
      * @throws MojoExecutionException if a problem happens
 584  
      */
 585  
     private void addRelevantProjectDependenciesToClasspath( List path )
 586  
         throws MojoExecutionException
 587  
     {
 588  0
         if ( this.includeProjectDependencies )
 589  
         {
 590  
             try
 591  
             {
 592  0
                 getLog().debug( "Project Dependencies will be included." );
 593  
 
 594  0
                 List artifacts = new ArrayList();
 595  0
                 List theClasspathFiles = new ArrayList();
 596  
  
 597  0
                 collectProjectArtifactsAndClasspath( artifacts, theClasspathFiles );
 598  
 
 599  0
                 for ( Iterator it = theClasspathFiles.iterator(); it.hasNext(); )
 600  
                 {
 601  0
                      URL url = ( (File) it.next() ).toURI().toURL();
 602  0
                      getLog().debug( "Adding to classpath : " + url );
 603  0
                      path.add( url );
 604  0
                 }
 605  
 
 606  0
                 Iterator iter = artifacts.iterator();
 607  0
                 while ( iter.hasNext() )
 608  
                 {
 609  0
                     Artifact classPathElement = (Artifact) iter.next();
 610  0
                     getLog().debug(
 611  
                         "Adding project dependency artifact: " + classPathElement.getArtifactId() + " to classpath" );
 612  0
                     path.add( classPathElement.getFile().toURI().toURL() );
 613  0
                 }
 614  
 
 615  
             }
 616  0
             catch ( MalformedURLException e )
 617  
             {
 618  0
                 throw new MojoExecutionException( "Error during setting up classpath", e );
 619  0
             }
 620  
         }
 621  
         else
 622  
         {
 623  0
             getLog().debug( "Project Dependencies will be excluded." );
 624  
         }
 625  
 
 626  0
     }
 627  
 
 628  
     /**
 629  
      * Determine all plugin dependencies relevant to the executable.
 630  
      * Takes includePlugins, and the executableDependency into consideration.
 631  
      *
 632  
      * @return a set of Artifact objects.
 633  
      *         (Empty set is returned if there are no relevant plugin dependencies.)
 634  
      * @throws MojoExecutionException if a problem happens resolving the plufin dependencies
 635  
      */
 636  
     private Set determineRelevantPluginDependencies()
 637  
         throws MojoExecutionException
 638  
     {
 639  
         Set relevantDependencies;
 640  0
         if ( this.includePluginDependencies )
 641  
         {
 642  0
             if ( this.executableDependency == null )
 643  
             {
 644  0
                 getLog().debug( "All Plugin Dependencies will be included." );
 645  0
                 relevantDependencies = new HashSet( this.pluginDependencies );
 646  
             }
 647  
             else
 648  
             {
 649  0
                 getLog().debug( "Selected plugin Dependencies will be included." );
 650  0
                 Artifact executableArtifact = this.findExecutableArtifact();
 651  0
                 Artifact executablePomArtifact = this.getExecutablePomArtifact( executableArtifact );
 652  0
                 relevantDependencies = this.resolveExecutableDependencies( executablePomArtifact );
 653  0
             }
 654  
         }
 655  
         else
 656  
         {
 657  0
             relevantDependencies = Collections.EMPTY_SET;
 658  0
             getLog().debug( "Plugin Dependencies will be excluded." );
 659  
         }
 660  0
         return relevantDependencies;
 661  
     }
 662  
 
 663  
     /**
 664  
      * Get the artifact which refers to the POM of the executable artifact.
 665  
      *
 666  
      * @param executableArtifact this artifact refers to the actual assembly.
 667  
      * @return an artifact which refers to the POM of the executable artifact.
 668  
      */
 669  
     private Artifact getExecutablePomArtifact( Artifact executableArtifact )
 670  
     {
 671  0
         return this.artifactFactory.createBuildArtifact( executableArtifact.getGroupId(),
 672  
                                                          executableArtifact.getArtifactId(),
 673  
                                                          executableArtifact.getVersion(), "pom" );
 674  
     }
 675  
 
 676  
     /**
 677  
      * Examine the plugin dependencies to find the executable artifact.
 678  
      *
 679  
      * @return an artifact which refers to the actual executable tool (not a POM)
 680  
      * @throws MojoExecutionException if no executable artifact was found
 681  
      */
 682  
     private Artifact findExecutableArtifact()
 683  
         throws MojoExecutionException
 684  
     {
 685  
         //ILimitedArtifactIdentifier execToolAssembly = this.getExecutableToolAssembly();
 686  
 
 687  0
         Artifact executableTool = null;
 688  0
         for ( Iterator iter = this.pluginDependencies.iterator(); iter.hasNext(); )
 689  
         {
 690  0
             Artifact pluginDep = (Artifact) iter.next();
 691  0
             if ( this.executableDependency.matches( pluginDep ) )
 692  
             {
 693  0
                 executableTool = pluginDep;
 694  0
                 break;
 695  
             }
 696  0
         }
 697  
 
 698  0
         if ( executableTool == null )
 699  
         {
 700  0
             throw new MojoExecutionException(
 701  
                 "No dependency of the plugin matches the specified executableDependency."
 702  
                 + "  Specified executableToolAssembly is: " + executableDependency.toString() );
 703  
         }
 704  
 
 705  0
         return executableTool;
 706  
     }
 707  
 
 708  
     /**
 709  
      * Resolve the executable dependencies for the specified project
 710  
      * @param executablePomArtifact the project's POM
 711  
      * @return a set of Artifacts
 712  
      * @throws MojoExecutionException if a failure happens
 713  
      */
 714  
     private Set resolveExecutableDependencies( Artifact executablePomArtifact )
 715  
         throws MojoExecutionException
 716  
     {
 717  
 
 718  
         Set executableDependencies;
 719  
         try
 720  
         {
 721  0
             MavenProject executableProject = this.projectBuilder.buildFromRepository( executablePomArtifact,
 722  
                                                                                       this.remoteRepositories,
 723  
                                                                                       this.localRepository );
 724  
 
 725  
             //get all of the dependencies for the executable project
 726  0
             List dependencies = executableProject.getDependencies();
 727  
 
 728  
             //make Artifacts of all the dependencies
 729  0
             Set dependencyArtifacts =
 730  
                 MavenMetadataSource.createArtifacts( this.artifactFactory, dependencies, null, null, null );
 731  
 
 732  
             //not forgetting the Artifact of the project itself
 733  0
             dependencyArtifacts.add( executableProject.getArtifact() );
 734  
 
 735  
             //resolve all dependencies transitively to obtain a comprehensive list of assemblies
 736  0
             ArtifactResolutionResult result = artifactResolver.resolveTransitively( dependencyArtifacts,
 737  
                                                                                     executablePomArtifact,
 738  
                                                                                     Collections.EMPTY_MAP,
 739  
                                                                                     this.localRepository,
 740  
                                                                                     this.remoteRepositories,
 741  
                                                                                     metadataSource, null,
 742  
                                                                                     Collections.EMPTY_LIST );
 743  0
             executableDependencies = result.getArtifacts();
 744  
 
 745  
         }
 746  0
         catch ( Exception ex )
 747  
         {
 748  0
             throw new MojoExecutionException(
 749  
                 "Encountered problems resolving dependencies of the executable " + "in preparation for its execution.",
 750  
                 ex );
 751  0
         }
 752  
 
 753  0
         return executableDependencies;
 754  
     }
 755  
 
 756  
     /**
 757  
      * Stop program execution for nn millis.
 758  
      *
 759  
      * @param millis the number of millis-seconds to wait for,
 760  
      *               <code>0</code> stops program forever.
 761  
      */
 762  
     private void waitFor( long millis )
 763  
     {
 764  0
         Object lock = new Object();
 765  0
         synchronized ( lock )
 766  
         {
 767  
             try
 768  
             {
 769  0
                 lock.wait( millis );
 770  
             }
 771  0
             catch ( InterruptedException e )
 772  
             {
 773  0
                 Thread.currentThread().interrupt(); // good practice if don't throw
 774  0
                 getLog().warn( "Spuriously interrupted while waiting for " + millis + "ms", e );
 775  0
             }
 776  0
         }
 777  0
     }
 778  
 
 779  
 }