Sunday, December 12, 2010

Complement of mrhaki's "Run Java Application From Build Script"

If you want to know how to run java app in build.gradle, you should check mrhaki's post: Run Java Application From Build Script. That post gave me big help on this task. In this post, I will give a complement on a topic that missed in that post.
In my app, I have some code that needs data from command line, such as:
    def input= new DataInputStream(System.in)
println "Work Dir:"
def rootDir= input.readLine()
println "Test Plan:"
def testplan= input.readLine()
When I applied the method I learned from mrhaki's post, I could run my app, but have no chance to input some data from command line. The app exited with an exception because it did not pause and got null from command line! After digging the gradle api doc, I found I could set the value of standardInput property of JavaExec task. So I made some change to my build.gradle:
task (processplan, dependsOn: classes, type: JavaExec) {
main= '....'
classpath= sourceSets.main.runtimeClasspath
standardInput= System.in
}
Note that the last line. I set the value of standardInput to "System.in". Then I ran the build task again. This time, the app stopped to wait for user's inputting. And app worked fine!
So, If your app needs user to input some data from command line, you'd better set the value of standardInput. Hope this tip is help for you.

Monday, June 14, 2010

Fix "junitvmwatcherXXX.properties could not be found" during grails unit test

Recently, I forked grails-core to fix the GRAILS-5876. But, when I modified and ran "gradlew testSingleMockUtils", I got a java.io.FileNotFoundException:
java.io.FileNotFoundException: D:\grails\grails-core\junitvmwatcher476409304.properties(no such file or directory)
Compile phase (sources compile and tests compile) was ok, the exception was thrown from the Unit Test phase, and the unit test didn't be launched at all. I tried another build approach, "ant -Dtest=MockUtils test", and got the same exception.
This is very confusing, beacause I launched unit tests successfully under grails 1.2. Google could not give me any suggest this time. Taking a close look at the output on the screen, I found some messages which showed the memory was not enough for running unit tests. That is it!
I compared the unit-test.xml in my local git repository with the one in grails 1.2 dist, and found there was some diffrence in the target "run-test" between these two files:
  • my local git repository:
  •   <target name="run-test" depends="defineTestingScope, build-test,-jar-app-files" unless="_skipTests_">
    <delete dir="${grails.test.reports}" />
    <mkdir dir="${grails.test.reports}" />
    <echo>Test being run ${test} from ${grails.test.build}</echo>
    <junit fork="true" forkmode="perBatch" clonevm="true" printsummary="on">
    <!-- only fork VMs as needed -->
    <sysproperty key="grails.cli.testing" value="true"/>
    <jvmarg line="-server -Dgroovy.grails.joint=${groovy.grails.joint} ${args.memory} ${args.debug}"/>
  • grails 1.2 dist:
  •   <target name="run-test" depends="defineTestingScope, build-test,-jar-app-files" unless="_skipTests_">
    <delete dir="${grails.test.reports}" />
    <mkdir dir="${grails.test.reports}" />
    <echo>Test being run ${test} from ${grails.test.build}</echo>
    <junit fork="true" forkmode="perBatch" clonevm="true" printsummary="on">
    <!-- only fork VMs as needed -->
    <sysproperty key="grails.cli.testing" value="true"/>
    <jvmarg value="-server" />
    <jvmarg value="-Xmx1G" />
    <jvmarg value="-Xms256m" />
    <jvmarg value="-XX:MaxPermSize=256m"/>
    <jvmarg value="-Dgroovy.grails.joint=${groovy.grails.joint}" />
    ...
The solution is obvious. Replacing the last statement in the former build script with the last 5 statements in the latter, I could run the unit test successfully again. Now, let's fix the gradle build script. Open the unit-test.gradle, and search the following statement:
options.forkOptions.jvmArgs = ["-server", "-Xmx1500m", "-Xms256m", "-XX:MaxPermSize=256m", "-Dgroovy.grails.joint=true"]
Change "-Xmx1500m" to "-Xmx1G", and save the file. Then you should run "gradlew testSingleMockUtils" successfully.
There are other reasons can cause "junitvmwatcherXXX.properties could not be found", you could get some advices from google using the key works "ant junitvmwatcherXXX.properties".

Saturday, June 12, 2010

Return partial Domain Class

Reading the description of GRAILS-5791, I found this interesting question. The asker expects the JSON returned by "domain as JSON" not including some properties he lists.
There are serval solutions, the comments following that question have list two ones. Here I will give my own one. In my way, I will add one method to the domain classes in the grails app: part, which returns a map including or excluding some properties of a domain class. Then you can render the result map as JSON. The following shows how to use this method:
  def job= Job.get(1)

//include
render job.part(include:['categorys', 'source']) as JSON

//except
render job.part(except:['id', 'version']) as JSON
This sample is very intuitive. The first statement will result in a JSON only including categorys and source; the JSON rendered by second statement will include all the properties of the domain class except id and version.
Using part, you can make your life easier and also make your code more grace.
Now, let's see how to adding the part method to the domain classes:
  • how: In groovy, in order to add a method to an object dynamiclly, we can use mop.
  • when: In grail app, there is a file named BootStrap.groovy, where is a good place to do some initialization works.
When we know how and when to do that job, here is the detail:
import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events

class BootStrap {
def grailsApplication

def excludedProps = [Events.ONLOAD_EVENT,
Events.BEFORE_DELETE_EVENT, Events.AFTER_DELETE_EVENT,
Events.BEFORE_INSERT_EVENT, Events.AFTER_INSERT_EVENT,
Events.BEFORE_UPDATE_EVENT, Events.AFTER_UPDATE_EVENT]

def init = { servletContext ->
grailsApplication.domainClasses.each{ domainClass ->
domainClass.metaClass.part= { m ->
def map= [:]
if(m.'include'){
m.'include'.each{
map[it]= delegate."${it}"
}
}else if(m.'except'){
m.'except'.addAll excludedProps
def props= domainClass.persistentProperties.findAll {
!(it.name in m.'except')
}
props.each{
map[it.name]= delegate."${it.name}"
}
}
return map
}
}
}
def destroy = {
}
}
You also can change this to a plugin, then you can use this feature across different grails apps. Hope you enjoy this.

Saturday, May 01, 2010

Summary on Transaction Rollback in Grails

This post is a summary on how to rollback transactions in grails application, and highlights a stain in grails reference document.

Rollback Programmatic Transactions

In Grails, we can use withTransaction method on domain classes to deal with programmatic transactions. This method takes a closure, which receives a TransactionStatus instance as its first argument. In order to rollback transactions, we can invoke the setRollbackOnly() method on TransactionStatus. Here is an example from grails reference document:
Account.withTransaction { status ->
def source = Account.get(params.from)
def dest = Account.get(params.to)
def amount = params.amount.toInteger()

if(source.active) {
source.balance -= amount
if(dest.active) {
dest.amount += amount
}else {
status.setRollbackOnly()
}
}
}

Rollback Declarative Transactions

With service, it's not a big deal to implement declarative transactions in grails. If you want to rollback, all that you need to do is to throw a RuntimeException or its subclass in service method. The following code shows how to do this job:
class DomainbService {
boolean transactional = true

def service2() {
new B().save()
throw new RuntimeException("save b failed!")
}
}
There is one thing you should notice: grails refernce document doesn't spot the exception you throw in method must be an RuntimeException object. Actually, if you throw an Exception object, the transaction doesn't rollback. You can have a test to verify this. And in spring reference document, you can find that you should throw an "unchecked" exception to trigger a rollback when you are using declarative transaction.

Sunday, March 28, 2010

A simple PageBus taglib

Today, javascript component is a must-be part in many web applications. As more and more such components are included in the web page, the difficulty of interaction between these components is increasing. There is a way to simplify this problem: Event. With it, what you need to do is to register your callback with the event that will be fired by your interested component, and to wait for the magic happened.

All seems good, but "how to register your callback with the component you care about?" If there is a long distance between those two component, this register is not a easy work. That's why I choose PageBus as the backbone of the interaction between components in my project.

If you are familiar with jms, you can simply think pagebus as a jms implemention in the web page. Here is an intuitive picture from its document:



The biggest benefit you can acquire from PageBus is full decoupling between those two parts of interaction. One component doesn't bother another. The whole interaction process is:
  1. subscriber registers a callback with a well-known topic
  2. publisher delivers a message to a well-known topic
  3. callback will be invoked when subscriber gets a message from the topic it registered.
Usage of PageBus is very simple, you just need:
  1. To Download it from here and include pagebus.js in your page.
  2. To register:
        window.PageBus.subscribe(topic, scope, function(sub, message, data){
    .....
    }, data);
  3. To publish:
        window.PageBus.publish(topic, message);
At the end of this post, I will create a simple PageBus taglib to show how to use it.

First, let's create a new Grails App, grails create-app pagebus.

Next, enter your application directory and create a taglib, grails create-tag-lib pagebus.

In your taglib file, write down the code:

class PagebusTagLib {

static namespace= "pagebus"

static final DEFAULT_TOPIC= "app.topic.default"

def include= {
def js= """
<script type="text/javascript">
var App = {
publish: function(topic, message){
window.PageBus.publish(topic, message);
},
subscribe: function(topic, scope, fn, data){
window.PageBus.subscribe(topic, scope, fn, data);
}
}
</script>
"""
out << g.javascript(src:'pagebus/pagebus.js')<< js
}
}
copy pagebus.js to the pagebus/web-app/js/pagebus.

In the app index.gsp,

  • add <pagebus:include/> to <head> section;
  • add a button in your <body> for publishing a "hello world!" message
        <input type="button" value="publish"
    onclick="App.publish('topic1', {message: 'Hello World!'})">
  • register your callback to show the message the subscriber received.
        <g:javascript>
    App.subscribe("topic1", null, function(sub, message, data){
    alert(message.message);
    }, null);
    </g:javascript>
Finally, run your app and test it. Now, you just create your first PageBus application!

Thursday, February 25, 2010

Event Applied: When to minify js and css files in your grails projects

High Performance Web Sites is a great book discussing how to accelerate your web sites. The rule 10 in this book is "Minify JavaScript", which I think can be applied in my grails projects easily.
There are some tools can be used to minify your js and css files, such as JSMIN, Dojo compressor, Edwards' Packer and YUI Compressor. Since I was using YUI these days, I decide to choose YUI Compressor to do this job.
The first solution comes into my mind is to create a Grails Script to process js and css files by "grails create-script". On second thought, I think this is not an appropriate one:
  • If it changes the name of js or css files, you have to change the corresponding files name in your frontend source code. This is annoying and error-prone.
  • If it doesn't change the files' name, it will modify the content of js and css source files. This can also make you unhappy: facing a minified js and css files, you can even hardly change the name of a variable. It is a big problem!
So the solution what I need is: a) which can minify js and css files, b) which can not change the name of files and the content of source code. By controlling the grails application build process, I can achieve my goal. Now, I can hear what you said: Event. That's it! We just need to create an event handler to do this job, and the event we should focus on is : CreateWarStart,which will be fired before grails war your grails application.
Since we know how to do it, let's do it:
  1. Downloading YUI Compressor,which usage is simple:"java -jar yuicompressor-x.x.x.jar inputfile -o outputfile".
  2. Unzipping it and copying YUI Compressor binary to lib directory in your grails project.
  3. Creating a "_Event.groovy" in your grails project's script directory:
       eventCreateWarStart = { warLocation, stagingDir ->
    stagingDir.eachFileRecurse{
    if(it.name.endsWith('.js')||it.name.endsWith('.css')){
    def f= it.absolutePath

    println "Minizing ${f}......................"
    ant.java(jar:"${basedir}/lib/yuicompressor-2.4.2.jar",
    fork: true){
    arg(value: "${f}")
    arg(value: "-o")
    arg(value: "${f}")
    }
    println "Minizing ${f}.................done!"
    }
    }
    }
Only 3 steps, you can minify all the js and css files in your grails projects. Typing "grails war" to test it. Of course, it is not perfect: it always does minification and doesn't care if the js or css files have been minified. If there are many minified files in your projects, which could come from the js lib(such as yui/dojo/jquery) you include, it will waste your cpu time. The way to fix it is simple: you can define an excluding directory list, all directories in it will not be processed.
Another interesting thing is: if there are some errors in your javascript source, YUI Compressor won't minify it(this won't break the build process). So you get an additional checking javascript function ;). Hope you enjoy it!

Saturday, January 16, 2010

A Note On Validation Non Domain classes

Validation non domain classes is a very cool grails feature, but when you use it, you should remember one thing: Invoking clearErrors method before re-validation, specially last validate invocation returns false.
A piece of script means a lot of things:
def u= new foxgem.test1.User1(name:'')
assert u.validate() == false
u.name='foxgem'
assert u.validate() == false
u.clearErrors()
assert u.validate() == true
Here, there is a blank constraint on name property of foxgem.test1.User1. But the note is not necessary to Domain Class, so the second assert statement in the script will failed when foxgem.test1.User1 is a domain class.
This is very confusing, I hope this will be imporved in the future of Grails.