-
Notifications
You must be signed in to change notification settings - Fork 1
Plugin
During the development of the Tangram framework project a set of build related things went into a plugin for the Gradle tool.
The functionality of this Tangram Gradle Plugin is only in very small parts directly related to Tangram. It is more or less a general purpose plugin for applications needing
- Byte-code transformation of model classes for
- JDO, JPA, and Ebean ORM layers
- Minification of CSS and JavaScript codes to be placed in WAR artifacts
- Support underlying of WAR files into others (similar to overlays)
Starting with version 1.0.5 the plugin can be used from the central Gradle plugins repository. The plugin id is
tangram.tools
Just a few lines have to be added to your Gradle build script to use the plugin with a stable release version:
plugins {
id "tangram.tools" version "1.2.0"
}
Snapshot versions or multiproject layouts need a few more lines for the "old style" gradle pluding usage:
buildscript {
repositories {
// Only used for tangram snapshots
maven { url "http://oss.jfrog.org/artifactory/oss-snapshot-local" }
jcenter()
}
dependencies {
// Cannot work with the version labels from the tangram plugin here
classpath 'tangram:gradle-plugin:1.2.0'
}
}
...
apply plugin: 'tangram.tools'
Parts of a build.gradle for tangram using its plugin.
All of the following steps described here take place without any additional configuration.
When used with Java projects - and when some data model classes are discovered, - the plugin tries to prepare them for use the respective Object Relational Mapper (ORM). The ORM APIs supported are
- Java Data Objects (JDO)
- Java Persistence API (JPA)
- EBean
These APIs in turn are supported by a number of implementations. The supported implementations are
- DataNucleus Access Platform (JDO and JPA)
- EBean
- EclipseLink
- Hibernate
- OpenJPA
These OR-Mapper API implementations require (DataNucleus and EBean) or recommend (the others) to apply byte-code transformations called "Enhancing" or "Weaving" to the class files. The compiled code is extended with some database access support to implement the active record pattern more or less seamless.
The API and implementation library in use is discovered from the names of the elements of the class path of the project. If one of the mentioned libraries is found, the corresponding byte-code transformation is applied to the appropriate step (post compile or pre jar creation).
martin@nelson:~/proj/tangram/sites/naturinspiriert$ gradle clean build
:clean
:compileJava
*Performing DataNucleus JPA byte code transformation.*
ENHANCED (Persistable) : org.naturinspiriert.RootGroup
ENHANCED (Persistable) : org.naturinspiriert.Topic
ENHANCED (Persistable) : org.naturinspiriert.AbstractGroup
ENHANCED (Persistable) : org.naturinspiriert.ImageData
ENHANCED (Persistable) : org.naturinspiriert.Article
ENHANCED (Persistable) : org.naturinspiriert.Linkable
ENHANCED (Persistable) : org.naturinspiriert.Group
DataNucleus Enhancer completed with success for 7 classes. Timings : input=60 ms, enhance=54 ms, total=114 ms. Consult the log for full details
7 classes enhanced.
:processResources
:classes
:jar
:war
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
BUILD SUCCESSFUL
Total time: 4.53 secs
(Highlighted message to indicate use of the DataNucleus Enhancer)
The byte-code transformations directly use the transformer of the respective library in use except for the OpenJPA case, where the ant task of the enhancer is integrated. Some of the transformers issue some logging.
Additionally it is possible to switch of the byte code transformation for JPA annotated classes by adding to your build file
// build.gradle:
enhancer.enabled=false
in case this might be necessary e.g. to only use the other parts of the plugin. Also EclipseLink, Hibernate, and OpenJPA support the use of plain Java classes without the byte-code transformation.
If you don't use the web app underlying / overlaying you can avoid the small overhead of this process by switching of the extraction and combination with the following switch:
// build.gradle:
overlay.enabled=false
version 1.1 and onwards feature
When used in conjunction with the war plugin, CSS and JavaScript resources are automatically minified.
The plugin checks for resources with a filename extension .css for Cascading
Style Sheets and .js
for JavaScript. Matching resources are minified using
the YUI Compressor.
It is not possible to minify resource included from archive files but only file resources local to your project. So contents from archives - while being included in the resulting web archive - cannot be minified. (We would expect WAR files to contain minified resources like WAR files generated using this plugin do.)
The plugin introduces a configuration named webapp for modules using the war plugin. Dependencies given for this configuration are extracted into the resulting war artifact.
// build.gradle:
dependencies {
webapp "tangram:tangram-core:$tangram_version:war@war"
webapp "tangram:tangram-editor:$tangram_version:war@war"
compile "tangram:tangram-core:$tangram_version"
// Persistence API JPA
compile "tangram:tangram-jpa:$tangram_version:nucleus"
compile "org.datanucleus:datanucleus-api-jpa:$versions.datanucleus"
compile "org.datanucleus:datanucleus-core:$versions.datanucleus"
compile "$versions.jdo_api"
compile "$versions.persistence_api"
runtime "org.datanucleus:datanucleus-mongodb:$versions.datanucleus"
compile "tangram:tangram-editor:$tangram_version"
runtime "tangram:tangram-dinistiq:$tangram_version"
runtime "org.slf4j:slf4j-log4j12:$versions.slf4j"
providedCompile "$versions.servlet_api"
providedCompile "$versions.jsp_api"
}
This process is not really described well if called an overlay, so I call it underlying, since your web application's directory in fact is the real overlay and as a result, the other archives referenced and included must be the underlying.
If your WAR relies on the contents of another pre-packaged or incomplete WAR, the contents of the latter will be copied into your resulting web application while you can override any file in this archive from your local web application contents directory.
The plugin maintains a version object which collects some version strings for a
number of libraries. This ensures that any project using the plugin can use
these libraries with recent versions and version changes are applied in sync.
The use of this part is optional and you have to explicitly use the versions in
your build file since this cannot be applied transparently thus not replacing
something like the <dependencyManagement/>
in Maven based projects.
Some random examples:
dependencies {
compile "org.pac4j:pac4j-openid:$versions.pac4j"
compile ("org.apache.openjpa:openjpa:$versions.openjpa") {
exclude group: 'asm'
}
compile "org.eclipse.persistence:org.eclipse.persistence.jpa:$versions.eclipselink"
compile "$versions.persistence_api"
compile "org.hibernate:hibernate-core:$versions.hibernate"
compile "org.datanucleus:datanucleus-api-jpa:$versions.datanucleus"
compile "org.dataucleus:datanucleus-core:$versions.datanucleus"
compile "$versions.jdo_api"
runtime "org.slf4j:slf4j-log4j12:$versions.slf4j"
testCompile "org.testng:testng:$versions.testng"
// your container will have this for you
providedCompile "$versions.servlet_api"
providedCompile "$versions.jsp_api"
}
Of course it is still possible to call the methods performing the different tasks directly like described in the 0.9 plugin blog post. This should only be necessary if you e.g. want to enhance files in the test section of your code, which is considered a very rare case.