1

The problem: Given the following multi-project gradle build

superproject
    subproject-A -> war
    subproject-B -> jar

I am looking for a way to configure subproject-B to unpack the content of the war generated by subproject-A and have the content of the unpacked webapp directory (with classes and resources for a deployment into a container) packed into the application distribution of subproject-B at the root level along with the classes, resources and dependencies of the latter. So the structure of the distribution produced for subproject-B should look like this:

subproject-B-0.1.0
    bin/...
    lib/
        META-INF/ (<-- from B)
        WEB-INF/  (<-- from A.war)
        css/      (<-- from A.war)
        js/       (<-- from A.war)
        *.jar     (code and dependencies of B)

The question of copying a resource from A to B was answered here. Here I need to copy the content of a dynamically generated build artifact (and generally it is ok if that is copied into main/resources as the latter will be packed into the jar).

The rationale: subproject-B is a standalone Java app running tomcat-embed-server with a JavaFX WebView accessing the web app of subproject-B on the localhost turning the otherwise web app into a sort of a standalone desktop app. It is 20 lines of code that run nicely in Eclipse, but seem to pose a packaging challenge for distribution.

Community
  • 1
  • 1
Oleg Sklyar
  • 9,834
  • 6
  • 39
  • 62

1 Answers1

2

I have finally found a solution so posting it here for the benefit of those facing a similar problem:

subprojectA/build.gradle

apply plugin: "java"
apply plugin: "war"

archivesBaseName = "subprojectA"

sourceCompatibility = 1.8
compileJava.options.encoding = "utf-8"

war {
    manifest {
        archiveName = "$baseName.$extension"
        attributes "Implementation-Title": archivesBaseName, 
                   "Implementation-Version": version
    }
}

// declare configuration to refer to in superprojectB
configurations {
    subprojectAwar
}
// make this configuration deliver the generated war
dependencies {
    subprojectAwar files(war.archivePath)
}

subprojectB/build.gradle

apply plugin: "java"
apply plugin: 'application'

archivesBaseName = "subprojectB"

sourceCompatibility = 1.8
compileJava.options.encoding = "utf-8"

// declare configuration to take files from
configurations {
    subprojectAwar
}

dependencies {
    // bind the configuration to the respective configuration in subprojectA
    subprojectAwar project(path: ":subprojectA", configuration: "subprojectAwar")

    compile "org.apache.tomcat.embed:tomcat-embed-core:$tomcatEmbedVersion"
    compile "org.apache.tomcat.embed:tomcat-embed-websocket:$tomcatEmbedVersion"
    compile "org.apache.tomcat.embed:tomcat-embed-logging-log4j:$tomcatEmbedVersion"
    compile "org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatEmbedVersion"
}

mainClassName = 'org.project.subprojectB.StartServer'

jar {
    // make sure this project is assembled after the war is generated
    dependsOn(":subprojectA:assemble")

    manifest {
        archiveName = "$baseName.$extension"
        attributes "Implementation-Title": archivesBaseName,
                   "Implementation-Version": version
        attributes 'Main-Class': '$mainClassName'
    }
    // if you need to copy the content of the war into the jar:
    // (otherwise only to the distribution, see below)
    /*
    from(zipTree(configurations.subprojectAwar.collect { it }[0])) {
        into ""
        exclude '**/META-INF/**'
    }
    */
}

// copy the content of the war excluding META-INF into the lib of superprojectB
applicationDistribution.from(zipTree(configurations.subprojectAwar.collect { it }[0])) {
     into "lib"
     exclude '**/META-INF/**'
}
Oleg Sklyar
  • 9,834
  • 6
  • 39
  • 62