| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.camel.guice.maven; |
| |
| import java.io.File; |
| import java.lang.reflect.Method; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| import org.apache.camel.util.CastUtils; |
| import org.apache.maven.artifact.Artifact; |
| import org.apache.maven.artifact.factory.ArtifactFactory; |
| import org.apache.maven.artifact.metadata.ArtifactMetadataSource; |
| import org.apache.maven.artifact.repository.ArtifactRepository; |
| import org.apache.maven.artifact.resolver.ArtifactResolutionResult; |
| import org.apache.maven.artifact.resolver.ArtifactResolver; |
| import org.apache.maven.artifact.resolver.filter.ArtifactFilter; |
| import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter; |
| import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; |
| import org.apache.maven.artifact.versioning.VersionRange; |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.Exclusion; |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.plugin.MojoFailureException; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.maven.project.MavenProjectBuilder; |
| import org.apache.maven.project.artifact.MavenMetadataSource; |
| import org.codehaus.mojo.exec.AbstractExecMojo; |
| import org.codehaus.mojo.exec.ExecutableDependency; |
| import org.codehaus.mojo.exec.Property; |
| |
| /** |
| * Runs a Camel using the |
| * <code>jndi.properties</code> file on the classpath as the |
| * way to <a href="http://camel.apache.org/guice.html">bootstrap Camel using Guice</a> |
| * |
| * @goal run |
| * @requiresDependencyResolution runtime |
| * @execute phase="test-compile" |
| */ |
| public class RunMojo extends AbstractExecMojo { |
| |
| // TODO |
| // this code is based on a copy-and-paste of maven-exec-plugin |
| // |
| // If we could avoid the mega-cut-n-paste it would really really help! |
| // ideally all I wanna do is auto-default 2 values! |
| // namely the main and the command line arguments.. |
| |
| /** |
| * The maven project. |
| * |
| * @parameter property="project" |
| * @required |
| * @readonly |
| */ |
| protected MavenProject project; |
| |
| /** |
| * The duration to run the application for which by default is in |
| * milliseconds. A value <= 0 will run forever. |
| * Adding a s indicates seconds - eg "5s" means 5 seconds. |
| * |
| * @parameter property="-1" |
| * |
| */ |
| protected String duration; |
| |
| /** |
| * The DOT output directory name used to generate the DOT diagram of the |
| * route definitions |
| * |
| * @parameter default-value="${project.build.directory}/site/cameldoc" |
| * @readonly |
| */ |
| protected String dotDir; |
| |
| /** |
| * Allows the DOT file generation to be disabled |
| * |
| * @parameter property="true" |
| * @readonly |
| */ |
| protected boolean dotEnabled; |
| |
| /** |
| * @component |
| */ |
| private ArtifactResolver artifactResolver; |
| |
| /** |
| * @component |
| */ |
| private ArtifactFactory artifactFactory; |
| |
| /** |
| * @component |
| */ |
| private ArtifactMetadataSource metadataSource; |
| |
| /** |
| * @parameter property="localRepository" |
| * @required |
| * @readonly |
| */ |
| private ArtifactRepository localRepository; |
| |
| /** |
| * @parameter property="project.remoteArtifactRepositories" |
| */ |
| private List<?> remoteRepositories; |
| |
| /** |
| * @component |
| */ |
| private MavenProjectBuilder projectBuilder; |
| |
| /** |
| * @parameter property="plugin.artifacts" |
| * @readonly |
| */ |
| private List<Artifact> pluginDependencies; |
| |
| /** |
| * Whether to enable the debugger or not |
| * |
| * @parameter property="camel.debug" |
| * default-value="false" |
| * @required |
| */ |
| private boolean debug; |
| |
| /** |
| * Whether to enable the tracer or not |
| * |
| * @parameter property="camel.trace" |
| * default-value="false" |
| * @required |
| */ |
| private boolean trace; |
| |
| /** |
| * Output all routes to the specified XML file |
| * |
| * @parameter property="camel.routesOutputFile" |
| */ |
| private String routesOutputFile; |
| |
| /** |
| * The main class to execute. |
| * |
| * @parameter property="camel.mainClass" |
| * default-value="org.apache.camel.guice.Main" |
| * @required |
| */ |
| private String mainClass; |
| |
| /** |
| * The class arguments. |
| * |
| * @parameter property="camel.arguments" |
| */ |
| private String[] arguments; |
| |
| /** |
| * A list of system properties to be passed. Note: as the execution is not |
| * forked, some system properties required by the JVM cannot be passed here. |
| * Use MAVEN_OPTS or the exec:exec instead. See the user guide for more |
| * information. |
| * |
| * @parameter |
| */ |
| private Property[] systemProperties; |
| |
| /** |
| * Deprecated; this is not needed anymore. Indicates if mojo should be kept |
| * running after the mainclass terminates. Usefull for serverlike apps with |
| * deamonthreads. |
| * |
| * @parameter property="camel.keepAlive" default-value="false" |
| */ |
| private boolean keepAlive; |
| |
| /** |
| * Indicates if the project dependencies should be used when executing the |
| * main class. |
| * |
| * @parameter property="camel.includeProjectDependencies" |
| * default-value="true" |
| */ |
| private boolean includeProjectDependencies; |
| |
| /** |
| * Indicates if this plugin's dependencies should be used when executing the |
| * main class. <p/> This is useful when project dependencies are not |
| * appropriate. Using only the plugin dependencies can be particularly |
| * useful when the project is not a java project. For example a mvn project |
| * using the csharp plugins only expects to see dotnet libraries as |
| * dependencies. |
| * |
| * @parameter property="camel.includePluginDependencies" |
| * default-value="false" |
| */ |
| private boolean includePluginDependencies; |
| |
| /** |
| * If provided the ExecutableDependency identifies which of the plugin |
| * dependencies contains the executable class. This will have the affect of |
| * only including plugin dependencies required by the identified |
| * ExecutableDependency. <p/> If includeProjectDependencies is set to |
| * <code>true</code>, all of the project dependencies will be included on |
| * the executable's classpath. Whether a particular project dependency is a |
| * dependency of the identified ExecutableDependency will be irrelevant to |
| * its inclusion in the classpath. |
| * |
| * @parameter |
| * @optional |
| */ |
| private ExecutableDependency executableDependency; |
| |
| /** |
| * Wether to interrupt/join and possibly stop the daemon threads upon |
| * quitting. <br/> If this is <code>false</code>, maven does nothing |
| * about the daemon threads. When maven has no more work to do, the VM will |
| * normally terminate any remaining daemon threads. |
| * <p> |
| * In certain cases (in particular if maven is embedded), you might need to |
| * keep this enabled to make sure threads are properly cleaned up to ensure |
| * they don't interfere with subsequent activity. In that case, see |
| * {@link #daemonThreadJoinTimeout} and |
| * {@link #stopUnresponsiveDaemonThreads} for further tuning. |
| * </p> |
| * |
| * @parameter property="camel.cleanupDaemonThreads" default-value="true" |
| */ |
| private boolean cleanupDaemonThreads; |
| |
| /** |
| * This defines the number of milliseconds to wait for daemon threads to |
| * quit following their interruption.<br/> This is only taken into account |
| * if {@link #cleanupDaemonThreads} is <code>true</code>. A value <=0 |
| * means to not timeout (i.e. wait indefinitely for threads to finish). |
| * Following a timeout, a warning will be logged. |
| * <p> |
| * Note: properly coded threads <i>should</i> terminate upon interruption |
| * but some threads may prove problematic: as the VM does interrupt daemon |
| * threads, some code may not have been written to handle interruption |
| * properly. For example java.util.Timer is known to not handle |
| * interruptions in JDK <= 1.6. So it is not possible for us to |
| * infinitely wait by default otherwise maven could hang. A sensible default |
| * value has been chosen, but this default value <i>may change</i> in the |
| * future based on user feedback. |
| * </p> |
| * |
| * @parameter property="camel.daemonThreadJoinTimeout" |
| * default-value="15000" |
| */ |
| private long daemonThreadJoinTimeout; |
| |
| /** |
| * Wether to call {@link Thread#stop()} following a timing out of waiting |
| * for an interrupted thread to finish. This is only taken into account if |
| * {@link #cleanupDaemonThreads} is <code>true</code> and the |
| * {@link #daemonThreadJoinTimeout} threshold has been reached for an |
| * uncooperative thread. If this is <code>false</code>, or if |
| * {@link Thread#stop()} fails to get the thread to stop, then a warning is |
| * logged and Maven will continue on while the affected threads (and related |
| * objects in memory) linger on. Consider setting this to <code>true</code> |
| * if you are invoking problematic code that you can't fix. An example is |
| * {@link java.util.Timer} which doesn't respond to interruption. To have |
| * <code>Timer</code> fixed, vote for <a |
| * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6336543">this |
| * bug</a>. |
| * |
| * @parameter property="camel.stopUnresponsiveDaemonThreads" |
| * default-value="false" |
| */ |
| private boolean stopUnresponsiveDaemonThreads; |
| |
| /** |
| * Deprecated this is not needed anymore. |
| * |
| * @parameter property="camel.killAfter" default-value="-1" |
| */ |
| private long killAfter; |
| |
| private Properties originalSystemProperties; |
| |
| /** |
| * Execute goal. |
| * |
| * @throws org.apache.maven.plugin.MojoExecutionException execution of the main class or one of the |
| * threads it generated failed. |
| * @throws org.apache.maven.plugin.MojoFailureException something bad happened... |
| */ |
| public void execute() throws MojoExecutionException, MojoFailureException { |
| if (killAfter != -1) { |
| getLog().warn("Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6."); |
| } |
| |
| // lets create the command line arguments to pass in... |
| List<String> args = new ArrayList<String>(); |
| if (dotDir != null && dotEnabled) { |
| args.add("-o"); |
| args.add(dotDir); |
| } |
| if (debug) { |
| args.add("-x"); |
| } |
| if (trace) { |
| args.add("-t"); |
| } |
| |
| if (routesOutputFile != null) { |
| args.add("-output"); |
| args.add(routesOutputFile); |
| } |
| |
| args.add("-d"); |
| args.add(duration); |
| if (arguments != null) { |
| args.addAll(Arrays.asList(arguments)); |
| } |
| arguments = new String[args.size()]; |
| args.toArray(arguments); |
| |
| if (getLog().isDebugEnabled()) { |
| StringBuilder msg = new StringBuilder("Invoking : "); |
| msg.append(mainClass); |
| msg.append(".main("); |
| for (int i = 0; i < arguments.length; i++) { |
| if (i > 0) { |
| msg.append(", "); |
| } |
| msg.append(arguments[i]); |
| } |
| msg.append(")"); |
| getLog().debug(msg); |
| } |
| |
| IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(mainClass /* name */); |
| Thread bootstrapThread = new Thread(threadGroup, new Runnable() { |
| public void run() { |
| try { |
| Method main = Thread.currentThread().getContextClassLoader().loadClass(mainClass) |
| .getMethod("main", new Class[] {String[].class}); |
| if (!main.isAccessible()) { |
| getLog().debug("Setting accessibility to true in order to invoke main()."); |
| main.setAccessible(true); |
| } |
| main.invoke(main, new Object[] {arguments}); |
| } catch (Exception e) { // just pass it on |
| Thread.currentThread().getThreadGroup().uncaughtException(Thread.currentThread(), e); |
| } |
| } |
| }, mainClass + ".main()"); |
| bootstrapThread.setContextClassLoader(getClassLoader()); |
| setSystemProperties(); |
| |
| bootstrapThread.start(); |
| joinNonDaemonThreads(threadGroup); |
| // It's plausible that spontaneously a non-daemon thread might be |
| // created as we try and shut down, |
| // but it's too late since the termination condition (only daemon |
| // threads) has been triggered. |
| if (keepAlive) { |
| getLog().warn("Warning: keepAlive is now deprecated and obsolete. Do you need it? Please comment on MEXEC-6."); |
| waitFor(0); |
| } |
| |
| if (cleanupDaemonThreads) { |
| |
| terminateThreads(threadGroup); |
| |
| try { |
| threadGroup.destroy(); |
| } catch (IllegalThreadStateException e) { |
| getLog().warn("Couldn't destroy threadgroup " + threadGroup, e); |
| } |
| } |
| |
| if (originalSystemProperties != null) { |
| System.setProperties(originalSystemProperties); |
| } |
| |
| synchronized (threadGroup) { |
| if (threadGroup.uncaughtException != null) { |
| throw new MojoExecutionException(null, threadGroup.uncaughtException); |
| } |
| } |
| |
| registerSourceRoots(); |
| } |
| |
| class IsolatedThreadGroup extends ThreadGroup { |
| Throwable uncaughtException; // synchronize access to this |
| |
| public IsolatedThreadGroup(String name) { |
| super(name); |
| } |
| |
| public void uncaughtException(Thread thread, Throwable throwable) { |
| if (throwable instanceof ThreadDeath) { |
| return; // harmless |
| } |
| boolean doLog = false; |
| synchronized (this) { |
| // only remember the first one |
| if (uncaughtException == null) { |
| uncaughtException = throwable; // will be reported |
| // eventually |
| } else { |
| doLog = true; |
| } |
| } |
| if (doLog) { |
| getLog().warn("an additional exception was thrown", throwable); |
| } |
| } |
| } |
| |
| private void joinNonDaemonThreads(ThreadGroup threadGroup) { |
| boolean foundNonDaemon; |
| do { |
| foundNonDaemon = false; |
| Collection<Thread> threads = getActiveThreads(threadGroup); |
| for (Thread thread : threads) { |
| if (thread.isDaemon()) { |
| continue; |
| } |
| foundNonDaemon = true; // try again; maybe more threads were |
| // created while we were busy |
| joinThread(thread, 0); |
| } |
| } while (foundNonDaemon); |
| } |
| |
| private void joinThread(Thread thread, long timeoutMsecs) { |
| try { |
| getLog().debug("joining on thread " + thread); |
| thread.join(timeoutMsecs); |
| } catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); // good practice if don't throw |
| getLog().warn("interrupted while joining against thread " + thread, e); // not |
| // expected! |
| } |
| // generally abnormal |
| if (thread.isAlive()) { |
| getLog().warn("thread " + thread + " was interrupted but is still alive after waiting at least " |
| + timeoutMsecs + "msecs"); |
| } |
| } |
| |
| @SuppressWarnings("deprecation") |
| private void terminateThreads(ThreadGroup threadGroup) { |
| long startTime = System.currentTimeMillis(); |
| Set<Thread> uncooperativeThreads = new HashSet<Thread>(); // these were not responsive |
| // to interruption |
| for (Collection<Thread> threads = getActiveThreads(threadGroup); !threads.isEmpty(); threads = getActiveThreads(threadGroup), threads |
| .removeAll(uncooperativeThreads)) { |
| // Interrupt all threads we know about as of this instant (harmless |
| // if spuriously went dead (! isAlive()) |
| // or if something else interrupted it ( isInterrupted() ). |
| for (Thread thread : threads) { |
| getLog().debug("interrupting thread " + thread); |
| thread.interrupt(); |
| } |
| // Now join with a timeout and call stop() (assuming flags are set |
| // right) |
| for (Thread thread : threads) { |
| if (!thread.isAlive()) { |
| continue; // and, presumably it won't show up in |
| // getActiveThreads() next iteration |
| } |
| if (daemonThreadJoinTimeout <= 0) { |
| joinThread(thread, 0); // waits until not alive; no timeout |
| continue; |
| } |
| long timeout = daemonThreadJoinTimeout - (System.currentTimeMillis() - startTime); |
| if (timeout > 0) { |
| joinThread(thread, timeout); |
| } |
| if (!thread.isAlive()) { |
| continue; |
| } |
| uncooperativeThreads.add(thread); // ensure we don't process |
| // again |
| if (stopUnresponsiveDaemonThreads) { |
| getLog().warn("thread " + thread + " will be Thread.stop()'ed"); |
| thread.stop(); |
| } else { |
| getLog().warn("thread " + thread |
| + " will linger despite being asked to die via interruption"); |
| } |
| } |
| } |
| if (!uncooperativeThreads.isEmpty()) { |
| getLog().warn("NOTE: " |
| + uncooperativeThreads.size() |
| + " thread(s) did not finish despite being asked to " |
| + " via interruption. This is not a problem with exec:java, it is a problem with the running code." |
| + " Although not serious, it should be remedied."); |
| } else { |
| int activeCount = threadGroup.activeCount(); |
| if (activeCount != 0) { |
| // TODO this may be nothing; continue on anyway; perhaps don't |
| // even log in future |
| Thread[] threadsArray = new Thread[1]; |
| threadGroup.enumerate(threadsArray); |
| getLog().debug("strange; " + activeCount + " thread(s) still active in the group " |
| + threadGroup + " such as " + threadsArray[0]); |
| } |
| } |
| } |
| |
| private Collection<Thread> getActiveThreads(ThreadGroup threadGroup) { |
| Thread[] threads = new Thread[threadGroup.activeCount()]; |
| int numThreads = threadGroup.enumerate(threads); |
| Collection<Thread> result = new ArrayList<Thread>(numThreads); |
| for (int i = 0; i < threads.length && threads[i] != null; i++) { |
| result.add(threads[i]); |
| } |
| // note: result should be modifiable |
| return result; |
| } |
| |
| /** |
| * Pass any given system properties to the java system properties. |
| */ |
| private void setSystemProperties() { |
| if (systemProperties != null) { |
| originalSystemProperties = System.getProperties(); |
| for (Property systemProperty : systemProperties) { |
| String value = systemProperty.getValue(); |
| System.setProperty(systemProperty.getKey(), value == null ? "" : value); |
| } |
| } |
| } |
| |
| /** |
| * Set up a classloader for the execution of the main class. |
| * |
| * @return the classloader |
| * @throws org.apache.maven.plugin.MojoExecutionException |
| */ |
| private ClassLoader getClassLoader() throws MojoExecutionException { |
| List<URL> classpathURLs = new ArrayList<URL>(); |
| this.addRelevantPluginDependenciesToClasspath(classpathURLs); |
| this.addRelevantProjectDependenciesToClasspath(classpathURLs); |
| |
| getLog().info("Classpath = " + classpathURLs); |
| return new URLClassLoader(classpathURLs.toArray(new URL[classpathURLs.size()])); |
| } |
| |
| /** |
| * Add any relevant project dependencies to the classpath. Indirectly takes |
| * includePluginDependencies and ExecutableDependency into consideration. |
| * |
| * @param path classpath of {@link java.net.URL} objects |
| * @throws org.apache.maven.plugin.MojoExecutionException |
| */ |
| private void addRelevantPluginDependenciesToClasspath(List<URL> path) throws MojoExecutionException { |
| if (hasCommandlineArgs()) { |
| arguments = parseCommandlineArgs(); |
| } |
| |
| try { |
| Iterator<Artifact> iter = this.determineRelevantPluginDependencies().iterator(); |
| while (iter.hasNext()) { |
| Artifact classPathElement = iter.next(); |
| getLog().debug("Adding plugin dependency artifact: " + classPathElement.getArtifactId() |
| + " to classpath"); |
| path.add(classPathElement.getFile().toURI().toURL()); |
| } |
| } catch (MalformedURLException e) { |
| throw new MojoExecutionException("Error during setting up classpath", e); |
| } |
| |
| } |
| |
| /** |
| * Add any relevant project dependencies to the classpath. Takes |
| * includeProjectDependencies into consideration. |
| * |
| * @param path classpath of {@link java.net.URL} objects |
| * @throws org.apache.maven.plugin.MojoExecutionException |
| */ |
| private void addRelevantProjectDependenciesToClasspath(List<URL> path) throws MojoExecutionException { |
| if (this.includeProjectDependencies) { |
| try { |
| getLog().debug("Project Dependencies will be included."); |
| |
| URL mainClasses = new File(project.getBuild().getOutputDirectory()).toURI().toURL(); |
| getLog().debug("Adding to classpath : " + mainClasses); |
| path.add(mainClasses); |
| |
| Set<Artifact> dependencies = CastUtils.cast(project.getArtifacts()); |
| |
| // system scope dependencies are not returned by maven 2.0. See |
| // MEXEC-17 |
| dependencies.addAll(getAllNonTestScopedDependencies()); |
| |
| Iterator<Artifact> iter = dependencies.iterator(); |
| while (iter.hasNext()) { |
| Artifact classPathElement = iter.next(); |
| getLog().debug("Adding project dependency artifact: " + classPathElement.getArtifactId() |
| + " to classpath"); |
| File file = classPathElement.getFile(); |
| if (file != null) { |
| path.add(file.toURI().toURL()); |
| } |
| } |
| |
| } catch (MalformedURLException e) { |
| throw new MojoExecutionException("Error during setting up classpath", e); |
| } |
| } else { |
| getLog().debug("Project Dependencies will be excluded."); |
| } |
| |
| } |
| |
| private Collection<Artifact> getAllNonTestScopedDependencies() throws MojoExecutionException { |
| List<Artifact> answer = new ArrayList<Artifact>(); |
| |
| for (Artifact artifact : getAllDependencies()) { |
| |
| // do not add test artifacts |
| if (!artifact.getScope().equals(Artifact.SCOPE_TEST)) { |
| answer.add(artifact); |
| } |
| } |
| return answer; |
| } |
| |
| // generic method to retrieve all the transitive dependencies |
| private Collection<Artifact> getAllDependencies() throws MojoExecutionException { |
| List<Artifact> artifacts = new ArrayList<Artifact>(); |
| |
| for (Iterator<?> dependencies = project.getDependencies().iterator(); dependencies.hasNext();) { |
| Dependency dependency = (Dependency)dependencies.next(); |
| |
| String groupId = dependency.getGroupId(); |
| String artifactId = dependency.getArtifactId(); |
| |
| VersionRange versionRange; |
| try { |
| versionRange = VersionRange.createFromVersionSpec(dependency.getVersion()); |
| } catch (InvalidVersionSpecificationException e) { |
| throw new MojoExecutionException("unable to parse version", e); |
| } |
| |
| String type = dependency.getType(); |
| if (type == null) { |
| type = "jar"; |
| } |
| String classifier = dependency.getClassifier(); |
| boolean optional = dependency.isOptional(); |
| String scope = dependency.getScope(); |
| if (scope == null) { |
| scope = Artifact.SCOPE_COMPILE; |
| } |
| |
| Artifact art = this.artifactFactory.createDependencyArtifact(groupId, artifactId, versionRange, |
| type, classifier, scope, null, optional); |
| |
| if (scope.equalsIgnoreCase(Artifact.SCOPE_SYSTEM)) { |
| art.setFile(new File(dependency.getSystemPath())); |
| } |
| |
| List<String> exclusions = new ArrayList<String>(); |
| for (Iterator<?> j = dependency.getExclusions().iterator(); j.hasNext();) { |
| Exclusion e = (Exclusion)j.next(); |
| exclusions.add(e.getGroupId() + ":" + e.getArtifactId()); |
| } |
| |
| ArtifactFilter newFilter = new ExcludesArtifactFilter(exclusions); |
| |
| art.setDependencyFilter(newFilter); |
| |
| artifacts.add(art); |
| } |
| |
| return artifacts; |
| } |
| |
| /** |
| * Determine all plugin dependencies relevant to the executable. Takes |
| * includePlugins, and the executableDependency into consideration. |
| * |
| * @return a set of Artifact objects. (Empty set is returned if there are no |
| * relevant plugin dependencies.) |
| * @throws org.apache.maven.plugin.MojoExecutionException |
| */ |
| private Set<Artifact> determineRelevantPluginDependencies() throws MojoExecutionException { |
| Set<Artifact> relevantDependencies; |
| if (this.includePluginDependencies) { |
| if (this.executableDependency == null) { |
| getLog().debug("All Plugin Dependencies will be included."); |
| relevantDependencies = new HashSet<Artifact>(this.pluginDependencies); |
| } else { |
| getLog().debug("Selected plugin Dependencies will be included."); |
| Artifact executableArtifact = this.findExecutableArtifact(); |
| Artifact executablePomArtifact = this.getExecutablePomArtifact(executableArtifact); |
| relevantDependencies = this.resolveExecutableDependencies(executablePomArtifact); |
| } |
| } else { |
| relevantDependencies = Collections.emptySet(); |
| getLog().debug("Plugin Dependencies will be excluded."); |
| } |
| return relevantDependencies; |
| } |
| |
| /** |
| * Get the artifact which refers to the POM of the executable artifact. |
| * |
| * @param executableArtifact this artifact refers to the actual assembly. |
| * @return an artifact which refers to the POM of the executable artifact. |
| */ |
| private Artifact getExecutablePomArtifact(Artifact executableArtifact) { |
| return this.artifactFactory.createBuildArtifact(executableArtifact.getGroupId(), executableArtifact |
| .getArtifactId(), executableArtifact.getVersion(), "pom"); |
| } |
| |
| /** |
| * Examine the plugin dependencies to find the executable artifact. |
| * |
| * @return an artifact which refers to the actual executable tool (not a POM) |
| * @throws org.apache.maven.plugin.MojoExecutionException |
| */ |
| private Artifact findExecutableArtifact() throws MojoExecutionException { |
| // ILimitedArtifactIdentifier execToolAssembly = |
| // this.getExecutableToolAssembly(); |
| |
| Artifact executableTool = null; |
| for (Artifact pluginDep : this.pluginDependencies) { |
| if (this.executableDependency.matches(pluginDep)) { |
| executableTool = pluginDep; |
| break; |
| } |
| } |
| |
| if (executableTool == null) { |
| throw new MojoExecutionException("No dependency of the plugin matches the specified executableDependency." |
| + " Specified executableToolAssembly is: " |
| + executableDependency.toString()); |
| } |
| |
| return executableTool; |
| } |
| |
| private Set<Artifact> resolveExecutableDependencies(Artifact executablePomArtifact) throws MojoExecutionException { |
| |
| Set<Artifact> executableDependencies; |
| try { |
| MavenProject executableProject = this.projectBuilder.buildFromRepository(executablePomArtifact, |
| this.remoteRepositories, |
| this.localRepository); |
| |
| // get all of the dependencies for the executable project |
| List<Artifact> dependencies = CastUtils.cast(executableProject.getDependencies()); |
| |
| // make Artifacts of all the dependencies |
| Set<Artifact> dependencyArtifacts |
| = CastUtils.cast(MavenMetadataSource.createArtifacts(this.artifactFactory, dependencies, |
| null, null, null)); |
| |
| // not forgetting the Artifact of the project itself |
| dependencyArtifacts.add(executableProject.getArtifact()); |
| |
| // resolve all dependencies transitively to obtain a comprehensive |
| // list of assemblies |
| ArtifactResolutionResult result = artifactResolver.resolveTransitively(dependencyArtifacts, |
| executablePomArtifact, |
| Collections.EMPTY_MAP, |
| this.localRepository, |
| this.remoteRepositories, |
| metadataSource, null, |
| Collections.EMPTY_LIST); |
| executableDependencies = CastUtils.cast(result.getArtifacts()); |
| |
| } catch (Exception ex) { |
| throw new MojoExecutionException("Encountered problems resolving dependencies of the executable " |
| + "in preparation for its execution.", ex); |
| } |
| |
| return executableDependencies; |
| } |
| |
| /** |
| * Stop program execution for nn millis. |
| * |
| * @param millis the number of millis-seconds to wait for, <code>0</code> |
| * stops program forever. |
| */ |
| private void waitFor(long millis) { |
| Object lock = new Object(); |
| synchronized (lock) { |
| try { |
| lock.wait(millis); |
| } catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); // good practice if don't throw |
| getLog().warn("Spuriously interrupted while waiting for " + millis + "ms", e); |
| } |
| } |
| } |
| |
| } |