001 package org.codehaus.mojo.exec; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import org.apache.maven.artifact.Artifact; 023 import org.apache.maven.artifact.factory.ArtifactFactory; 024 import org.apache.maven.artifact.metadata.ArtifactMetadataSource; 025 import org.apache.maven.artifact.repository.ArtifactRepository; 026 import org.apache.maven.artifact.resolver.ArtifactResolutionResult; 027 import org.apache.maven.artifact.resolver.ArtifactResolver; 028 import org.apache.maven.plugin.MojoExecutionException; 029 import org.apache.maven.plugin.MojoFailureException; 030 import org.apache.maven.project.MavenProject; 031 import org.apache.maven.project.MavenProjectBuilder; 032 import org.apache.maven.project.artifact.MavenMetadataSource; 033 034 import java.io.File; 035 import java.lang.reflect.Method; 036 import java.net.MalformedURLException; 037 import java.net.URL; 038 import java.net.URLClassLoader; 039 import java.util.ArrayList; 040 import java.util.Collection; 041 import java.util.Collections; 042 import java.util.HashSet; 043 import java.util.Iterator; 044 import java.util.List; 045 import java.util.Properties; 046 import java.util.Set; 047 048 /** 049 * Executes the supplied java class in the current VM with the enclosing project's 050 * dependencies as classpath. 051 * 052 * @author <a href="mailto:kaare.nilsen@gmail.com">Kaare Nilsen</a>, <a href="mailto:dsmiley@mitre.org">David Smiley</a> 053 * @goal java 054 * @requiresDependencyResolution test 055 * @execute phase="validate" 056 * @since 1.0 057 */ 058 public class ExecJavaMojo 059 extends AbstractExecMojo 060 { 061 /** 062 * @component 063 */ 064 private ArtifactResolver artifactResolver; 065 066 /** 067 * @component 068 */ 069 private ArtifactFactory artifactFactory; 070 071 /** 072 * @component 073 */ 074 private ArtifactMetadataSource metadataSource; 075 076 /** 077 * @parameter expression="${localRepository}" 078 * @required 079 * @readonly 080 * @since 1.0 081 */ 082 private ArtifactRepository localRepository; 083 084 /** 085 * @parameter expression="${project.remoteArtifactRepositories}" 086 * @required 087 * @readonly 088 * @since 1.1-beta-1 089 */ 090 private List remoteRepositories; 091 092 /** 093 * @component 094 * @since 1.0 095 */ 096 private MavenProjectBuilder projectBuilder; 097 098 /** 099 * @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 <=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 <= 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 if ( isSkip() ) 246 { 247 getLog().info( "skipping execute as per configuraion" ); 248 return; 249 } 250 if ( killAfter != -1 ) 251 { 252 getLog().warn( "Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6." ); 253 } 254 255 if ( null == arguments ) 256 { 257 arguments = new String[0]; 258 } 259 260 if ( getLog().isDebugEnabled() ) 261 { 262 StringBuffer msg = new StringBuffer( "Invoking : " ); 263 msg.append( mainClass ); 264 msg.append( ".main(" ); 265 for ( int i = 0; i < arguments.length; i++ ) 266 { 267 if ( i > 0 ) 268 { 269 msg.append( ", " ); 270 } 271 msg.append( arguments[i] ); 272 } 273 msg.append( ")" ); 274 getLog().debug( msg ); 275 } 276 277 IsolatedThreadGroup threadGroup = new IsolatedThreadGroup( mainClass /*name*/ ); 278 Thread bootstrapThread = new Thread( threadGroup, new Runnable() 279 { 280 public void run() 281 { 282 try 283 { 284 Method main = Thread.currentThread().getContextClassLoader().loadClass( mainClass ) 285 .getMethod( "main", new Class[]{ String[].class } ); 286 if ( ! main.isAccessible() ) 287 { 288 getLog().debug( "Setting accessibility to true in order to invoke main()." ); 289 main.setAccessible( true ); 290 } 291 main.invoke( main, new Object[]{arguments} ); 292 } 293 catch ( NoSuchMethodException e ) 294 { // just pass it on 295 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 catch ( Exception e ) 302 { // just pass it on 303 Thread.currentThread().getThreadGroup().uncaughtException( Thread.currentThread(), e ); 304 } 305 } 306 }, mainClass + ".main()" ); 307 bootstrapThread.setContextClassLoader( getClassLoader() ); 308 setSystemProperties(); 309 310 bootstrapThread.start(); 311 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 if ( keepAlive ) 315 { 316 getLog().warn( 317 "Warning: keepAlive is now deprecated and obsolete. Do you need it? Please comment on MEXEC-6." ); 318 waitFor( 0 ); 319 } 320 321 if ( cleanupDaemonThreads ) 322 { 323 324 terminateThreads( threadGroup ); 325 326 try 327 { 328 threadGroup.destroy(); 329 } 330 catch ( IllegalThreadStateException e ) 331 { 332 getLog().warn( "Couldn't destroy threadgroup " + threadGroup, e ); 333 } 334 } 335 336 337 if ( originalSystemProperties != null ) 338 { 339 System.setProperties( originalSystemProperties ); 340 } 341 342 synchronized ( threadGroup ) 343 { 344 if ( threadGroup.uncaughtException != null ) 345 { 346 throw new MojoExecutionException( "An exception occured while executing the Java class. " 347 + threadGroup.uncaughtException.getMessage(), 348 threadGroup.uncaughtException ); 349 } 350 } 351 352 registerSourceRoots(); 353 } 354 355 /** 356 * a ThreadGroup to isolate execution and collect exceptions. 357 */ 358 class IsolatedThreadGroup extends ThreadGroup 359 { 360 private Throwable uncaughtException; // synchronize access to this 361 362 public IsolatedThreadGroup( String name ) 363 { 364 super( name ); 365 } 366 367 public void uncaughtException( Thread thread, Throwable throwable ) 368 { 369 if ( throwable instanceof ThreadDeath ) 370 { 371 return; //harmless 372 } 373 boolean doLog = false; 374 synchronized ( this ) 375 { 376 if ( uncaughtException == null ) // only remember the first one 377 { 378 uncaughtException = throwable; // will be reported eventually 379 } 380 else 381 { 382 doLog = true; 383 } 384 } 385 if ( doLog ) 386 { 387 getLog().warn( "an additional exception was thrown", throwable ); 388 } 389 } 390 } 391 392 private void joinNonDaemonThreads( ThreadGroup threadGroup ) 393 { 394 boolean foundNonDaemon; 395 do 396 { 397 foundNonDaemon = false; 398 Collection threads = getActiveThreads( threadGroup ); 399 for ( Iterator iter = threads.iterator(); iter.hasNext(); ) 400 { 401 Thread thread = (Thread) iter.next(); 402 if ( thread.isDaemon() ) 403 { 404 continue; 405 } 406 foundNonDaemon = true; //try again; maybe more threads were created while we were busy 407 joinThread( thread, 0 ); 408 } 409 } while ( foundNonDaemon ); 410 } 411 412 private void joinThread( Thread thread, long timeoutMsecs ) 413 { 414 try 415 { 416 getLog().debug( "joining on thread " + thread ); 417 thread.join( timeoutMsecs ); 418 } 419 catch ( InterruptedException e ) 420 { 421 Thread.currentThread().interrupt(); // good practice if don't throw 422 getLog().warn( "interrupted while joining against thread " + thread, e ); // not expected! 423 } 424 if ( thread.isAlive() ) //generally abnormal 425 { 426 getLog().warn( "thread " + thread + " was interrupted but is still alive after waiting at least " 427 + timeoutMsecs + "msecs" ); 428 } 429 } 430 431 private void terminateThreads( ThreadGroup threadGroup ) 432 { 433 long startTime = System.currentTimeMillis(); 434 Set uncooperativeThreads = new HashSet(); // these were not responsive to interruption 435 for ( Collection threads = getActiveThreads( threadGroup ); !threads.isEmpty(); 436 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 for ( Iterator iter = threads.iterator(); iter.hasNext(); ) 441 { 442 Thread thread = (Thread) iter.next(); 443 getLog().debug( "interrupting thread " + thread ); 444 thread.interrupt(); 445 } 446 // Now join with a timeout and call stop() (assuming flags are set right) 447 for ( Iterator iter = threads.iterator(); iter.hasNext(); ) 448 { 449 Thread thread = (Thread) iter.next(); 450 if ( ! thread.isAlive() ) 451 { 452 continue; //and, presumably it won't show up in getActiveThreads() next iteration 453 } 454 if ( daemonThreadJoinTimeout <= 0 ) 455 { 456 joinThread( thread, 0 ); //waits until not alive; no timeout 457 continue; 458 } 459 long timeout = daemonThreadJoinTimeout 460 - ( System.currentTimeMillis() - startTime ); 461 if ( timeout > 0 ) 462 { 463 joinThread( thread, timeout ); 464 } 465 if ( ! thread.isAlive() ) 466 { 467 continue; 468 } 469 uncooperativeThreads.add( thread ); // ensure we don't process again 470 if ( stopUnresponsiveDaemonThreads ) 471 { 472 getLog().warn( "thread " + thread + " will be Thread.stop()'ed" ); 473 thread.stop(); 474 } 475 else 476 { 477 getLog().warn( "thread " + thread + " will linger despite being asked to die via interruption" ); 478 } 479 } 480 } 481 if ( ! uncooperativeThreads.isEmpty() ) 482 { 483 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 int activeCount = threadGroup.activeCount(); 490 if ( activeCount != 0 ) 491 { 492 // TODO this may be nothing; continue on anyway; perhaps don't even log in future 493 Thread[] threadsArray = new Thread[1]; 494 threadGroup.enumerate( threadsArray ); 495 getLog().debug( "strange; " + activeCount 496 + " thread(s) still active in the group " + threadGroup + " such as " + threadsArray[0] ); 497 } 498 } 499 } 500 501 private Collection getActiveThreads( ThreadGroup threadGroup ) 502 { 503 Thread[] threads = new Thread[ threadGroup.activeCount() ]; 504 int numThreads = threadGroup.enumerate( threads ); 505 Collection result = new ArrayList( numThreads ); 506 for ( int i = 0; i < threads.length && threads[i] != null; i++ ) 507 { 508 result.add( threads[i] ); 509 } 510 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 if ( systemProperties != null ) 519 { 520 originalSystemProperties = System.getProperties(); 521 for ( int i = 0; i < systemProperties.length; i++ ) 522 { 523 Property systemProperty = systemProperties[i]; 524 String value = systemProperty.getValue(); 525 System.setProperty( systemProperty.getKey(), value == null ? "" : value ); 526 } 527 } 528 } 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 List classpathURLs = new ArrayList(); 540 this.addRelevantPluginDependenciesToClasspath( classpathURLs ); 541 this.addRelevantProjectDependenciesToClasspath( classpathURLs ); 542 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 if ( hasCommandlineArgs() ) 556 { 557 arguments = parseCommandlineArgs(); 558 } 559 560 try 561 { 562 Iterator iter = this.determineRelevantPluginDependencies().iterator(); 563 while ( iter.hasNext() ) 564 { 565 Artifact classPathElement = (Artifact) iter.next(); 566 getLog().debug( 567 "Adding plugin dependency artifact: " + classPathElement.getArtifactId() + " to classpath" ); 568 path.add( classPathElement.getFile().toURI().toURL() ); 569 } 570 } 571 catch ( MalformedURLException e ) 572 { 573 throw new MojoExecutionException( "Error during setting up classpath", e ); 574 } 575 576 } 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 if ( this.includeProjectDependencies ) 589 { 590 try 591 { 592 getLog().debug( "Project Dependencies will be included." ); 593 594 List artifacts = new ArrayList(); 595 List theClasspathFiles = new ArrayList(); 596 597 collectProjectArtifactsAndClasspath( artifacts, theClasspathFiles ); 598 599 for ( Iterator it = theClasspathFiles.iterator(); it.hasNext(); ) 600 { 601 URL url = ( (File) it.next() ).toURI().toURL(); 602 getLog().debug( "Adding to classpath : " + url ); 603 path.add( url ); 604 } 605 606 Iterator iter = artifacts.iterator(); 607 while ( iter.hasNext() ) 608 { 609 Artifact classPathElement = (Artifact) iter.next(); 610 getLog().debug( 611 "Adding project dependency artifact: " + classPathElement.getArtifactId() + " to classpath" ); 612 path.add( classPathElement.getFile().toURI().toURL() ); 613 } 614 615 } 616 catch ( MalformedURLException e ) 617 { 618 throw new MojoExecutionException( "Error during setting up classpath", e ); 619 } 620 } 621 else 622 { 623 getLog().debug( "Project Dependencies will be excluded." ); 624 } 625 626 } 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 if ( this.includePluginDependencies ) 641 { 642 if ( this.executableDependency == null ) 643 { 644 getLog().debug( "All Plugin Dependencies will be included." ); 645 relevantDependencies = new HashSet( this.pluginDependencies ); 646 } 647 else 648 { 649 getLog().debug( "Selected plugin Dependencies will be included." ); 650 Artifact executableArtifact = this.findExecutableArtifact(); 651 Artifact executablePomArtifact = this.getExecutablePomArtifact( executableArtifact ); 652 relevantDependencies = this.resolveExecutableDependencies( executablePomArtifact ); 653 } 654 } 655 else 656 { 657 relevantDependencies = Collections.EMPTY_SET; 658 getLog().debug( "Plugin Dependencies will be excluded." ); 659 } 660 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 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 Artifact executableTool = null; 688 for ( Iterator iter = this.pluginDependencies.iterator(); iter.hasNext(); ) 689 { 690 Artifact pluginDep = (Artifact) iter.next(); 691 if ( this.executableDependency.matches( pluginDep ) ) 692 { 693 executableTool = pluginDep; 694 break; 695 } 696 } 697 698 if ( executableTool == null ) 699 { 700 throw new MojoExecutionException( 701 "No dependency of the plugin matches the specified executableDependency." 702 + " Specified executableToolAssembly is: " + executableDependency.toString() ); 703 } 704 705 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 MavenProject executableProject = this.projectBuilder.buildFromRepository( executablePomArtifact, 722 this.remoteRepositories, 723 this.localRepository ); 724 725 //get all of the dependencies for the executable project 726 List dependencies = executableProject.getDependencies(); 727 728 //make Artifacts of all the dependencies 729 Set dependencyArtifacts = 730 MavenMetadataSource.createArtifacts( this.artifactFactory, dependencies, null, null, null ); 731 732 //not forgetting the Artifact of the project itself 733 dependencyArtifacts.add( executableProject.getArtifact() ); 734 735 //resolve all dependencies transitively to obtain a comprehensive list of assemblies 736 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 executableDependencies = result.getArtifacts(); 744 745 } 746 catch ( Exception ex ) 747 { 748 throw new MojoExecutionException( 749 "Encountered problems resolving dependencies of the executable " + "in preparation for its execution.", 750 ex ); 751 } 752 753 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 Object lock = new Object(); 765 synchronized ( lock ) 766 { 767 try 768 { 769 lock.wait( millis ); 770 } 771 catch ( InterruptedException e ) 772 { 773 Thread.currentThread().interrupt(); // good practice if don't throw 774 getLog().warn( "Spuriously interrupted while waiting for " + millis + "ms", e ); 775 } 776 } 777 } 778 779 }