Tuesday, April 29, 2008

How to add transactions to your grails business logic

There are 3 common ways in which you can surround your existing groovy or java code with transactions support under grails framework:

1. grails 'service' classes are transactional by default.
As long as the following statement is included in your grail service class, all methods executed will be executed under ongoing transaction. If no transaction exists when entering the service method, a new one will be auto created.

boolean transactional = true

2. If you are working with one or more grails domain objects in your code, wrap the code in 'withTransaction' block against one of the domain objects.
Described in more detail here:
http://grails.org/doc/1.0.x/guide/single.html#5.6%20Programmatic%20Transactions

3. Manually access hibernate session and create transaction against the session. This of course is tedious way and would require you to handle any exceptions yourself.

def session = sessionFactory.getCurrentSession()

Transaction tx = session.beginTransaction()

<>

tx.commit()
or
tx.rollback()

at the end.

4. Use spring declarative transaction control. I personally haven't tried it with grails; if you have please free feel to comment.

Saturday, April 12, 2008

grails continuous integration using hudson

Hudson is a powerful continuous integration environment for Windows / Linux systems. The big selling point of hudson is its simplicity compared to other popular integration systems as cruisecontrol: everything is done using the intuitive GUI with guidance on each step. No mucking around with xml files or shell commands to check system status ...

Described here are the steps you need to follow to automate the grails build, unit and regression testing environment using hudson continuous integration environment.

Prerequisites:

1. grails 1.0.1 or higher
2. jdk 1.5 or higher
3. hudson 1.2 onwards ( earlier versions may work as well, but we only tested hudson 1.2.x.x versions)
4. apache ant 1.6 onwards
5. apache tomcat 5.5 onwards (to run hudson inside servlet container)
6. Knowledge of grails and basic system admin; no expertise in hudson needed

Sample Continuous Integration Cycle:

Continous integration cycle of our example app performs the following steps:
a) Update the build system copy of application to latest source code from SCM
b) Run grails upgrade to create any missing files
c) Generate the application war file if needed
d) Run unit / integration tests
e) Run system functional tests
f) Generate application artifacts and reports for the above tests
g) Email/notify the admin in case there were problems with any of the above steps


System setup:

Follow the steps below in sequence to setup the environment on either UNIX or Windows machine:

Step1: Install

Download and install hudson.war into tomcat server webapps directory. If you are using app server different from tomcat, follow the app server specific instructions to install and bringup hudson.



Step 2: Update application files


(a) Modify build.xml:

Add the following to your default build.xml to enable ant based execution of 'grails upgrade' and grails 'run-webtest'











(b) Create Build script:

Even though hudson can directly execute ant commands, we will need to define our own build script to invoke ant. This allows us complete control our environment variables to be passed to grails. The control is especially useful in a hosted environment, where we do not have control over original environment (GRAILS_HOME, JAVA_HOME , PATH) etc passed to hudson.


The UNIX build script we will use is (to build grails project 'locate' , called buildlocate.sh):


# export env variables

JAVA_HOME=/usr/lib/jvm/java-6-sun-1.6.0.00;

export JAVA_HOME

GRAILS_HOME=/opt/grails

export GRAILS_HOME

# cd to project directory within hudson workspace:

cd locate

echo "classpath is $CLASSPATH; java home is $JAVA_HOME"

env

# remove JAVA_OPTS provided by hudson as it may cause errors

export -n JAVA_OPTS

export JAVA_OPTS=-Xmx768m

# now run the grails build / tests

exec ant upgrade war test webtest




Equivalent Windows script to use is (buildlocate.bat) :


REM set any global env vars in the beginning as necessary

set JAVA_HOME=C:\Program Files\jdk1.6.0_01

set GRAILS_HOME=C:\Programs\grails

REM cd to project directory within hudson workspace:

cd locate

REM reset JAVA_OPTS provided by hudson as it may cause errors

set JAVA_OPTS=-Xmx768m

# now run the grails build / tests

call ant upgrade war test webtest




Step 4: Hudson Configuration using Web Interface



Here are the steps you need to follow



1. Open the hudson dashboard on your browser

http://your_hudson_server_ip/hudson/
















2. Select 'New job' option on hudson console,


3. On the new job page, give a name to your hudson project . We call it 'projectlocate'

Make sure you select "Build a free-style software project" , click OK to go to detailed configuration page.



4. Expand Advanced Project Options by clicking on the Advanced button:



The description below applies to source code management using subversion:

Select Subversion source code management system;

Repository URL: put the http URL of your subversion repository

e.g. http://127.0.0.1/svn/trunk/server/locate



Leave the repository browser option to Auto


hudson will immediately attempt to contact the svn repository; and will prompt you to 'enter credentials' if the access requires authentication.



You can provide multiple project locations to pull in components of your build environment as needed here. Our example here uses a single project location, checked out under subdirectory 'locate'



5. Define the right Build Triggers: the most common is to select 'build peridoically' option to do nightly builds. You can enter the schedule in UNIX crontab like format.



6. Click on 'Build -> Add build step' button:

Choose 'Execute shell' for UNIX , 'Execute Windows batch command for Windows'. As described before, 'Invoke ant' option cannot be used directly here due to the need to customize environment variables.



Provide the full path of the unix shell script or windows batch file under the command textbox.

e.g. /home/rahul/hudson/grailsbuildlocate.sh

This is the same UNIX build script we defined above.






















7. Under Post-build Actions, check 'Archive the artifacts':

You can provide any of the artifacts or war files produced by the project.

e.g. our sample project produces locate.war that we can archive as result of successful build.


Also, add any artifacts you would like to have easy access to for information purposes.

We added locate/webtest/reports/WebTestResults.html; generated by running canoo webtest scripts.


8. Select 'Publish JUnit test result report' for any of your unit test reports that you want to be visible from hudson web console.

You can use wildcards to include all reports, hudson will automatically diff the successful tests across builds as they happen.

e.g. locate/test/reports/*.xml


9. Lastly, we add email notifications for the build admin email address.

Check 'E-mail notification' and define email address of recipient in the textbox.

















Hudson Email Config:

For hudson to be able to send emails, you do need to configure email server details for the overall hudson application:

Go to hudson dashboard, select 'Manage Hudson' to update hudson global configuration. This can also be accessed by URL /hudson/manage


Select 'System Configuration' : 'E-mail Notification'

The example here describes use of gmail as email server:



SMTP server : smtp.gmail.com

Check 'Use SMTP authentication'

User Name: your gmail user name

Password: your gmail password

Check 'Use SSL'



Hudson enables you to do an instant email config test using the hyperlink: 'Test configuration by sending email to system admin address'



Other useful tips:


If you found the above useful, here are few more tips to keep in mind when setting up hudson projects for grails:


1. The above example did not add any security to hudson, a real life hudson based CI server must have a user login to do any build admin tasks. You can add security to hudson Enable security check, and specify Security Realm and authorization as needed.


2. In the example given, the project war file is created before running unit tests. This is important, because executing 'grails war' command after 'grails test-app' will force the cleanup of all unit test reports; in that case hudson will not find any unit test reports to archive.



3. For the case as in the example, the webtest plugin is included in the application. The webtest execution forces the bringup of application on the server port. To avoid clash with application server already running on your machine, ensure that you set webtest_port under webtest/conf/webtest.properties to a different value . e.g. if tomcat server on your build / test server already runs on port 8080, specify webtest_port as 9090 etc. to avoid the clash.


4. ant was used to build the above example, but it is not required. The build can also be executed fully under Windows batch command or UNIX shell script.


Here are UNIX bash shell script lines to replace the ant command:


# bash CI script:
function error {
echo ERROR
exit 1
}

trap error ERR

grails upgrade -force

grails war

grails test-app

grails run-webtest


The above ensures that the shell script exits as soon as any of the grails commands returns with non zero exit code. This is important to enable hudson to detect build failure at the right step and notify the build admin.


5. Manual debugging of the CI environment can be done on build machine by directly executing the build script under the build copy of the project. You can find the CI build copy created by hudson under:

UNIX: ~build_home/.hudson/jobs/hudson_project_name/workspace
Windows: file://documents and Settings/build_user/.hudson/jobs/hudson_project_name/workspace


--------

Appreciate any feedback / suggestions you folks may have on the process above.

How to change the name of file to be downloaded..

Example from mailing list:

If I have a controller say:

def genFile {

ByteArrayOutputStream out = new ByteArrayOutputStream();

.... read data into outputstream here

response.setContentType('application/exe')
out.writeTo(response.getOutputStream())
out.close()
}

The file name presented to the user for save would be 'genFile'

However, adding the following in the beginning of controller would force the browser to recognize a different name:
response.addHeader("content-disposition", "attachment;filename=myfilename.ext")

Friday, April 11, 2008

Making jsp files reloadable


The secret of jsp reloading described by Graeme:

under (http://archive.grails.codehaus.org/user/3f2c19a70804110109h66324f79s8cabb490b7b7e5f7@mail.gmail.com)


Basically you can edit the generation template of web.xml with the settings to enable reloading of jsp files.




The template resides under GRAILS_HOME/conf/webdefault.xml under

Note that this will apply to all web.xml files generated for grails applications in your environment.

Also, will need to take care of modifying the webdefault.xml file when moving to a new release of grails !

Purpose of this blog

All,

I've been avidly following grails mailing list for quite a while. With heavy traffic on list, there are so many useful gems of wisdom that flow thru the list everyday; however my limited time to arrange them leaves me with lot of questions 'this was definitely answered in grails list, but how do I find the right question ?" etc...

This blog is attempt to manually get the useful items (at least once that I find useful ) from the list and put them in the list every day.