Gradle

Add support for EAR archives

Details

  • Type: New Feature New Feature
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: 0.1
  • Fix Version/s: 1.0-milestone-4
  • Component/s: tasks
  • Labels:
    None

Activity

Hide
Hans Dockter added a comment -

This will be a top priority issue for Gradle 0.3.

Show
Hans Dockter added a comment - This will be a top priority issue for Gradle 0.3.
Hide
Tom Eyckmans added a comment -

does this also include support for EJB jars ?

Show
Tom Eyckmans added a comment - does this also include support for EJB jars ?
Hide
Hans Dockter added a comment -

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

Show
Hans Dockter added a comment - 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
Hide
David Gileadi added a comment -

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.

Show
David Gileadi added a comment - 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.
Hide
Andrew Thorburn added a comment -

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.

Show
Andrew Thorburn added a comment - 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.
Hide
Adam Murdoch added a comment -

@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

Show
Adam Murdoch added a comment - @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
Hide
Szczepan Faber added a comment -

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

Show
Szczepan Faber added a comment - @david, definitely share your code in github using 'fork' feature. Check out the link Adam sent earlier.
Hide
David Gileadi added a comment - - edited

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

Show
David Gileadi added a comment - - edited 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
Hide
David Gileadi added a comment -

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.

Show
David Gileadi added a comment - 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.
Hide
Andrew Thorburn added a comment -

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.

Show
Andrew Thorburn added a comment - 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.
Hide
David Gileadi added a comment -

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.

Show
David Gileadi added a comment - 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.
Hide
Szczepan Faber added a comment -

@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.

Show
Szczepan Faber added a comment - @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.
Hide
Szczepan Faber added a comment -

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

Show
Szczepan Faber added a comment - Once released, the documentation of the plugin can found here: http://gradle.org/releases/latest/docs/userguide/userguide_single.html#ear_plugin
Hide
Thor Åge Eldby added a comment -

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.

Show
Thor Åge Eldby added a comment - 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.
Hide
David Gileadi added a comment - - edited

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.

Show
David Gileadi added a comment - - edited 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.
Hide
Adam Murdoch added a comment -

Still needs work

Show
Adam Murdoch added a comment - Still needs work
Hide
Szczepan Faber added a comment -

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

Show
Szczepan Faber added a comment - 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

People

Vote (16)
Watch (15)

Dates

  • Created:
    Updated:
    Resolved: