Here is a copy of the Gradle presentation that will be given on Wednesday's Charleston Java User's Group (CJUG). This is a 1 hour presentation, so the topics in no way get into the details of what is available in Gradle. I highly encourage anyone interested in Gradle to visit www.gradle.org. The documentation on gradle.org is well written. In addition, there are plenty of examples in the absolute flexibility that Gradle provides as not only a Java build tool, but a wide variety of plugins and other incredible features.
https://docs.google.com/present/edit?id=0AbPfjtUUq51FZGhmcmo3cXdfMzdmaHJyNjJjMw&hl=en_US
Notes from my day to day Java and J2EE software development experiences and other related software development technologies.
Monday, September 19, 2011
Sunday, September 11, 2011
Introduction to Gradle Part 3
In part 1 and 2, we built a simple Gradle build file
for a Java project, war project, Groovy project , and finally a Gradle
multi-build project. We saw how these Gradle plugins worked
and how to setup complex multi-project dependencies. There is
so much that groovy Gradle can do including OSGi, Scala, reports, and much
more. The documentation for Gradle builds can be found here.
The script above is a custom task called the LumberghTask. This task asks a variety of employees pointless and useless queries, but demonstrates how custom tasks work in Gradle.
The first step to run this task will be to call the hello target. Execute the following task first:
gradle -q hello
Output:
Hello Peter ... How's it going?
Um... yah, I'm going to have to ask you to work this weekend.
Next, execute the following:
gradle -q requestWork
Output:
Hello Samir ... How's it going?
Yah, if you could get those TPS reports to me, yah that would be great
The requestWork overrides the person and request variables based on the task being called. The taskHello is calling the LumberghTask directly. There are so many combinations available in Gradle, that reading the documentation provided here is highly recommended. Gradle and Groovy provides maximum felxibility for any build environment.
Gradle customizations
Last, let's design some custom tasks. Since, we are
writing
build scripts in Groovy, Gradle build custom tasks are simple and straight-forward.
(Project D/build.gradle)
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class LumberghTask extends DefaultTask {
def person = "Peter"
def request = "Um... yah, I'm going to
have to ask you to work this weekend."
@TaskAction
def greetEmployee() {
println
"Hello ${person} ... How's it going?"
println
request
}
}
task hello(type: LumberghTask)
task requestWork(type: LumberghTask) {
person = 'Samir'
request = "Yah, if you could get those
TPS reports to me, yah that would be great"
}
The script above is a custom task called the LumberghTask. This task asks a variety of employees pointless and useless queries, but demonstrates how custom tasks work in Gradle.
The first step to run this task will be to call the hello target. Execute the following task first:
gradle -q hello
Output:
Hello Peter ... How's it going?
Um... yah, I'm going to have to ask you to work this weekend.
Next, execute the following:
gradle -q requestWork
Output:
Hello Samir ... How's it going?
Yah, if you could get those TPS reports to me, yah that would be great
The requestWork overrides the person and request variables based on the task being called. The taskHello is calling the LumberghTask directly. There are so many combinations available in Gradle, that reading the documentation provided here is highly recommended. Gradle and Groovy provides maximum felxibility for any build environment.
Introduction to Gradle Part 2
In part 1, we built project A, a simple Gradle build file that
compiled Java class files and built a jar file. Next, we will
build a war project dependent on the jar file generated from project A.
This uses Maven dependency managment. It is
possible to setup your project completely using Maven or Ivy.
Gradle also has a framework to manage it's own dependencies
and will be described shortly using subprojects.
One interesting extension of the war plugin is the Jetty
plugin. Gradle provides a library that will wrap a war in a
self-contained web container. This is nice if you have a
small web app and want to get it up and running quickly.
(Project B/build.gradle)
(Project C/build.gradle)
Files in project C...
Next, let's setup a Gradle multi-project build called UberProject which will contain projectA, project B, and project C. This mult-project build will contain the following structure:
UberProject/
settings.gradle
/ProjectA
/ProjectA/build.gradle
/ProjectB
/ProjectB/build.gradle
/ProjectC
/ProjectC/build.gradle
settings.gradle will contain the following line:
include 'ProjectA', 'ProjectB', 'ProjectC'
What is nice about the Gradle multi-project build is that the main settings.gradle and build.gradle (if existing) will be inherited and can be re-used in all of the subprojects. This is similar in concept to the Maven pom, but much easier to read and appears on the surface more straight-forward.
Next, in each project we need to use the 'dependsOn' call to manage inter-project dependencies. Remove any reference to projectA, projectB, or projectC in the dependencies section. Leave all of the third party libraries, so that we can still download these dependencies as needed.
Add the following line to project C:
dependsOn(':ProjectA')
Add the following line to project B:
dependsOn(':ProjectA')
Run gradle assemble on project C. You should see the following output.
:ProjectA:compileJava
:ProjectA:processResources
:ProjectA:classes
:ProjectA:jar
:ProjectA:assemble
:ProjectC:compileJava
:ProjectC:compileGroovy
:ProjectC:processResources
:ProjectC:classes
:ProjectC:jar
:ProjectC:assemble
BUILD SUCCESSFUL
Total time: 16.298 secs
Notice how building project C now, automatically builds the dependency of project A. Nice right?
Now, let's have some fun with our projects and flex the depedency management features in Gradle by adding a circular dependency to project A. One of the best ways to understand how Gradle works is to break the build.
Add the following line to project A:
dependsOn(':ProjectC')
You should see the following output:
FAILURE: Build failed with an exception.
* Where:
Build file '/home/robert/workspace/UberProject/ProjectC/build.gradle' line: 12
* What went wrong:
A problem occurred evaluating project ':ProjectC'.
Cause: Circular referencing during evaluation for project ':ProjectA'.
* Try:
Run with -s or -d option to get more details. Run with -S option to get the full (very verbose) stacktrace.
BUILD FAILED
Total time: 8.698 secs
By adding a reference to projectC to projectA, we have added a circular dependency. Gradle finds circular dependencies in multi-project builds and does not allow a build to continue once the circular dependency is found.
Build Project B (simple Java war build)
(Project B/build.gradle)
// We can add
comments to the build script using typical Java/Groovy notation
// We need to specify the java plugin which by
default
looks for src/main/java
usePlugin 'java'
usePlugin 'war' // Use the war plugin to build a war file
usePlugin 'maven'
version = 1.0
artifactId='projectB'
repositories { // reference all of the required Maven repositories.
mavenRepo(urls :
"file://localhost/tmp/repos/")
mavenCentral() //
Setup the Maven repository
}
dependencies { // Add external dependencies here
compile group: 'commons-cli',
name: 'commons-cli', version: '1.0'
compile group:
'projectA', name: 'projectA', version:'1.0'
}
uploadArchives { // Again upload our final product into the local Maven
repository
repositories.mavenDeployer {
repository(url: "file://localhost/tmp/repos/")
pom.groupId = 'projectB'
pom.version = '1.0'
pom.artifactId = 'projectB'
}
}
assemble.dependsOn ':uploadArchives'
sourceSets { // Defines which source files to include in the build
main {
java {
}
resources {
}
}
}
ProjectB/.classpath
ProjectB/.settings/org.eclipse.jdt.core.prefs
ProjectB/bin/com/pac/domain/Manager.class
ProjectB/.project
ProjectB/build.gradle
ProjectB/build/libs/ProjectB-3.1.war
ProjectB/build/classes/main/com/pac/domain/Manager.class
ProjectB/build/classes/main/Manager.class
ProjectB/build/ivy.xml
ProjectB/build/poms/pom-default.xml
ProjectB/src/main/java/com/pac/domain/Manager.java
ProjectB/.settings/org.eclipse.jdt.core.prefs
ProjectB/bin/com/pac/domain/Manager.class
ProjectB/.project
ProjectB/build.gradle
ProjectB/build/libs/ProjectB-3.1.war
ProjectB/build/classes/main/com/pac/domain/Manager.class
ProjectB/build/classes/main/Manager.class
ProjectB/build/ivy.xml
ProjectB/build/poms/pom-default.xml
ProjectB/src/main/java/com/pac/domain/Manager.java
Build Project C (Groovy Class build)
In project C, we will build a Groovy based project that uses Java libraries and is also dependent on our project A. This Gradle maven project will again use the Maven repository to dowload dependencies and upload the final artifiact after the build.
(Project C/build.gradle)
// We can add comments to the build script using typical Java/Groovy
notation
// We need to specify the java plugin which by
default looks for src/main/java
usePlugin 'groovy'
usePlugin 'maven'
usePlugin 'java'
version = 1.0
repositories {
mavenRepo(urls :
"file://localhost/tmp/repos/")
mavenCentral() //
Setup the Maven repository
}
dependencies { // Add external dependencies here
groovy
module('org.codehaus.groovy:groovy-all:1.7.0') {
dependency('commons-cli:commons-cli:1.0')
dependency('projectA:projectA:1.0')
}
}
uploadArchives {
repositories.mavenDeployer {
repository(url: "file://localhost/tmp/repos/")
pom.groupId = 'projectC'
pom.version = '1.0'
pom.artifactId = 'projectC'
}
}
assemble.dependsOn ':uploadArchives'
sourceSets { // Defines which source files to include in the build
main {
groovy {
}
resources {
}
}
}
Files in project C...
ProjectC/.classpath
ProjectC/.settings/org.eclipse.jdt.core.prefs
ProjectC/bin/com/pac/domain/Company.class
ProjectC/.project
ProjectC/build.gradle
ProjectC/build/libs/ProjectC-1.0.jar
ProjectC/build/classes/main/com/pac/domain/Company.class
ProjectC/build/ivy.xml
ProjectC/build/poms/pom-default.xml
ProjectC/src/main/groovy/com/pac/domain/Company.groovy
Configuring Gradle Multi-Project Builds
Next, let's setup a Gradle multi-project build called UberProject which will contain projectA, project B, and project C. This mult-project build will contain the following structure:
UberProject/
settings.gradle
/ProjectA
/ProjectA/build.gradle
/ProjectB
/ProjectB/build.gradle
/ProjectC
/ProjectC/build.gradle
settings.gradle will contain the following line:
include 'ProjectA', 'ProjectB', 'ProjectC'
What is nice about the Gradle multi-project build is that the main settings.gradle and build.gradle (if existing) will be inherited and can be re-used in all of the subprojects. This is similar in concept to the Maven pom, but much easier to read and appears on the surface more straight-forward.
Next, in each project we need to use the 'dependsOn' call to manage inter-project dependencies. Remove any reference to projectA, projectB, or projectC in the dependencies section. Leave all of the third party libraries, so that we can still download these dependencies as needed.
Add the following line to project C:
dependsOn(':ProjectA')
Add the following line to project B:
dependsOn(':ProjectA')
Run gradle assemble on project C. You should see the following output.
:ProjectA:compileJava
:ProjectA:processResources
:ProjectA:classes
:ProjectA:jar
:ProjectA:assemble
:ProjectC:compileJava
:ProjectC:compileGroovy
:ProjectC:processResources
:ProjectC:classes
:ProjectC:jar
:ProjectC:assemble
BUILD SUCCESSFUL
Total time: 16.298 secs
Notice how building project C now, automatically builds the dependency of project A. Nice right?
Now, let's have some fun with our projects and flex the depedency management features in Gradle by adding a circular dependency to project A. One of the best ways to understand how Gradle works is to break the build.
Add the following line to project A:
dependsOn(':ProjectC')
You should see the following output:
FAILURE: Build failed with an exception.
* Where:
Build file '/home/robert/workspace/UberProject/ProjectC/build.gradle' line: 12
* What went wrong:
A problem occurred evaluating project ':ProjectC'.
Cause: Circular referencing during evaluation for project ':ProjectA'.
* Try:
Run with -s or -d option to get more details. Run with -S option to get the full (very verbose) stacktrace.
BUILD FAILED
Total time: 8.698 secs
By adding a reference to projectC to projectA, we have added a circular dependency. Gradle finds circular dependencies in multi-project builds and does not allow a build to continue once the circular dependency is found.
Introduction to Gradle Part 1
Many build tools have been created for building and packaging software. Make, Ant, Maven, etc., all seem to have their own frameworks of completing tasks that are driven by the structure of each build tool. The industry while successfully using existing tools constantly requires more features in a build tool to adapt to newer technologies that are emerging (OSGi, Grails, Scala, Jetty, numerous advances in IDEs, etc.).
This article focuses on using Gradle, because of the wide usage of Java and J2EE as an enterprise platform along with Groovy as a Java meta-language. Gradle is also poised to become the next widely adopted build tool in the world of software build tools and configuration management because Gradle bridges the feature gap between Ant and Maven.
Gradle is a build tool based on the popular language Groovy. Groovy is an extension of Java and has many built-in features and frameworks for completing complex tasks. Gradle has many features which will be described briefly.
Gradle fills in the build tool feature gaps that the two most commonly used build tools, Maven and Ant. Either tool may have one or less of the following features, but neither tool has all of the following features:
- Both Ant and Maven build scripts are based in xml. A build tool that allows the flexibility of a true language allows the developer to include libraries into the build file. The semantics of a language based build tool also allow flexible development and lower learning curves if the Domain Specific Language (DSL) used in the build tool are already known.
- Software configuration managers are often the keepers of all build knowledge. A build tool that does not require special knowledge either due to complexity of a project or intimate knowledge about a build tool configuration keeps both developers and software configuration managers involved in the process at all times.
- The choice of being able to create builds by convention ala Maven or in a more free manner such as Ant is an either/or choice of build tools.
- Good dependency management. While Ant has dependency management in Ivy and Maven has its own dependency management. A tool that is simple and excels in dependency management is needed.
- Partial builds. In Maven when building a multi-project module it is difficult to build only specific projects without building all projects.
- A potpourri of plugins and other 3rd party modules that are easy to integrate into a build. Also, a build tool should allow users to easily build their own customizations with minimum hassle.
The history of software build tools has always had challenges. Builds in Make for instance used tabs in the semantics of a build file, Ant without ant-contrib or other 3rd party libraries was never meant to run a for loop, Maven pom files are difficult to manage for the average developer trying to include a custom task not in the standard lifecycle. Each build tool had its own idiosyncrasies.
Gradle Features
Gradle provides the following features:- Robust dependency management. Gradle uses Ivy to resolve dependencies on third party libraries or even inter-project dependencies. Circular dependencies will also cause build failures. Gradle also builds on Ivy with its own distinct features not found in the standard Ivy distribution.
- Gradle allows you to build by convention, IF you choose to build by convention. The alternative of building by non-convention or a unique non-standard convention is just as easy to select.
- Ant tasks can be called directly from Gradle. If a project already is written in ANT, it is possible to convert all, some, or none of the build scripts to Gradle.
- Gradle being a meta-language of Java allows many of the same object types to be introduced into the build scripts. The richness of Java/Groovy objects introduce a higher level of flexibility when writing build scripts.
- Gradle
executes builds by phases. Maven has a similar architecture,
but
Gradle makes configuring special hooks by execution phase simple.
- Support for existing Maven and Ivy repositories exists through client modules.
- Multiproject builds are made simple in Gradle with features such as configuration injection across projects, partial builds, and robust transitive dependency management.
- Since Gradle is based on Groovy, it is possible to include third party libraries and customize build scripts based on the Groovy and Java languages.
- Numerous plugins for Jetty, wars, Scala, Maven, code quality (metrics), OSGi, Eclipse, and Reporting.
- A Gradle wrapper, that will setup Gradle-free machines with a fresh new copy of Gradle from your repository.
A Simple Build Script
Let us start by creating a simple Gradle build script for Java code. The installation and setup of Gradle can be found here. Project A is a simple java project that follows Java naming conventions and uses a Maven central repository and a local maven repository located in the local file system at /tmp/repos/.Build Project A (simple Java jar build)
(Project A/build.gradle)
// We can add comments to the build script using
typical
Java/Groovy notation
//We need to specify the java plugin which by
default
looks for src/main/java
usePlugin 'java'
usePlugin 'maven'
version = 1.0
configure(install.repositories.mavenInstaller) {
pom.version = '1.0'
pom.artifactId = 'project-A'
}
repositories {
mavenCentral() //
Setup the Maven repository
mavenRepo(urls :
"file://localhost/tmp/repos/")
}
// call uploadArchives to deploy to repository
uploadArchives {
repositories.mavenDeployer {
repository(url: "file://localhost/tmp/repos/")
pom.groupId = 'projectA'
pom.version = '1.0'
pom.artifactId = 'projectA'
}
}
install.dependsOn ':uploadArchives'
dependencies { // Add external dependencies here
compile group:
'commons-cli', name: 'commons-cli', version: '1.0'
compile group:
'commons-logging', name: 'commons-logging', version: '1.0.4'
compile group:
'commons-net', name: 'commons-net', version: '1.4.1'
compile group:
'junit', name: 'junit', version: '4.7'
compile group:
'org.codehaus.groovy', name: 'groovy-all', version: '1.6.2'
compile group:
'quartz', name: 'quartz', version: '1.5.1'
compile group:
'xstream', name: 'xstream', version: '1.2.1'
compile group:
'commons-net', name: 'commons-net', version: '2.0'
}
sourceSets { // Defines which source files to include in the build
main {
java {
}
resources {
}
}
}
Run 'gradle assemble'
Output:
:compileJava
downloading (2 KB)
http://repo1.maven.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0.pom
..
downloading (2 KB)
http://repo1.maven.org/maven2/commons-lang/commons-lang/1.0/commons-lang-1.0.pom
...
downloading (5 KB)
http://repo1.maven.org/maven2/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom
.....
downloading (1 KB)
http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.pom
..
downloading (24 KB)
http://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/1.6.2/groovy-all-1.6.2.pom
...................
downloading (9 KB)
http://repo1.maven.org/maven2/org/apache/ant/ant/1.7.1/ant-1.7.1.pom
........
downloading (4 KB)
http://repo1.maven.org/maven2/org/apache/ant/ant-parent/1.7.1/ant-parent-1.7.1.pom
.....
downloading (2 KB)
http://repo1.maven.org/maven2/org/apache/ant/ant-launcher/1.7.1/ant-launcher-1.7.1.pom
...
downloading (6 KB)
http://repo1.maven.org/maven2/jline/jline/0.9.94/jline-0.9.94.pom
.....
downloading (146 B)
http://repo1.maven.org/maven2/quartz/quartz/1.5.1/quartz-1.5.1.pom
..
downloading (371 B)
http://repo1.maven.org/maven2/xstream/xstream/1.2.1/xstream-1.2.1.pom
..
downloading (6 KB)
http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream/1.2.1/xstream-1.2.1.pom
......
downloading (7 KB)
http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream-parent/1.2.1/xstream-parent-1.2.1.pom
.......
downloading (638 B)
http://repo1.maven.org/maven2/xpp3/xpp3_min/1.1.3.4.O/xpp3_min-1.1.3.4.O.pom
..
downloading (7 KB)
http://repo1.maven.org/maven2/commons-net/commons-net/2.0/commons-net-2.0.pom
.......
downloading (24 KB)
http://repo1.maven.org/maven2/org/apache/commons/commons-parent/11/commons-parent-11.pom
...................
downloading (4 KB)
http://repo1.maven.org/maven2/org/apache/apache/4/apache-4.pom
.....
downloading (30 KB)
http://repo1.maven.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0.jar
.......................
downloading (38 KB)
http://repo1.maven.org/maven2/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar
............................
downloading (232 KB)
http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.jar
..................................................................................
downloading (4.45 MB)
http://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/1.6.2/groovy-all-1.6.2.jar
.........................................................................
downloading (353 KB)
http://repo1.maven.org/maven2/quartz/quartz/1.5.1/quartz-1.5.1.jar
........................................................................
downloading (63 KB)
http://repo1.maven.org/maven2/commons-lang/commons-lang/1.0/commons-lang-1.0.jar
..............................................
downloading (1.32 MB)
http://repo1.maven.org/maven2/org/apache/ant/ant/1.7.1/ant-1.7.1.jar
...............................................................................
downloading (87 KB)
http://repo1.maven.org/maven2/jline/jline/0.9.94/jline-0.9.94.jar
..............................................................
downloading (12 KB)
http://repo1.maven.org/maven2/org/apache/ant/ant-launcher/1.7.1/ant-launcher-1.7.1.jar
..........
downloading (349 KB)
http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream/1.2.1/xstream-1.2.1.jar
..................................................................................
downloading (24 KB)
http://repo1.maven.org/maven2/xpp3/xpp3_min/1.1.3.4.O/xpp3_min-1.1.3.4.O.jar
...................
:processResources
:classes
:jar
:assemble
BUILD SUCCESSFUL
Total time: 1 mins 13.323 secs
The build will generate classes and a final jar file in the following directories:
ProjectA/.classpath
ProjectA/.classpath.old
ProjectA/.settings/org.eclipse.jdt.core.prefs
ProjectA/bin/com/pac/domain/Employee.class
ProjectA/.project
ProjectA/build.gradle
ProjectA/build/libs/ProjectA-1.0.jar
ProjectA/build/classes/main/com/pac/domain/Employee.class
ProjectA/build/ivy.xml
ProjectA/build/poms/pom-default.xml
ProjectA/src/main/java/com/pac/domain/Employee.java
One thing to note. If all of the dependencies have not been added to the gradle an error will occur. The list of dependencies includes transitive dependencies or libraries that are required by libraries listed in your dependency list. One way to automate the compilation of transitive dependencies is to add the following line to the build script...
configurations.compile.transitive = true
Any library that is required, but is not explicitly defined in the build script will be managed automatically with this entry. Also, it is possible to manage transitive dependencies at a more granular level (disabling for specific libraries). One example of this is as follows:
dependency("commons-cli:commons-cli:1.0") {
transitive = false
}
Useful Firefox Plugins For Web Development
I found this article useful in my AJAX development. Thought I would share. Enjoy!
Here's another personal favorite plugin that reads/modifies HTTP headers.
Here's another personal favorite plugin that reads/modifies HTTP headers.
Subscribe to:
Posts (Atom)