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