Monday, January 22, 2007

Configuring Grails datasource with a .properties file

A Grails user needs to configure Grails data sources with an external .properties file (posted here), but having Spring beans inside "resources.xml" for it won't work for some reasons. I was trying to investigate what's going on, and found that there're steps done by Grails Hibernate plugin to retrieve references of datasouce before some beans defined in "resources.xml" are processed.

Anyway, I like the concept of using .properties file as well. So I modified *some*DataSource.groovy to see how can I use .properties to fill the data source properties, and here's the code:

import java.util.Properties
import org.springframework.core.io.FileSystemResource

class DevelopmentDataSource {

def static propFile = "web-app/WEB-INF/conf.properties";

boolean pooling = true
String dbCreate = "create-drop"

String url
String driverClassName
String username
String password

public DevelopmentDataSource() {
def props = new Properties()
try {
props.load(new FileSystemResource(propFile).inputStream)
} catch(Exception e){
e.printStackTrace();
}
this.driverClassName = props.getProperty("jdbc.driver","org.hsqldb.jdbcDriver")
this.url = props.getProperty("jdbc.url","jdbc:hsqldb:mem:inDB")
this.username = props.getProperty("jdbc.username","sa")
this.password = props.getProperty("jdbc.password","")
}
}


I know that it's not an elegant solution for the moment, but it works :).
With this modified datasource, you use the "propFile" to point to some file outside .WAR, and have some better level of abstraction.

Saturday, January 20, 2007

XFire plugin changed convention and upgraded to XFire 1.2.4

I've patched the XFire plugin to 1.2.4 and changed some convention to be more compatible with Grails.
Now you can just tweak your Grails services to be Web services by adding the static property 'expose'.
Here's an example:

class TestService {

static expose=['xfire']

def String doSomething(DomainClass dc) {
return "done"
}

def String getData() {
return "data"
}

def void setSomething(String something) {
// set some values here
}
}


The current build is going to skip all properties in a service, including transactional.
However, it's smart enough to expose some methods like 'getData' or void 'setSomething' correctly.
The policy used to expose methods in this build will detect existence of both "getter" and "setter" for a property.
Because in Groovy and Grails, we usually have property by simply defining a property with the 'def' keyword.

BTW, I was trying to compile it using JDK 1.4 but nothing works.
Some type casting exception has been occurred inside XFireSpringServlet and I cannot fix it yet.
So please stay tuned if you're going to use this plugin with Grails on 1.4 VM.

Thursday, January 11, 2007

I've finally done XFire plugin for Grails

Last post, I mentioned about Grails plugin architecture in 0.4. This great feature allows us to develop our own plugins. I firstly thought that it might be difficult to develop my own one. But after having a look into some plugin codes in Grails itself, and another one - OpenLaszlo plugin. I finally got some ideas about how the plugin works, and what to do.

However, I was suffered a bit by bugs from Spring Bean Builder because it doesn't provide complete APIs to cover methods I need, such as "bean.initMethod". Anyway, it's not too hard to figure it out, and I have some workaround to avoid these bugs. I'm planning to fix them soon after my XFire plugin is stable for Grails 0.4.

So, what's about the XFire plugin for Grails ?
It's a plugin to expose a Grils service as a Web service. Only requirement is that the service must have "XFireService" suffix. The plugin scans pulbic methods of the service, and generates complex type definition for parameter and return types using a modified XFire's Aegis engine.
For a Grails domain class, this plugin will generate type information for every properties, including "id", but it will ignore "version" and other Groovy specific properties.
If you want to exclude some methods, you can define "static excludes = []" in the service.

Here's some example:


class MyXFireService {

def static excludes = ["notMe"]

def String myMethod(MyDomain d) {
d.save()
return "test"
}

def String notMe() {
return "nothing"
}
}



I've added a page for this plugin at Grails space here:
http://grails.org/XFire+plugin

Saturday, January 06, 2007

XFire for Grails Applications - the pre-plugin Era

I've updated my Grails from 0.3.1 to 0.4 snapshot and its new coming plug-in architecture looks very promising. I'm hoping that someone will implement an XFire plugin for Grails soon (mentioned some where in Grails' wiki). Anyway, I'm going to talk about how to integrate XFire into an Grails application manually.

Here, I briefly show you steps to integrate annotation-based XFire Web services into your Grails Applications.

1. download XFire distro (I'm using 1.2.3).
2. put everything (.jar files) of XFire into ${YOUR_GRAILS_APP}\lib
3. create your Web service class in src/java
4. modify resources.xml
5. modify web.template.xml
6. grails run-app

It's still configuration-based approach, not conventional yet.
Anyway, this might be useful to someone, who currently need to use XFire, when the XFire plugin still be an imaginary thing.

Note that, this covers only HTTP-based transportation of XFire, since Grails is mainly for Web.

Let's go into details:
Before starting, you have to put all XFire .jar files into your /lib folder first.

So, you can start by put your annotation-based classes in "src/java" folder.


@WebService
public class MyService {

@WebMethod
public String doSomething() {
return "hello";
}

@WebMethod(exclude=true)
public void hideMePlease() {
return;
}

}


what you needs are modification of "resources.xml" for spring, and "web.template.xml".

OK, then add some XML chunks into your spring/resources.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<!-- You need this line to import "xfire" and
"xfire.transportManager" references in -->
<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />

<!-- Your service goes here -->
<bean name="myService" class="org.codehaus.xfire.spring.ServiceBean">
<property name="xfire" ref="xfire"/>
<property name="serviceBean" ref="myService"/>
<property name="serviceClass" value="MyService"/>
<property name="serviceFactory" ref="jsr181"/>
</bean>

<!-- Here's initialising an "jsr181" instance to be
a factory object for your services -->
<bean id="jsr181"
class="org.codehaus.xfire.spring.config.ServiceFactoryBean"
init-method="initialize">
<constructor-arg index="0" value="jsr181" />
<property name="transportManager" ref="xfire.transportManager" />
</bean>

</beans>


Finally, put some servlet configuration into your "web.template.xml", like this

<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFire Servlet</display-name>
<servlet-class>
org.codehaus.xfire.spring.XFireSpringServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>


OK, let's type "grails run-app" and browse to "http://localhost:8080/${your_grails_app}/services/myService/" to see its WSDL link.
And that's all, your XFire service is now ready.