How to use the new Java buildpack with jar based applications?

503 views
Skip to first unread message

davidi...@gmail.com

unread,
Sep 3, 2013, 2:16:22 PM9/3/13
to vcap...@cloudfoundry.org
Hi,
With the current java buildpack I can take my existing build which generates a zip containing jars (a main jar and dependencies), specify
command: java -Xmx64m -Xms64m -jar jarname.jar
in the manifest.yml and push.

This doesn't seem to work with the new buildpack because it doesn't detect based on .jar

How are jar based apps (of the java main class style) supposed to work with the new buildpack?

Cheers,
David

Ben Hale

unread,
Sep 4, 2013, 8:29:38 AM9/4/13
to vcap...@cloudfoundry.org, davidi...@gmail.com
David,

You are correct that the new buildpack doesn't detect the presence of .jar files.  Instead it makes the assumption that if you're pushing a JAR, Cloud Foundry's support for exploding archives comes into play and we end up with a filesystem that has a bunch of .class, .groovy, etc. that it'll detect and work against.  In the case of Java main() applications, this results in a filesystem that contains a /META-INF/MANIFEST.MF which we then examine for the Main-Class attribute.  Now clearly your application doesn't fit this pattern as it's an archive within an archive (Cloud Foundry doesn't expand the inner archive) which is why it is not being detected.  The closest analog that we've got to this is Spring Boot applications that are packaged as self-executing JAR files.  They package their dependency JARs within themselves and use a special loader mechanism to get everything onto the classpath.  Ideally, this would be how we'd like all applications to work (it fits better with the Cloud Foundry model and doesn't require us to do any guesswork), but you've got an application that used to work but doesn't any longer, so let's take a look at what we can do.

My understanding from your email is that the ZIP file contains all of the dependencies for the primary JAR, however in your example custom command you don't seem to mention them.  How are you getting those JARs onto the classpath, Class-Path manifest entries?  In addition, how is the primary JAR uniquely identified; is it semantic knowledge about the application, the only one with a Main-Class manifest entry, or something else?

Our goal is to make the Java buildpack work without any custom configuration in the majority of cases, and the custom command counts as custom configuration to my mind.  In fact, the custom command is a bit more insidious as necessarily bypasses the all of the smarts we do with memory sizing, zero-touch services, and other great things that the buildpack provides.  If it's possible and reasonable, I'd like to add the ability for the buildpack to support the deployment scenario so that you don't have to specify that custom command any longer.


-Ben Hale
Cloud Foundry Java Experience

davidi...@gmail.com

unread,
Sep 4, 2013, 2:42:43 PM9/4/13
to vcap...@cloudfoundry.org, davidi...@gmail.com


On Wednesday, September 4, 2013 1:29:38 PM UTC+1, Ben Hale wrote:
<snip>
David,

You are correct that the new buildpack doesn't detect the presence of .jar files.  Instead it makes the assumption that if you're pushing a JAR, Cloud Foundry's support for exploding archives comes into play and we end up with a filesystem that has a bunch of .class, .groovy, etc. that it'll detect and work against.  In the case of Java main() applications, this results in a filesystem that contains a /META-INF/MANIFEST.MF which we then examine for the Main-Class attribute.

As an aside, one of the things I did try was building a monster-jar along those lines, but that seemed to fail to stage after pretty slowly processing a lot of individual class files.
 
 Now clearly your application doesn't fit this pattern as it's an archive within an archive (Cloud Foundry doesn't expand the inner archive) which is why it is not being detected.  The closest analog that we've got to this is Spring Boot applications that are packaged as self-executing JAR files.  They package their dependency JARs within themselves and use a special loader mechanism to get everything onto the classpath.  Ideally, this would be how we'd like all applications to work (it fits better with the Cloud Foundry model and doesn't require us to do any guesswork), but you've got an application that used to work but doesn't any longer, so let's take a look at what we can do.

My understanding from your email is that the ZIP file contains all of the dependencies for the primary JAR, however in your example custom command you don't seem to mention them.  How are you getting those JARs onto the classpath, Class-Path manifest entries?

In Maven, it's as simple as <addClasspath>true</addClasspath> in the maven-jar-plugin configuration. It's a couple of lines in gradle.
 
 In addition, how is the primary JAR uniquely identified; is it semantic knowledge about the application, the only one with a Main-Class manifest entry, or something else?

It's semantic knowledge about the application. In a non-CF environment it'd be specified in an upstart script in that java -jar form.
 

Our goal is to make the Java buildpack work without any custom configuration in the majority of cases, and the custom command counts as custom configuration to my mind.
 
 In fact, the custom command is a bit more insidious as necessarily bypasses the all of the smarts we do with memory sizing, zero-touch services, and other great things that the buildpack provides.

Indeed. I was a bit surprised that using the custom command didn't just make java available, hand me a lot of rope, and skip detection.

FWIW though, I'd rather write a custom command (and be responsible for it) in manifest.yml than fork an entire buildpack to edit a single param in config.yml and then have to worry about keeping a fork code I don't really understand up-to-date
 
 If it's possible and reasonable, I'd like to add the ability for the buildpack to support the deployment scenario so that you don't have to specify that custom command any longer.

That sounds nice :)  Scanning the top level for .jars and running the first one with a Main-Class? And allowing an override in case a dependency lib has a Main-Class?

davidi...@gmail.com

unread,
Sep 7, 2013, 12:30:41 PM9/7/13
to vcap...@cloudfoundry.org, davidi...@gmail.com
On Wednesday, September 4, 2013 7:42:43 PM UTC+1, davidi...@gmail.com wrote:

<snip>
 In fact, the custom command is a bit more insidious as necessarily bypasses the all of the smarts we do with memory sizing, zero-touch services, and other great things that the buildpack provides.

Indeed. I was a bit surprised that using the custom command didn't just make java available, hand me a lot of rope, and skip detection.

FWIW though, I'd rather write a custom command (and be responsible for it) in manifest.yml than fork an entire buildpack to edit a single param in config.yml and then have to worry about keeping a fork code I don't really understand up-to-date

 On reflection, I think I'd just like a the ability to specify a java buildpack, a custom command, and then not have to worry about detection. Dealing with including the $JAVA_OPTS into the command line and pulling the params out of the appropriate environment variable isn't hard and leaves me less tied into CF magic for when I want to run the app elsewhere.
Reply all
Reply to author
Forward
0 new messages