[GRADLE-37] Add support for EAR archives Created: 18/Apr/08  Updated: 04/Jan/13  Resolved: 28/Jul/11

Status: Resolved
Project: Gradle
Affects Version/s: 0.1
Fix Version/s: 1.0-milestone-4

Type: New Feature
Reporter: Hans Dockter Assignee: Szczepan Faber
Resolution: Fixed Votes: 16


 Comments   
Comment by Hans Dockter [ 17/Jun/08 ]

This will be a top priority issue for Gradle 0.3.

Comment by Tom Eyckmans [ 07/Nov/08 ]

does this also include support for EJB jars ?

Comment by Hans Dockter [ 10/Nov/08 ]

I guess. It is a long time since I have worked with EJB's. So I don't have a clear picture of what to do, except that it involves creating deployment descriptors

Comment by David Gileadi [ 07/Mar/11 ]

I've started on some code for this, based on the existing War task and on WarPlugin. From what I understand based on http://download.oracle.com/javaee/6/tutorial/doc/bnaby.html and on the .ear files I am currently building with Maven, an .ear file contains:

a) one or more deployable module archives in its root such as .jars or .wars
b) optional deployment descriptors in /META-INF, the most common one being application.xml
c) other dependencies in /lib

What I've built is an Ear task with three FileCollections configurable via getter/setter and closure: 'modules', 'libraries' and 'descriptors' which are packaged into the .ear's root, /lib and /META-INF directories respectively.

I've also built an EarPlugin which maps all 'compile' dependencies to Ear.modules, non-transitively. It maps all 'runtime' dependencies to Ear.libraries, transitively (including transitive dependencies of 'compile' dependencies). It also maps the contents of the /src/main/application directory to Ear.descriptors. It also borrows other code from the WarPlugin to disable the Jar task and remove it from the archives config.

This means that the only items in the root will be those explicitly listed as 'compile' dependencies, regardless of whether those dependencies are marked as transitive or not. This hopefully makes sense, as we only want deployable modules in the .ear's root. All other dependencies go into /lib.

Does this sound like good behavior? Should I use more explicit configurations than 'compile' and 'runtime'? Also, what steps should I take in order to contribute this code?

Note that I'm also working on changing the EclipsePlugin to support EAR projects, and to support EJB projects as well.

Comment by Andrew Thorburn [ 09/Mar/11 ]

What I would suggest is leaving the 'compile' configuration alone, and rather creating a new configuration called 'modules', perhaps. That configuration would automatically map transitive dependencies to the 'compile' configuration, which seems closer to the way Gradle currently handles 'compile' and 'runtime' configurations. Changing the meaning of existing configurations in a plugin seems like a bad idea to me.

Is this code somewhere we can see? If not, I would suggest creating a Git Hub project for it (or on whichever host you prefer), as I would like to have a bit of a play around with this at some point in the near future.

Comment by Adam Murdoch [ 11/Mar/11 ]

@david: the best option for contributing the code is to fork the Gradle github repository, and add your code. I think the best location for this code at the moment is in the 'subprojects/plugins' project. For more details about contributing: http://gradle.codehaus.org/How+to+contribute+a+patch+to+Gradle

Comment by Szczepan Faber [ 15/Mar/11 ]

@david, definitely share your code in github using 'fork' feature. Check out the link Adam sent earlier.

Comment by David Gileadi [ 20/Apr/11 ]

Update: new pull request created, now with support for generating application.xml and with a clean merge into the latest git source. See https://github.com/gradle/gradle/pull/31

Comment by David Gileadi [ 31/May/11 ]

A few notes about the current design available in my latest pull request:

There’s an Ear task that extends Jar and has the following properties:
• lib CopySpec, for putting files into the “lib” dir in the generated EAR
• libDirName, for renaming the “lib” dir in the generated EAR and in the generated deployment descriptor (application.xml)
• deploymentDescriptor, an instance of the new DeploymentDescriptor interface for customizing the generated deployment descriptor

Note that the Ear task only generates a deployment descriptor (application.xml) if one doesn’t already exist in the source files.

There’s an EarPlugin that has the following configurations:
• deploy, which puts dependencies into the root of the EAR, non-transitively
• earlib, which puts dependencies into the “lib” dir in the generated EAR, transitively

The associated EarPluginConvention echoes the libDirName and deploymentDescriptor properties of the Ear task, and also adds an appDirName property, which is the name of the project’s source folder which holds EAR metadata like a “META-INF” dir. The default value is “src/main/application”.

The EarPlugin also works with the Java plugin if configured for the project.

Finally I’ve also changed the EclipsePlugin and helpers to support EAR projects, allowing Eclipse to deploy them to a container for debugging.

Comment by Andrew Thorburn [ 31/May/11 ]

David, couple of queries:

1) When adding dependencies to the 'deploy' configuration, are their dependencies added to the 'earLib' configuration? That is, I add a 'WAR' project as a dependency - are it's dependencies added to the 'earLib' configuration? Or do I have to manage them manually? It sounds like the latter, but I'd just like to be sure.

2) Do you support 'thin' EAR/WAR files? Basic scenario is that, when creating an EAR which includes multiple WAR files, I don't want to have each WAR include a whole bunch of libraries. Any common dependencies should be included in the EAR file, and only dependencies specific to a given WAR should be included in it. And even then, it might make more sense to have all dependencies in the EAR file, with the WARs containing no libraries at all.

I know that Maven supports this, technically, but it requires moving all your dependencies into the PROVIDED scope, I believe (been a while since I checked), so it's bit finicky, and prevents you from building just one WAR. I'm not sure if Gradle would allow you to modify how the dependencies of projects you depend on, but it would awesome if there was some way to achieve this without having to fiddle with the dependencies of the WAR projects.

I should also note that I haven't looked at your modifications or at the Gradle source yet.

Comment by David Gileadi [ 01/Jun/11 ]

You're right that I was pretty basic with how I dealt with dependencies--transitive dependencies of 'deploy' dependencies are simply ignored, meaning you have to manage your 'earlib' dependencies yourself. And no, I didn't build any support for 'thin' EAR/WAR files. However it would be awesome if both of your suggestions could be done.

I shied away from doing anything fancy with dependencies because, frankly, I don't understand the dependency system very well and the last few times I tried messing with it I met with very little success. It was hard for me to even determine what the resolved dependencies of a project were in many cases!

With that said, perhaps I should revisit this, since what you're asking for would be very nice. If anyone knows of a good primer for how to mess around with dependencies in Gradle, please let me know.

Comment by Szczepan Faber [ 01/Jun/11 ]

@David - I commented on the patch in github. Thanks again for your efforts on it.

I'm thinking of merging it possibly quickly (Thu/Fri) and releasing a snapshot so that people can play with it and we can iterate and polish the implementation.

Comment by Szczepan Faber [ 07/Jun/11 ]

Once released, the documentation of the plugin can found here: http://gradle.org/releases/latest/docs/userguide/userguide_single.html#ear_plugin

Comment by Thor Åge Eldby [ 23/Jun/11 ]

I'm trying to use the new plugin (with build 1.0-milestone-4-20110610162713+0200) and I'm pretty close to getting the ear I want. This is a hack of course. By adding the war and the ejbs as earlib I get all the dependencies I need; however I of course get the war and ejbs in the lib directory as well. Is there anyway to hack around that?

apply plugin: 'ear'

dependencies {
    deploy project(':service:service-wswar')
    deploy project(':service:service-ejbs')
    earlib project(':service:service-wswar')
    earlib project(':service:service-ejbs')
}

ear {
    libDirName 'APP-INF/lib'
    deploymentDescriptor {
        version = "5"
    }
}

The most logical solution I can see for a non-hacky solution would be to have something like this:

dependencies {
    deploy project(':service:service-wswar') {
        addTransitivesAsEarlibs = true
    }
}

However I'm quite new to gradle so I don't know if the model would support that.

Comment by David Gileadi [ 23/Jun/11 ]

It sounds like what you want is a "skinny" ear, i.e. with all the dependencies of your deployed modules put in the ear's lib dir, and not within the war's WEB-INF/lib dir, for instance. This seems to be a somewhat popular request.

I have some code created that will do this with the following config:

ear

{ skinnyDeploy = true }

The code is NOT currently part of Gradle. However since this seems to be popular request I've just opened issue 1637 (http://issues.gradle.org/browse/GRADLE-1637) for including it and will make a pull request in Github.

Comment by Adam Murdoch [ 23/Jun/11 ]

Still needs work

Comment by Szczepan Faber [ 28/Jul/11 ]

I'd like to close this issue to tidy up things before release. It is a first version so I expect improvements reported & worked on. However, it feels they should tracked as separate & specific jira tickets (just like GRADLE-1637, e.g. the skinnyDeploy).

If someone disagrees please reopen

Generated at Wed Jun 30 11:20:26 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.