google web font

среда, 26 августа 2015 г.

Shell executable jar


So, Java is rich on surpises, one can find some funny features in some pretty boring places. For instance, as boring as jar files.

Let's say, I 've got a jar which I run as usual:
java -jar my-fancy-app.jar
For this to work I need to add MainClass into manifest file, there is nothing to see there, except that jar files like this are called "executable" for some strange reason.

Then, if my program does something useful than it probably make use of some third-party libraries. And since I don't feel happy about annoying my users, I'd like to ship that libraries together with my application. Most common aproach is to use so-called "uber-jar" which contains third-party jars compiled into it. There is a maven plugin that can do so (sure, there is!), it installs it's own MainClass that installs it's own classloader and than yields for my MainClass. That classloader can load classes from jars inside the jar and is pretty much like one can find in the java tutorial from oracle.com.

While uber-jar is very convinient way for deploying an application, there are useful and important proprietary third-party libraries which have licences that don't allow me to bundle them inside my jar. And since one does not simply run java with both -jar and -cp options, I need a better solution. And there it is. I'd even say, sure there they are.
The truth is that I can simply add my jar to classpath and run java in a usual way: $ java -cp my-fancy-app.jar my.fancy.Application
Ok, of course it's not that simple, because I have that naughty proprietary library and also my jar is "uber-jar" with some extra MainClass which I need to run instead of my fancy one: $ java -cp that-proprietary-labrary.jar:my-fancy-app.jar org.springframework.boot.ICantRememberClassName
Good news is that it could be a one-liner shell script. Bad news is that I don't like having one-liners all over the place. So here comes the Feature.

I can just paste that one-liner into the jar file. Well, I can't just use vim, unless there is some fancy macro which I simply don't know about, so I have to do it like this:
$ cat > my-fancy-app <<EOF <target/my-fancy-app-1.0-SNAPSHOT.jar
> #!/bin/sh
> exec java -cp "that-proprietary-labrary.jar:\$0" org.springframework.boot.ICantRememberClassName
> EOF
What we've got here is a jar called my-fancy-app (no .jar extension) which is still "executable jar" one can run it with "java -jar" or "java -cp". But it is also an executable shell script that can be executed by simply calling ./my-fancy-app. Even more, it may be placed into /usr/bin and invoked as regular system application. One can even put it into /etc/init.d and use as an init-script for a system daemon, although one-liner wouldn't be enough to accomplish that. At a very least I can check that-proprietary-labrary.jar for existence ant gently ask my user to go and download it from the Internet.

So that's Java, having very strange limitations and even more strange workarounds. By the way, Spring Boot 1.3 provides this feature, allowing you to make jar-files with powerfull init-script bundled inside. I narrowed it down to one-liner just as to stress the point.

Комментариев нет:

Отправить комментарий