I recently wanted to convert an old Ant WebLogic build to use the Gradle build tool instead of Ant. The main driving force behind that change was that the Ant build.xml file housed many different responsibilities, from building and testing the source code, to maintaining property files, to deploying and running the application, along with many tasks that were any combination of unused, not understood, or just plain wrong.
Oracle does not provide any fancy Grails plugins for building EAR files in Gradle, but that was not a concern since Gradle has a very nice Ant integration, allowing a user to define and run Ant tasks, or even just call out to an external Ant build file if necessary. I could have chosen to move the builds to Maven; Oracle does have some support for Maven builds, however looking over the documentation for the Maven plugins, it looked very limited and not well supported. Gradle seems to be a more standard technology today than Ant, so there you have it.
Sounds Simple(ish)
Sounds like a fairly simple, or at least fairly straightforward task. I already had a functional Ant build to base my work off of, and if all else failed, as a last resort I could just pull out the build tasks I needed from the legacy build.xml file and call out to them from the new Gradle build. That definitely was a last-resort fallback position that I wanted to avoid at all costs, but there were points during this process that made that position very appealing. Probably the one reason I did not give in to that temptation was that the Ant build had such convoluted setup and initialization steps that it was not at all clear which pieces of those tasks would be required for a more targeted build machine.
In all honesty, I do not think the words “simple” and “Enterprise Application aRchive”, or even “WebLogic” can really be said together in the same sentence with a straight face.
Just Tell Me What you Did!
Right down to it. It works. It is not pretty. Gradle accepts it, but I don’t think she likes it (would Gradle have a masculine or feminine declination?).
Gradle’s EAR Plugin
Gradle has a plugin for building EAR files. Be careful with this, as Oracle’s WebLogic build tools really want to be in charge of generating the EAR file, and those build tools and this plugin will fight incessantly if you are not careful.
WebLogic Install
Of course you need WebLogic installed. Not only for the build tools that come with the weblogic.jar, but also to just get your app to compile (we said Enterprise earlier, remember?).
Configurations
Configurations galore! If all you’ve really done with Gradle before was just use it to build and publish fairly standard Java apps, you may not have much experience with Gradle configurations. I know I didn’t, besides the default “compile” and “testCompile” dependency configurations.
Mileage May Vary
Depending on just how much WebLogic stuff you use (ejbgen, wlappc, appMerge, etc.), these steps may be totally wrong for you. We were running WebLogic 10.3.6, with old EJB 2 style WebLogic annotations, and we wanted an offline merge of a WebLogic library EAR into the end result.
build.gradle:
buildscript { ext { // Ensure that we can find a WebLogic installation if(!project.hasProperty('WL_SERVER_HOME') && !System.env.WL_SERVER_HOME) { println '''"WL_SERVER_HOME" is a required property. This should be set to WebLogic server's base directory, e.g. "/u01/app/Oracle/Middleware1036/wlserver''' throw new InvalidUserDataException('"WL_SERVER_HOME" property must be specified') } else if (!project.hasProperty('WL_SERVER_HOME')) { WL_SERVER_HOME = System.env.WL_SERVER_HOME } } } apply plugin: 'java' apply plugin: 'ear' sourceCompatibility = '1.7' targetCompatibility = '1.7' configurations { weblogic shared_ear // The library EAR that we will do an offline merge of } sourceSets { main { java { srcDirs = [ //This is basically WebLogic's split directory development model 'src/main/java', 'src/main/SomeMDB', 'src/main/awesomeApplication/WEB-INF/src' ] includes = ['**/*.ejb'] } compileClasspath += configurations.earlib } } dependencies { def sharedLibraryEarVersion = '1.0.0' compileOnly files( //any compile dependencies your code has on WL "${WL_SERVER_HOME}/../modules/com.bea.core.ejbgen_1.1.0.3.jar", "${WL_SERVER_HOME}/../modules/javax.ejb_3.0.1.jar") weblogic files( //files needed for WL tool invocations later "${WL_SERVER_HOME}/server/lib/weblogic.jar", "${System.getProperty('java.home')}/../lib/tools.jar") //The shared library ear shared_ear group: 'com.example', name: 'shared-ear', version: sharedLibraryEarVersion //Dependencies I want bundled in with the EAR earlib group: 'log4j', name: 'log4j', version: '1.2.14' // etc. testCompile group: 'junit', name: 'junit', version: '4.10' testCompile files( //Some of those compileOnly files are needed here too "${WL_SERVER_HOME}/../modules/javax.ejb_3.0.1.jar") } //Pay attention, here's where things get tricky //Add WL to the 'Ant Classpath', so that invocation of the WL tools via Ant // does not blow out the max command line length on Windows boxes ClassLoader antClassLoader = org.apache.tools.ant.Project.class.classLoader configurations.weblogic.each {File f -> antClassLoader.addURL(f.toURI().toURL()) } task weblogicCompile { description 'Calls the wlcompile task to generate class files based on WL EJB sources' outputs.dir("${buildDir}/AwesomeApplication") inputs.dir('src/main') doLast { ant.taskdef( name: 'wlcompile', classname: 'weblogic.ant.taskdefs.build.WLCompileTask') ant.taskdef( name: 'ejbgen', classname: 'com.bea.wls.ejbgen.ant.EJBGenAntTask') ant.wlcompile( srcDir: 'src/main', destDir: "${buildDir}/AwesomeApplication", classpath: (configurations.earlib + configurations.weblogic).asPath) { ant.ejbgen( source: '1.5', forceGeneration: false, verbose: true, localBaseClass: 'com.example.service.EJBLocalService', remoteBaseClass: 'com.example.service.EJBRemoteService', fork: true) library(name: 'Shared-Lib', file: configurations.shared_ear.singleFile) } } } } task weblogicAppc { description 'Calls the wlpackage task to package jsp and other WEB-INF files' outputs.dir("${buildDir}/AwesomeApplication/awesomeness") inputs.dir('src/main/awesomeApplication') dependsOn weblogicCompile doLast { ant.taskdef( name: 'wlpackage', classname: 'weblogic.ant.taskdefs.build.WLPackageTask') ant.taskdef( name: 'wlappc', classname: 'weblogic.ant.taskdefs.j2ee.Appc') ant.wlpackage( srcDir: 'src/main/awesomeApplication', destDir: "${buildDir}/AwesomeApplication/awesomeness", toDir: "${buildDir}/AwesomeApplication/awesomeness") ant.wlappc( source: '${buildDir}/AwesomeApplication/awesomeness', keepgenerated: true, verbose: true, classpath: (configurations.earlib + configurations.weblogic).asPath) { library(name: 'Shared-Lib', file: configurations.shared_ear.singleFile) } } } ear { dependsOn weblogicCompile, weblogicAppc libDirName 'APP-INF/lib' exclude '**/.beabuild.txt' into('/') { from("${buildDir}/AwesomeApplication") } } task copyEar(type: Copy) { description 'Back up the compiled ear before merging in the shared library ear' dependsOn ear from ear.archivePath into ear.archivePath.getParent() rename '.ear', '-slim.ear' } task fat_ear(type: JavaExec) { description 'Calls the WL appmerge task to generate a fat ear' dependsOn ear, copyEar def inputFile = ear.archivePath.toString().replace('.ear', '-slim.ear') inputs.file(inputFile) outputs.file(ear.archivePath) jvmArgs "-XX:MaxPermSize=256m" main = 'weblogic.appmerge' classpath = configurations.weblogic args = [ '-output', ear.archivePath, '-library', configurations.shared_ear.singleFile, inputFile ] } //make sure the "fat_ear" task gets called for the final result assemble.dependsOn fat_ear
Originally Posted on my Blogger site June of 2018