Introduction
SOAP 은 분산분배 환경에서 구조적 데이터를 주고 받기 위한 lightweight protocol이다. Goovy는 SOAP서버나 SOAP서버로 부터 리모트 Call을 만들 수 있게 해주는 Xfire
기반으로 SOAP을 구현했다.
Installation
$
{user.home}/.groovy/lib안에 이 jar 파일을 다운로드 받아야 만한다. 이 jar 파일은 groovy-1.0-JSR-06이 요구된다.
Getting Started
The Server
Groovy class나 script를 사용해서 웹서비스를 개발할 수 있다. 두개의 groovy파일이 웹서비스를 작성한 것이다.
- MathService.groovy
public class MathService { double add(double arg0, double arg1) { return (arg0 + arg1) } double square(double arg0) { return (arg0 * arg0) } }
- Groovy어디서나 사용할 수 있다.
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()
That's all !
Custom Data Types
이 예제는 Groovy SOAP으로 사용자 정의 데이터 타잎을 어떻게 사용하는지를 보여준다. 이코드는 here에서 다운로드 받을 수 있다.
The Server
PersonService.groovy script는 서비스의 구현과 사용자 정의 데이터 타잎(Person)을 포함하고 있다.
class Person {
int id
String firstname
String lastname
}
Person findPerson(int id) {
return new Person(id:id, firstname:'First', lastname:'Last')
Server.groovy는 이전 예제와 동일한다.
import groovy.net.soap.SoapServer; def server = new SoapServer("localhost", 6980); server.setNode("PersonService"); server.start();
Groovy 컴파일러로 컴파일 된 각각의 클래스들은 metaclass property가 바이트코드에 포함시켜야한다. 이 프로퍼티는 Xfire와 매핑되어지는걸 막아야만한다, 만약 그렇지 않으면 http://localhost:6980/PersonServiceInterface?wsdl로 부터 WSDL 문서에 획들할때 에러가 발생한다. 이 유는 Xfire가 groovy.lang.MetaClass를 맵핑할 수 없기 때문이다. 사용자 정의 타입 매핑은 메타 클래스 속성을 무시하고 디파인 해야함 한다. (참조 : 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>
하지만, 자바 부터 사용자 정의 데이터 타입을 컴파일 한다면 바이트 코드는 metaClass속성의 포함을 원하지 않을 것이다. 그러므로, 커스텀 맵핑을 정의할 필요가 없다.
More Information
Current limitations (and workaround)
- 인증(authentication)이 없다. (see JIRA issue 1457)
- Proxy를 지원하지 않는다 (see JIRA issue 1458)
- Numeric values는 사용자 정의 데이터 타잎과 array에서는 String으로 의미되어진다.
- 사용자 정의 데이터 타잎은 현재 groovy-1.0 release에서 Grooby SOAP모듈을 사용하는 클라이언트 사이드에서 사용할 수 없다.
- It looks like the XFire dynamic client does not support complex datatypes. This may be a concern if you need for example to transfer an Image as a byte array. The workaround I use is to transform this in a String an transfer that String - As this is a bit painful I am investigating moving to the regular XFire client. Here is a little program demo-ing this (look at this "disco age" image - Is Groovy that old ?
클라이언트 (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()
Base64로 인코딩된 이미가 포함된 서버:
import groovy.net.soap.SoapServer def server = new SoapServer("localhost", 6980) server.setNode("ImageService") server.start()
그리고 보호와 보이지 않는 부분은 []이다.
Demos with public web services
여기 테스팅을 위한 쓸모있는 웹서비스가 있다. 쉬운 예제 중 하나는 webservicex.net.에서 제공해주는 환율을 계산해주는 것이다.
여기 서비스를 사용을 데모해주는 작은 스윙 예제가 있다. 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 }
결과:







