create a SOAP server and make calls to remote SOAP servers using Groovy |
|
Before using GroovySOAP, make sure to check GroovyWS |
{link:SOAP|http://www.w3.org/TR/soap/}{link} |
{link:Xfire |http://xfire.codehaus.org}{link} |
You just need to download this jar file in your ${user.home}/.groovy/lib directory. This jar file embeds all the dependencies.
You can develop your web service using a groovy script and/or a groovy class. The following two groovy files are valid for building a web-service.
public class MathService {
double add(double arg0, double arg1) {
return (arg0 + arg1)
}
double square(double arg0) {
return (arg0 * arg0)
}
}
|
double add(double arg0, double arg1) {
return (arg0 + arg1)
}
double square(double arg0) {
return (arg0 * arg0)
}
|
import groovy.net.soap.SoapServer
def server = new SoapServer("localhost", 6980)
server.setNode("MathService")
server.start()
|
import groovy.net.soap.SoapClient
def proxy = new SoapClient("http://localhost:6980/MathServiceInterface?wsdl")
def result = proxy.add(1.0, 2.0)
assert (result == 3.0)
result = proxy.square(3.0)
assert (result == 9.0)
|
This example shows how to use custom data types with Groovy SOAP. The code can be downloaded from here.
The PersonService.groovy script contains the service implementation and the custom data type (Person).
class Person {
int id
String firstname
String lastname
}
Person findPerson(int id) {
return new Person(id:id, firstname:'First', lastname:'Last')
|
Server.groovy is equivalent to the previous example.
import groovy.net.soap.SoapServer;
def server = new SoapServer("localhost", 6980);
server.setNode("PersonService");
server.start();
|
For each class compiled by the groovy compiler a metaClass property is added to the bytecode. This property must be excluded from being mapped by XFire, otherwise an error will be reported when trying to obtain the WSDL document from http://localhost:6980/PersonServiceInterface?wsdl. The reason is that XFire cannot map groovy.lang.MetaClass. To ignore the metaClass property a custom type mapping must be defined (for details refer to Aegis Binding).
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns:sample="http://DefaultNamespace">
<mapping name="sample:Person">
<property name="metaClass" ignore="true"/>
</mapping>
</mappings>
|
However, if you compile custom data types from Java the bytecode won't contain a metaClass property and, hence, there is no need to define a custom mapping.
import groovy.net.soap.SoapClient
def proxy = new SoapClient('http://localhost:6980/PersonServiceInterface?wsdl')
def person = proxy.findPerson(12)
println 'Person (' + person.id + ') = ' +
person.firstname + ' ' + person.lastname
|
The client (ImageClient.groovy)
import groovy.swing.SwingBuilder
import groovy.net.soap.SoapClient
import javax.swing.ImageIcon
import org.apache.commons.codec.binary.Base64
proxy = new SoapClient("http://localhost:6980/ImageServiceInterface?WSDL")
// get the string, transform it to a byte array and decode this array
b64 = new Base64()
bbytes = b64.decode(proxy.getImage().getBytes())
swing = new groovy.swing.SwingBuilder()
// this is regular SwingBuilder stuff
i1 = swing.label(icon:new ImageIcon(bbytes))
frame = swing.frame(title:'Groovy logo', defaultCloseOperation:javax.swing.WindowConstants.DISPOSE_ON_CLOSE) {
panel(){
widget(i1)
}
}
frame.pack()
frame.show()
|
The (ugly) server part embedding the image which is Base64 encoded (ImageServer.groovy):
import groovy.net.soap.SoapServer
def server = new SoapServer("localhost", 6980)
server.setNode("ImageService")
server.start()
|
and the missing and secred part is here.
There exist a lot of web-services available for testing. One which is pretty easy to evaluate is the currency rate calculator from webservicex.net.
Here is a small swing sample that demonstrate the use of the service. Enjoy !
import groovy.swing.SwingBuilder
import groovy.net.soap.SoapClient
proxy = new SoapClient("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL")
def currency = ['USD', 'EUR', 'CAD', 'GBP', 'AUD']
def rate = 0.0
swing = new SwingBuilder()
refresh = swing.action(
name:'Refresh',
closure:this.&refreshText,
mnemonic:'R'
)
frame = swing.frame(title:'Currency Demo') {
panel {
label 'Currency rate from '
comboBox(id:'from', items:currency)
label ' to '
comboBox(id:'to', items:currency)
label ' is '
textField(id:'currency', columns:10, rate.toString())
button(text:'Go !', action:refresh)
}
}
frame.pack()
frame.show()
def refreshText(event) {
rate = proxy.ConversionRate(swing.from.getSelectedItem(), swing.to.getSelectedItem())
swing.currency.text = rate
}
|
And here is the result: 