Using War plugin but without creating an archive - gradle

I'm trying to get Gradle to handle the deployment of a very large Web application. In the past when we used Ant, instead of creating a very large .war file, we would simply assemble all the code in one folder--libraries, .jsp's etc--and then scp them to the deployment destination. This would speed deployment since we would be moving only the files that changed.
I'm having trouble trying to do this with Gradle, however. Using the War plugin creates an actual .war file, which we don't want. I've tried simply creating a task that depends on 'classes' and that generates the necessary classes and resources folders. However, where are the library dependencies? How can I get this all in one place so I can do an scp?
Current build:
apply plugin: "java"
apply plugin: "maven"
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
sourceCompatibility = 1.6
targetCompatibility = 1.6
repositories {
maven {
url 'http://buildserver/artifactory/repo'
}
}
sourceSets {
main {
java {
srcDir 'src'
}
resources {
srcDir 'src'
}
}
}
webAppDirName = 'web'
dependencies {
compile 'antlr:antlr:2.7.6'
compile 'antlr:antlr:2.7.7'
*** etc ***
}
task deploystage(dependsOn: 'classes') << {
println 'assemble and scp code here'
}

your right Opal ... no easynway to use the War plugin for this ... although it would be nice if it had a createExplodedWar option. I just used the Jar plugin methods.
The .jars were available, along with other things in war.classpath.files:
gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
project.ext.set("allclasspathjars", files(war.classpath.files))
}
I then when through these to separate out the .jars from the other stuff:
task deployJars(dependsOn: 'classes') << {
FileUtils.cleanDirectory(new File("web/WEB-INF/lib/"))
project.allclasspathjars.each {File file ->
if(file.name.endsWith(".jar")) {
println "Including .jar: " + file.name
org.apache.commons.io.FileUtils.copyFile(file, new File("web/WEB-INF/lib/" + file.name))
}
}
After this I could copy all the classes & resources into the .war structure:
task createExplodedWar(type: Copy, dependsOn: 'deployJars') {
from 'build/classes/main'
from 'build/resources/main'
into 'web/WEB-INF/classes'
}
Finally used Gradle SSH Plugin to push it up to tomcat and restart the server.
All good.

Related

Gradle: Distributing Executable, Obfuscated Jar File

I'm trying to use gradle with proguard to obfuscate the code then generate a zip file to distribute. I'd like to use the distribution plugin, but it always includes the jar that is generated by the jar task. Is there some way to force the distribution plugin to omit the original (non-obfuscated) jar and only include the obfuscated jar? I can easily add the obfuscated jar in addition to the original, but I want to distribute the obfuscated jar instead of the original so the generated execution scripts run against the obfuscated version.
Here's my abridged build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:5.3.3'
}
}
apply plugin: 'java'
apply plugin: 'application'
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars "build/libs/${rootProject.name}.jar"
outjars "build/libs/${rootProject.name}-release.jar"
}
jar.finalizedBy(project.tasks.obfuscate)
distributions {
main {
contents {
from(obfuscate) {
into "lib"
}
from(jar) {
exclude "*.jar"
}
}
}
}
I've tried a number of things in the distributions block to try to exclude the original jar, but nothing seems to work.
Any ideas would be greatly appreciated.
This isn't the best solution, but I was able to work around the issue by renaming the jars at the end of the obfuscation step. Now, I name the original jar something like <JAR_NAME>-original.jar and I give the obfuscated jar the original jar's name. I still wish there was a better way to do it, but this seems to work.
Here is the updated, abridged build.gradle file:
import java.nio.file.Paths
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:5.3.3'
}
}
apply plugin: 'java'
apply plugin: 'application'
def jarNameWithoutExtension = jar.archiveName.with { it.take(it.lastIndexOf(".")) }
def obfuscatedJarName = "${jarNameWithoutExtension}-release.jar"
def jarFileLocation = jar.archivePath.parent
def obfuscatedFilePath = Paths.get(jarFileLocation, obfuscatedJarName)
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars jar.archivePath
outjars obfuscatedFilePath.toString()
// Rename the original and obfuscated jars. We want the obfuscated jar to
// have the original jar's name so it will get included in the distributable
// package (generated by installDist / distZip / distTar / assembleDist).
doLast {
jar.archivePath.renameTo(Paths.get(jarFileLocation, "$jarNameWithoutExtension-original.jar").toFile())
obfuscatedFilePath.toFile().renameTo(jar.archivePath)
}
}
jar.finalizedBy(project.tasks.obfuscate)

Gradle war command not including hibernate cfg file

Hibernate-cfg.xml not added to war classes folder.I am using below script to deploy web applcation to tomcat.After copy, when i am starting tomcat , gettign below error
eNotFoundException: class path resource [hibernate.cfg.xml] cannot be resolved URL because it does not exist
apply plugin: 'java'
apply plugin: 'war'
sourceCompatibility = 1.7
apply plugin: 'eclipse'
repositories {
mavenCentral()
}
dependencies {
compile("javax.servlet:jstl:1.2")
compile("org.springframework:spring-context:4.0.3.RELEASE")
compile("org.springframework:spring-webmvc:4.0.3.RELEASE")
compile("org.springframework:spring-web:4.0.3.RELEASE")
compile("org.springframework:spring-aop:4.0.3.RELEASE")
compile("org.springframework:spring-aspects:4.0.3.RELEASE")
compile("org.springframework:spring-beans:4.0.3.RELEASE")
compile("org.springframework:spring-core:4.0.3.RELEASE")
compile("org.springframework:spring-expression:4.0.3.RELEASE")
compile("org.springframework:spring-jdbc:4.0.3.RELEASE")
compile("org.springframework:spring-orm:4.0.3.RELEASE")
compile("org.eclipse.persistence:javax.persistence:2.0.0")
compile("antlr:antlr:2.7.7")
compile("commons-logging:commons-logging:1.1.1")
compile("org.hibernate:hibernate-commons-annotations:3.2.0.Final")
compile("org.hibernate:hibernate-core:4.3.5.Final")
compile("org.apache.derby:derbyclient:10.12.1.1")
compile("javax.validation:validation-api:1.0.0.GA")
compile("org.slf4j:slf4j-api:1.7.5")
}
task deploy (dependsOn: war){
copy {
from "build/libs"
into "C:/soft/apache-tomcat-7.0.67/webapps"
include "*.war"
}
}
/*task startTomcat(dependsOn:deploy,type:Exec) {
workingDir "C:/mdi/soft/apache-tomcat-7.0.67/bin"
commandLine 'cmd', '/c', 'startup.bat'
}*/
task startTomcat << {
def processBuilder = new ProcessBuilder(['cmd','/c','startup.bat'])
processBuilder.directory(new File("C:/soft/apache-tomcat-7.0.67/bin"))
processBuilder.start()
}
// Set source directory
// War file name
war
{
war.baseName = 'userregisteration'
project.webAppDirName = 'WebContent'
sourceSets{
main {
java {
srcDir 'src'
}
}
}
}
In your war task add a from closure:
from(<directory containing Hibernate-cfg.xml>){
into <'directory in the war in which you'd like the file to be placed'>
include 'Hibernate-cfg.xml'
}
This is also pretty basic. I'd recommend perhaps reviewing the Gradle manual again to gain a better understanding of working with files.

Not Publishing the mentioned file(war/tar/zip) to artifactory in gradle script

I wrote a gradle script where I am creating the zip and war file and then I need to upload/publish it to the artifactory but the issue is I specified the war file in my artifact task even after that it is publishing everything to the artifactory zip,tar and war instead of only war file.
apply plugin: 'war'
apply plugin: 'java'
apply plugin: 'distribution'
//-- set the group for publishing
group = 'com.xxx.discovery'
/**
* Initializing GAVC settings
*/
def buildProperties = new Properties()
file("version.properties").withInputStream {
stream -> buildProperties.load(stream)
}
//add the jenkins build version to the version
def env = System.getenv()
if (env["BUILD_NUMBER"]) buildProperties.coveryadBuildVersion += "_${env["BUILD_NUMBER"]}"
version = buildProperties.coveryadBuildVersion
println "${version}"
//name is set in the settings.gradle file
group = "com.aaa.covery"
version = buildProperties.discoveryadBuildVersion
println "Building ${project.group}:${project.name}:${project.version}"
repositories {
maven {
url "http://cxxxxt.tshaaaaa.tho.com:9000/artifactory/libselease"
}
maven {
url "http://cxxxxt.tshaaa.tho.com:9000/artifactory/cache"
}
}
dependencies {
compile ([
"com.uters.omni:HermesSessionAPI:1.2",
"com.uters.proxy:ProxyResources:1.1",
"com.uters.omni:SeshataDirectory:1.0.1" ,
"com.euters.omni:CybeleInfrastructure:1.1.2",
"com.euters:JSONBus:1.4.1",
"javaee:javaee-api:5"
])
}
distributions {
main {
contents {
from {
war.outputs
}
}
}
}
// for publishing to artifactory
artifacts {
archives war
}
According to gradle distribution plugin documentation:
All of the files in the “src/$distribution.name/dist” directory will automatically be included in the distribution.
And also,
The distribution plugin adds the distribution archives as candidate for default publishing artifacts.
In other words, by default all the files will be published so this explains the behavior you're experiencing.
What you can probably do in order to workaround this behavior is to define the contents copySpec more accurately by explicitly exclude the unwanted files, i.e.:
distributions {
main {
contents {
exclude('**/.zip')
exclude('**/.tar')
from {
war.outputs
}
}
}
}
Note that I didn't try the above by myself though so some fine tuning might be needed. However I believe that you can find the data you need in the CopySpec Interface documentation

Gradle Setting Manifest Class-Path on Jars in Ear

Set Up
I'm using Gradle and have a multi-project build using Java EE with IBM WebSphere Application Server. The project directory structure looks like this:
--/build.gradle
--/defaults.gradle
--/settings.gradle
--/common-ejb
--/common-ejb/build.gradle
--/logging
--/logging/build.gradle
--/project1
--/project1/build.gradle
--/project1-ejb
--/project1-ejb/build.gradle
--/project2
--/project2/build.gradle
--/project2-ejb
--/project2-ejb/build.gradle
project1 and project2 are individual ears that get deployed. They both reuse a number of EJBs from common-ejb and share some other library dependencies that aren't relevant for this question.
After performing the build: project1.ear looks like:
--/lib/log4j.jar
--/lib/logging.jar
--/META-INF/application.xml
--/META-INF/MANIFEST.MF
--/common-ejb.jar
--/project1-ejb.jar
Gradle properly creates the application.xml to load EJBs from both projects. Unfortunately, project1-ejb.jar will fail to load due to dependencies on common-ejb.jar. The project1-ejb.jar/META-INF/MANIFEST.MF needs to have the Class-Path set with common-ejb.jar since it's not in the lib/ directory.
I was able to set it by explicitly defining it as done below. Gradle knows the dependencies for the Class-Path, so it should be able do this automatically. Is there a way to set this up?
Gradle Files
Not including project2, but you can guess what it looks like.
--/build.gradle
apply from: 'defaults.gradle'
defaultTasks 'clean', 'build'
--/defaults.gradle
defaultTasks 'build'
repositories {
mavenCentral()
}
--/settings.gradle
include 'common-ejb'
include 'project1'
include 'project1-ejb'
include 'logging'
--/logging/build.gradle
apply from: '../defaults.gradle'
apply plugin: 'java'
dependencies {
compile 'log4j:log4j:1.2.+'
}
--/common-ejb/build.gradle
apply from: '../defaults.gradle'
apply plugin: 'java'
dependencies {
compile 'javax:javaee-api:6.0'
compile project(':logging')
}
--/project1-ejb/build.gradle
apply from: '../defaults.gradle'
apply plugin: 'java'
dependencies {
compile 'javax:javaee-api:6.0'
compile project(':common-ejb')
compile project(':logging')
}
// THIS IS THE WORKAROUND, I don't want to explicitly modify the Class-Path for each EJB based on the EAR the EJB is going to be included in.
jar {
manifest {
attributes("Class-Path": project(':common-ejb').jar.archiveName)
}
}
--/project1/build.gradle
apply from: '../defaults.gradle'
apply plugin: 'ear'
apply plugin: 'java'
dependencies {
deploy project(':project1-ejb')
deploy project(':common-ejb')
earlib project(':logging')
}
Using some information from and modifying code from a question about getting all dependencies of a project from the Gradle forums.
Essentially, you want to take the EAR's deploy dependencies and see if any deploy dependencies depend on each other. If they do, you set the Class-Path to include the referenced jars.
Remove the manifest lines from project1-ejb and project2-ejb. Add the following to your defaults.gradle:
def getAllDependentProjects(project) {
if ( !project.configurations.hasProperty("runtime") ) {
return []
}
def projectDependencies = project.configurations.runtime.getAllDependencies().withType(ProjectDependency)
def dependentProjects = projectDependencies*.dependencyProject
if (dependentProjects.size > 0) {
dependentProjects.each { dependentProjects += getAllDependentProjects(it) }
}
return dependentProjects.unique()
}
gradle.projectsEvaluated {
if (plugins.hasPlugin('ear')) {
def deployProjectDependencies = configurations.deploy.getAllDependencies().withType(ProjectDependency)*.dependencyProject
deployProjectDependencies.each {
def cur = it
def cur_deps = getAllDependentProjects(cur)
def depJars = []
deployProjectDependencies.each {
def search = it
if ( cur_deps.contains(search)) {
depJars += search.jar.archiveName
}
}
depJars = depJars.unique()
if ( depJars.size() > 0 ) {
logger.info("META-INF Dependencies for deploy dependency " + cur.name + ": " + depJars)
cur.jar.manifest.attributes(
'Class-Path': depJars.join(' ')
)
}
}
}
}
This will have the desired affect. Directly after the configuration step and before build, the EAR projects will reevaluate their dependencies to see if any are cross-referenced. There may be a more efficient way, but this gets the job done.

How to generate multiple jar files with gradle's java plugin

I have a multi-project gradle build using the java plugin setup as follows:
myProj/
settings.gradle
build.gradle
util/
build.gradle
In my util project, I would like to generate 2 jars... one for packageA and one for packageB. I'm a noob with gradle so any help here would be much appreciated. Here are my settings and gradle files:
myProj/settings.gradle
include 'util'
myProj/build.gradle
subprojects {
apply plugin: 'java'
repositories {
maven {
url "http://mymavenurl"
}
}
sourceSets {
main {
java {
srcDir 'src/java'
}
}
}
}
myProj/util/build.gradle
dependencies {
.
.
.
}
jar {
baseName = 'packageA'
includes = ['com/mycomp/packageA']
}
task packageBJar(type: Jar) {
dependsOn classes
includes = ['com/mycomp/packageB']
baseName = 'packageB'
}
When I try to build my project here is the output:
:util:compileJava
:util:processResources UP-TO-DATE
:util:classes
:util:jar
:util:assemble
:util:compileTestJava UP-TO-DATE
:util:processTestResources UP-TO-DATE
:util:testClasses UP-TO-DATE
:util:test
:util:check
:util:build
I would hope to see :util:packageBJar after classes, but I'm not having any luck.
One way is to declare packageBJar as an artifact of, say, the archives configuration:
artifacts {
archives packageBJar
}
Now gradle assemble, and therefore also gradle build, will produce packageBJar.

Resources