{% extends "../../layout.html" %} {% block sectionClasses %}plugins hasBreadCrumb plugins-spincast-process-utils{% endblock %} {% block meta_title %}Plugins - Spincast Process Utils{% endblock %} {% block meta_description %}Spincast Process Utils plugin - utilities related to processes and external programs manipulation{% endblock %} {% block scripts %} {% endblock %} {% block body %}
This plugin contains utilities to help manipulate processes and external programs.
It allows you to easily compile/package/install a Maven project
located outside your application. It also provides a way to programmatically launch and
control an executable .jar file.
The utilities provided by this plugin are available through the SpincastProcessUtils interface, which you can inject wherever you want.
The executeGoalOnExternalMavenProject(...) method allows you to programmatically compile, package or install a Maven project located outside of your application.
This feature can be useful for example to run tests that need to validate code from inside a .jar file.
The signature of this method is:
{% verbatim %}
public File executeGoalOnExternalMavenProject(ResourceInfo projectRootInfo,
MavenProjectGoal mavenGoal,
Map<String,Object> pomParams);
{% endverbatim %}
Using this method you can:
compile, package or install goal on a Maven
project located:
pom.xml, before
executing the Maven goal. The replacement is done using the Templating Engine.
Note that this method returns the root directory of the Maven project. If the project is extracted from
the classpath, this directory is going to be created under the
Temporary Directory.
If the project is already on the file system, it will return its root directory, as is.
Let's look at an example where we run the package goal on a Maven project located
on the classpath (the project would be provided by your application at "src/main/resources/myMavenProject"):
{% verbatim %}
String spincastVersion = getSpincastUtils().getSpincastCurrentVersion();
File projectDir = getSpincastProcessUtils()
.executeGoalOnExternalMavenProject(new ResourceInfo("/myMavenProject", true),
MavenProjectGoal.PACKAGE,
SpincastStatics.map("spincastVersion",
spincastVersion));
File jarFile = new File(projectDir,
"target/project-artifact-name-" + spincastVersion + ".jar");
assertTrue(jarFile.isFile());
{% endverbatim %}
Explanation :
pom.xml file with this version.
executeGoalOnExternalMavenProject() method.
The first parameter is the path to the Maven project. Here, the project is on the classpath ("true").
goal to run. In this example, we will call
the "package" goal so the .jar associated with this project is generated.
pom.xml file (the Templating Engine is used
to do so).
.jar file has been successfully generated!
Have a look at this test
for a real example of running a goal on an external Maven project.
The executeJar(...)
method allows you to run an external executable .jar file and to keep control over the process.
It starts the target .jar file using java -jar yourJar.jar arg1 arg2 arg3 ...
Here is the signature of the method:
{% verbatim %}
public void executeJar(String jarFilePath,
List<String> args,
JarExecutionHandler handler)
{% endverbatim %}
Explanation :
.jar
file to run, on the file system.
.jar
when executing it.
The JarExecutionHandler
instance you pass to the method allows you to control the process that is going to be started to run the .jar file.
The default
implementation is JarExecutionHandlerDefault
and you can, of course, extend it.
The main methods of the handler are:
Process getJarProcess()
To get direct access to the Process started to execute the .jar file.
void onException(Exception ex)
This method is going to be called if an exception occurs during the launch of the executable .jar file. The default method, in JarExecutionHandlerDefault, will catch the exception, will make sure the process is killed properly, and will then rethrow the exception.
void onExit(int exitVal)
This method will be called when the process exits. If it exits by itself, without any error,
exitVal will in general be "0".
Note that if you execute a .jar file that doesn't exit by itself (for example an HTTP server is started by the .jar file), you have to explicitly kill the process.
The default implementation for this method simply logs the exit value.
void killJarProcess()
Kills the .jar process.
If it is not able to kill it, for any reason, an exception is thrown.
void waitForPortOpen(String host, int port, int nbrTry, int sleepMilliseconds)
This method, provided by JarExecutionHandlerDefault,
allows you to wait for a port to be available. This is useful when the
executable .jar file starts an HTTP server and you need to wait for it to be ready.
If the port is still not available after nbrTry * sleepMilliseconds, a
PortNotOpenException
exception is thrown.
You can create a custom implementation of JarExecutionHandler
to be used as the handler. This gives you control over how errors and exit codes are dealt with.
Your implementation can extend the default
JarExecutionHandlerDefault
implementation.
If you need to specify the full path to the java binary to be used to execute the
.jar file ("/usr/bin/java" for example), you can do so using
this overload.
Otherwise, "java" is used, as is, and must be on your PATH.
Finally, note that if you run an executable .jar file that doesn't exit by itself (for example
it starts an HTTP server that listens forever for requests), you are responsible
to kill the process when you are done with it, by calling killJarProcess().
This can be done using a try/finally block:
{% verbatim %}
JarExecutionHandlerDefault handler = new JarExecutionHandlerDefault();
// Start an executable jar on port 12345
getSpincastProcessUtils().executeJar("/some/path.jar",
Lists.newArrayList("12345")),
handler);
try {
// Wait for the port 12345 to be open
handler.waitForPortOpen("localhost", 12345, 5, 1000);
// Make a request to the HTTP server started by the .jar file
HttpResponse response = getHttpClient().GET("http://localhost:12345").send();
assertEquals(HttpStatus.SC_OK, response.getStatus());
// ...
} finally {
// Kill the process when we are done with it!
handler.killJarProcess();
}
{% endverbatim %}
1. Add this Maven artifact to your project:
<dependency>
<groupId>org.spincast</groupId>
<artifactId>spincast-plugins-process-utils</artifactId>
<version>{{spincast.spincastCurrrentVersion}}</version>
</dependency>
2. Add an instance of the SpincastProcessUtilsPlugin plugin to your Spincast Bootstrapper: {% verbatim %}
Spincast.configure()
.plugin(new SpincastProcessUtilsPlugin())
// ...