Fxlauncher is a auto updating launcher for javafx programs. Download a small jar (around 18Kb), start it and it will download the actual application and run it. Every time you start the small jar it will check if there is a newer version and download it automatically. So fxlauncher is a fun project and it will make keeping a desktop application uptodate easy. Setting up fxlauncher from Maven was not so easy. A plugin was needed.
requirements
The plugin needs to do the following:
- create the
app.xml
that is used to describe the application, its dependencies and several settings. - update
fxlauncher.jar
with app.xml - copy all the dependencies to a directory from where it can later be uploaded to a webserver
- upload to a webserver.
All these tasks can be done without writing a plugin for it and was how it was done untill now, this means several calls using the maven-exec-plugin
. The setup was huge.
I will not go into details about all of them, but I do want to highlight some interesting things I found while writing this.
Maven plugin documentation is bad
Subject says it all. I did not expect the documentation to be this bad. In the end I analyzed several well known plugins (the dependency plugin, the shade plugin and the jgitflow plugin) to see how a maven-plugin project is supposed to be setup. There is an archetype for it but I could not get that one to work. See pom.xml for how I set it.
java.nio.file.FileSystem is cool
To manipulate the fxlauncher.jar I decided to use the FileSystem that was introduced in Java7. This makes it very easy to add or delete files to, in this case, a jar file.
void addtoLauncher(String fileToAdd) throws MojoExecutionException {
getLog().info(String.format("placing %s in fxlauncher", fileToAdd));
Path path = Paths.get(String.format("%s/fxlauncher.jar", buildDir));
Map<String, String> props = new HashMap<>();
props.put("create", "false");
URI uri = URI.create("jar:" + path.toUri().toASCIIString());
try (FileSystem jarFile = FileSystems.newFileSystem(uri, props)) {
Path source = Paths.get(fileToAdd);
Path target = jarFile.getPath(String.valueOf(source.getFileName()));
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new MojoExecutionException("error in adding file to jar", e);
}
}
The heavy lifting is done in the try
block. There are several types of files you can open this way.
mojo-executor is cool too
Normally when you want to copy dependencies to a certain place you will setup the maven-dependency-plugin to do the heavy lifting for you. You would configure it in your pom.xml and tie it to a phase. I wanted however to be able to call the maven-dependency-plugin from another plugin. Luckily this is possible with the mojo-executor:
void copyDependencies() throws MojoExecutionException, IOException {
getLog().info("copying to " + buildDir);
executeMojo(
plugin(groupId("org.apache.maven.plugins"),
artifactId("maven-dependency-plugin"),
version("2.0")
),
goal("copy-dependencies"),
configuration(
element(name("outputDirectory"), buildDir)
),
executionEnvironment(
project,
session,
buildPluginManager
));
}
It doesn’t get much easier then this. I like the fluent like api.