Clover Coverage Report - Exec Maven Plugin 1.1
Coverage timestamp: Wed Dec 31 1969 19:00:00 EST
../../../../img/srcFileCovDistChart0.png 0% of files have more coverage
183   779   68   10.76
84   470   0.37   8.5
17     4  
2    
 
  ExecJavaMojo       Line # 58 173 0% 63 266 0% 0.0
  ExecJavaMojo.IsolatedThreadGroup       Line # 358 10 0% 5 18 0% 0.0
 
No Tests
 
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    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  0 toggle 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    {
 
280  0 toggle public void run()
281    {
282  0 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    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    catch ( Exception e )
302    { // just pass it on
303  0 Thread.currentThread().getThreadGroup().uncaughtException( Thread.currentThread(), e );
304    }
305    }
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  0 try
327    {
328  0 threadGroup.destroy();
329    }
330    catch ( IllegalThreadStateException e )
331    {
332  0 getLog().warn( "Couldn't destroy threadgroup " + threadGroup, e );
333    }
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    }
351   
352  0 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  0 toggle public IsolatedThreadGroup( String name )
363    {
364  0 super( name );
365    }
366   
 
367  0 toggle 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    }
385  0 if ( doLog )
386    {
387  0 getLog().warn( "an additional exception was thrown", throwable );
388    }
389    }
390    }
391   
 
392  0 toggle private void joinNonDaemonThreads( ThreadGroup threadGroup )
393    {
394  0 boolean foundNonDaemon;
395  0 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    }
409  0 } while ( foundNonDaemon );
410    }
411   
 
412  0 toggle private void joinThread( Thread thread, long timeoutMsecs )
413    {
414  0 try
415    {
416  0 getLog().debug( "joining on thread " + thread );
417  0 thread.join( timeoutMsecs );
418    }
419    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    }
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    }
430   
 
431  0 toggle 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    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    }
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    }
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    }
500   
 
501  0 toggle 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  0 toggle 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    }
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  0 toggle 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  0 toggle private void addRelevantPluginDependenciesToClasspath( List path )
553    throws MojoExecutionException
554    {
555  0 if ( hasCommandlineArgs() )
556    {
557  0 arguments = parseCommandlineArgs();
558    }
559   
560  0 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    }
570    }
571    catch ( MalformedURLException e )
572    {
573  0 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  0 toggle private void addRelevantProjectDependenciesToClasspath( List path )
586    throws MojoExecutionException
587    {
588  0 if ( this.includeProjectDependencies )
589    {
590  0 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    }
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    }
614   
615    }
616    catch ( MalformedURLException e )
617    {
618  0 throw new MojoExecutionException( "Error during setting up classpath", e );
619    }
620    }
621    else
622    {
623  0 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  0 toggle private Set determineRelevantPluginDependencies()
637    throws MojoExecutionException
638    {
639  0 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    }
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  0 toggle 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  0 toggle 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    }
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  0 toggle private Set resolveExecutableDependencies( Artifact executablePomArtifact )
715    throws MojoExecutionException
716    {
717   
718  0 Set executableDependencies;
719  0 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    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    }
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  0 toggle private void waitFor( long millis )
763    {
764  0 Object lock = new Object();
765  0 synchronized ( lock )
766    {
767  0 try
768    {
769  0 lock.wait( millis );
770    }
771    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    }
776    }
777    }
778   
779    }