As part of migrating our build over from Ant to Gradle, I’ve found myself having to recreate in Gradle some of the crufty and sometimes questionable things the old build does. One of the relatively standard things (although still ended up being slightly crufty) I’ve had to do is creating an arbitrary number of EBJ jars from source packages contained in multiple projects.
So: I have a multi-project build and in each of the projects I have several packages in the main src tree which need to be packaged up separately from the rest of the src as individual EJB artifacts:
com/foo/ejb/ejb1/[EJB1.class, EJB1Bean.class, EJB1Home.class]
com/foo/ejb/ejb2/[EJB2.class, EJB2Bean.class, EJB2Home.class]
...
There can be an arbitrary number of these EJBs in each project (0 or several). So I need to create a task (or tasks) that can per project, Jar each of these as separate artifacts after the regular compile, i.e. So I end up with following artifacts for each project:
project.jar (usual Java classes)
ejb1.jar (MyEjb1Home/Remote/Bean.class, META_INF/[descriptors])
ejb2.jar (MyEjb2Home/Remote/Bean.class, META_INF/[descriptors])
...
I wanted the task(s) shared to each project so that they would automatically find the EJB sources, given a base package to start at, and generate a jar for each. It would automagically do this without having to explicitly define the EJBs in the subprojects, but with perhaps requiring a property set in the sub-projects to narrow things down a bit.
This is what I ended up doing:
// file: build.groovy (root project)
subprojects
{
//...
afterEvaluate { project ->
if (project.hasProperty('containsEjbs')) {
def basePath = '/com/foo/ejb'
def classesDir = project.sourceSets.main.classesDir
def ejbRootClassesDir = file(classesDir.getPath() + basePath)
def srcFileDirs = project.sourceSets.main.java.srcDirs.collect { file(it.getPath() + basePath) }.findAll { it.exists() && it.isDirectory() }
def ejbDirs = srcFileDirs.collect { it.listFiles() }.flatten()
def ejbs = ejbDirs.findAll { it.listFiles().findAll { f -> f.name == 'META-INF'} }
ejbs.each { file ->
task "jarEjbFor_$file.name" (type: Jar, dependsOn:classes) {
baseName = "$file.name"
classifier = 'ejb'
from fileTree(file).include('META-INF/**')
into ("$basePath/$file.name")
{
from fileTree( ejbRootClassesDir.getPath() + "/$file.name" )
}
}
}
}
}
}
This relies on setting the basePath to the package where the ejbs live in the sourcecode. This is always the same for me because its a convention across all of our projects.
So if any projects have a property containsEjbs=true, then tasks are added for each ejb package found under /com/foo/ejb in each sub-project, named as jarEjbFor_[package name].
Note that we store META-INF with descriptors in same source tree as classes, so there may be tweaks needed for your set up.
If there’s a better way of doing this, or a way to enhance it, please let me know!