xml and web services with groovy

86
XML and Web Services with Groovy Dr Paul King, ASERT: @paulk_asert, [email protected] SpringOne2GX - 1

Upload: paul-king

Post on 25-Jan-2015

3.758 views

Category:

Technology


2 download

DESCRIPTION

Dr Paul King's presentation slides on \'XML and Web Services with Groovy\'

TRANSCRIPT

Page 1: XML and Web Services with Groovy

XML and WebServices with Groovy

Dr Paul King, ASERT: @paulk_asert, [email protected]

SpringOne2GX - 1

Page 2: XML and Web Services with Groovy

© A

SE

RT

2006-2

009

What is Groovy?

• “Groovy is like a super version

of Java. It can leverage Java's

enterprise capabilities but also

has cool productivity features like closures,

DSL support, builders and dynamic typing.”

Groovy = Java – boiler plate code+ optional dynamic typing+ closures+ domain specific languages+ builders+ metaprogramming

SpringOne2GX - 2

Page 3: XML and Web Services with Groovy

Growing Acceptance …

A slow and steady start but now gaining in

momentum, maturity and mindshare

Now free

Page 4: XML and Web Services with Groovy

… Growing Acceptance …

© A

SE

RT

2006-2

009

SpringOne2gx_Oct2009 - 4

Page 5: XML and Web Services with Groovy

… Growing Acceptance …

© A

SE

RT

2006-2

009

SpringOne2gx_Oct2009 - 5

Groovy and Grails downloads:

70-90K per month and growing

Page 6: XML and Web Services with Groovy

… Growing Acceptance …

© A

SE

RT

2006-2

009

SpringOne2gx_Oct2009 - 6

Source: http://www.grailspodcast.com/

Source: http://www.micropoll.com/akira/mpresult/501697-116746

Page 7: XML and Web Services with Groovy

… Growing Acceptance …

© A

SE

RT

2006-2

009

SpringOne2gx_Oct2009 - 7http://www.java.net

http://www.jroller.com/scolebourne/entry/devoxx_2008_whiteboard_votes

Page 8: XML and Web Services with Groovy

… Growing Acceptance …

© A

SE

RT

2006-2

009

SpringOne2gx_Oct2009 - 8http://www.leonardoborges.com/writings

What alternative JVM language are you using or intending to use

Page 9: XML and Web Services with Groovy

… Growing Acceptance …

© A

SE

RT

2006-2

009

SpringOne2gx_Oct2009 - 9

http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo.com)

Page 10: XML and Web Services with Groovy

… Growing Acceptance

SpringOne2gx_Oct2009 - 10

© A

SE

RT

2006-2

009

Page 11: XML and Web Services with Groovy

Better XML Manipulation...

AUG 2009 - 11

© A

SE

RT

2006-2

009

<records>

<car name='HSV Maloo' make='Holden' year='2006'>

<country>Australia</country>

<record type='speed'>Production Pickup Truck with speed of 271kph</record>

</car>

<car name='P50' make='Peel' year='1962'>

<country>Isle of Man</country>

<record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg weight</record>

</car>

<car name='Royale' make='Bugatti' year='1931'>

<country>France</country>

<record type='price'>Most Valuable Car at $15 million</record>

</car>

</records>

records.xml

Page 12: XML and Web Services with Groovy

...Better XML Manipulation...

AUG 2009 - 12

© A

SE

RT

2006-2

009

import org.w3c.dom.Document;import org.w3c.dom.NodeList;import org.w3c.dom.Node;import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.ParserConfigurationException;import java.io.File;import java.io.IOException;

public class FindYearsJava {public static void main(String[] args) {

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();try {

DocumentBuilder builder = builderFactory.newDocumentBuilder();Document document = builder.parse(new File("records.xml"));NodeList list = document.getElementsByTagName("car");for (int i = 0; i < list.getLength(); i++) {

Node n = list.item(i);Node year = n.getAttributes().getNamedItem("year");System.out.println("year = " + year.getTextContent());

}} catch (ParserConfigurationException e) {

e.printStackTrace();} catch (SAXException e) {

e.printStackTrace();} catch (IOException e) {

e.printStackTrace();}

}}

Page 13: XML and Web Services with Groovy

...Better XML Manipulation...

AUG 2009 - 13

© A

SE

RT

2006-2

009

import org.w3c.dom.Document;import org.w3c.dom.NodeList;import org.w3c.dom.Node;import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.ParserConfigurationException;import java.io.File;import java.io.IOException;

public class FindYearsJava {public static void main(String[] args) {

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();try {

DocumentBuilder builder = builderFactory.newDocumentBuilder();Document document = builder.parse(new File("records.xml"));NodeList list = document.getElementsByTagName("car");for (int i = 0; i < list.getLength(); i++) {

Node n = list.item(i);Node year = n.getAttributes().getNamedItem("year");System.out.println("year = " + year.getTextContent());

}} catch (ParserConfigurationException e) {

e.printStackTrace();} catch (SAXException e) {

e.printStackTrace();} catch (IOException e) {

e.printStackTrace();}

}}

boilerplate

Page 14: XML and Web Services with Groovy

...Better XML Manipulation

AUG 2009 - 14

© A

SE

RT

2006-2

009

def records = new XmlParser().parse("records.xml")records.car.each {

println "year = ${it.@year}"}

year = 2006year = 1962year = 1931

Page 15: XML and Web Services with Groovy

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

XML

Page 16: XML and Web Services with Groovy

Groovy and XML ...

• Reading XML

– Special Groovy support:

XmlParser, XmlSlurper, DOMCategory

– Or Groovy sugar for your current favorites:

DOM, SAX, StAX, DOM4J, JDom, XOM, XPath,

XSLT, XQuery, etc.

• Creating XML

– Special Groovy support:

MarkupBuilder and StreamingMarkupBuilder

– Or again, enhanced syntax for your current

favorites

© A

SE

RT

2006-2

009

SpringOne2GX - 16

Page 17: XML and Web Services with Groovy

... Groovy and XML ...

• Updating XML

– Using above: read followed by create

– Can be done with XmlParser, XmlSlurper,

DOMCategory

– Or with your Java favorites

• Verifying XML

– Also DTD, W3C XML Schema, Relax NG in a

similar fashion to Java mechanisms for these

features

© A

SE

RT

2006-2

009

SpringOne2GX - 17

Page 18: XML and Web Services with Groovy

... Groovy and XML

• So many technologies – how to choose?

– Normally just use XmlSlurper and

StreamingMarkupBuilder

– Or if you want a DOM, use XmlParser and

MarkupBuilder or DOMBuilder

– Or if you must have a W3C DOM, use

DOMCategory

– Or if you expect to have a large amount of

legacy or Java parsing code, you can stick

with your favorite Java XML API/stack

© A

SE

RT

2006-2

009

SpringOne2GX - 18

Page 19: XML and Web Services with Groovy

An Xml Example ...

import groovy.xml.dom.DOMCategory

class Flights {static final String XML = '''

<trip><flight hours="13">

<from>Brisbane</from><to>Los Angeles</to>

</flight><flight hours="4">

<from>Los Angeles</from><to>New Orleans</to>

</flight></trip>

'''...

© A

SE

RT

2006-2

009

SpringOne2GX - 19

Page 20: XML and Web Services with Groovy

... An Xml Example

© A

SE

RT

2006-2

009

...static final Reader getReader() {

new StringReader(XML)}static final Set getCities(flights) {

Set cities = []use(DOMCategory) {

flights.each { f ->cities += f.to[0].text()cities += f.from[0].text()

}}cities

}}

SpringOne2GX - 20

You can mostly ignore

the details here for now.

We’ll cover DOMCategory

in more detail shortly.

Page 21: XML and Web Services with Groovy

XmlParser

def trip = new XmlParser().parseText(Flights.XML)assert trip.flight[0].to.text() == 'Los Angeles'assert trip.flight[1].@hours == '4'

Set cities = trip.flight.from*.text() +trip.flight.to*.text()

assert cities == ['Brisbane', 'Los Angeles','New Orleans'] as Set

assert trip.flight.@hours == ['13', '4']assert trip.flight.@hours*.toInteger().sum() == 17

• Builds an in-memory DOM tree

© A

SE

RT

2006-2

009

SpringOne2GX - 21

Page 22: XML and Web Services with Groovy

XmlParser – Under the covers• For a JavaBean, this Groovy expression:

• Is “roughly” converted to:

where getFlight() and getTo() return a List

• But for XML Parser, it overrides this mechanism

and “roughly” converts to:

where getByName is a Groovy method similar to

getElementsByTagName in org.w3c.dom.Element

trip.flight[0].to[0].text()

trip.getflight().get(0).getTo().get(0).text()

trip.getByName('flight').get(0).getByName('to').get(0).text()

© A

SE

RT

2006-2

009

SpringOne2GX - 22

Page 23: XML and Web Services with Groovy

XmlSlurper...

• The same again using XmlSlurper– Mostly identical syntax and capabilities

– But features lazy evaluation of expressions

– Consider this for streaming scenarios

def trip = new XmlSlurper().parseText(Flights.XML)assert trip.flight[0].to.text() == 'Los Angeles'assert trip.flight[1].@hours == '4'

Set cities = trip.flight.from*.text() +trip.flight.to*.text()

assert cities == ['Brisbane', 'Los Angeles','New Orleans'] as Set

assert [email protected]() == ['13', '4']assert trip.flight.@hours*.toInteger().sum() == 17

© A

SE

RT

2006-2

009

SpringOne2GX - 23

Page 24: XML and Web Services with Groovy

...XmlSlurper...

• What does Lazy mean?

def trip = new XmlSlurper().parseText(Flights.XML)def moreThanFiveHours = { f -> [email protected]() > 5 }def arrivingLax = { f -> f.to == 'Los Angeles' }def departingOz = { f -> f.from == 'Brisbane' }

def longFlights = trip.flight.findAll(moreThanFiveHours)def longLaxFlights = longFlights.findAll(arrivingLax)def longOzLaxFlights = longLaxFlights.findAll(departingOz)assert longOzLaxFlights.@hours == '13'

© A

SE

RT

2006-2

009

SpringOne2GX - 24

Page 25: XML and Web Services with Groovy

• This may look puzzling at first– But the good news is you don’t normally have to care

def trip = new XmlSlurper().parseText(Flights.XML)def moreThanFiveHours = { f -> [email protected]() > 5 }def arrivingLax = { f -> f.to == 'Los Angeles' }def departingOz = { f -> f.from == 'Brisbane' }

def longFlights = trip.flight.findAll(moreThanFiveHours)def longLaxFlights = longFlights.findAll(arrivingLax)def longOzLaxFlights = longLaxFlights.findAll(departingOz)assert longOzLaxFlights.@hours == '13'

Light-weight scanning here

Lazy expression storage

but deferred evaluationUsage triggers evaluation

...XmlSlurper

© A

SE

RT

2006-2

009

SpringOne2GX - 25

Page 26: XML and Web Services with Groovy

class Books {

static final String XML = '''

<rdf:rdf xmlns:bibterm="http://www.book-stuff.com/terms/"

xmlns:dc="http://purl.org/dc/elements/1.0/"

xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

<rdf:description rdf:about="http://www.book-stuff.com/bib">

<bibterm:book rdf:parseType="Resource">

<bibterm:year>2007</bibterm:year>

<dc:title>Groovy in Action</dc:title>

<bibterm:author rdf:parseType="Resource">

<bibterm:last>König</bibterm:last>

<bibterm:first>Dierk</bibterm:first>

</bibterm:author>

<rdf:comment>

Coauthors: Andrew Glover, Paul King,

Guillaume Laforge and Jon Skeet

</rdf:comment>

</bibterm:book>

</rdf:description>

</rdf:rdf>

''' ...

A Namespace Example

© A

SE

RT

2006-2

009

SpringOne2GX - 26

Page 27: XML and Web Services with Groovy

• Recommended syntax:

• Options

// use string style matching (exact match on prefix or wildcard or URI)assert b.'bibterm:year'.text() == '2007'assert b.'*:year'.text() == '2007'assert b.'http://www.book-stuff.com/terms/:year'.text() == '2007'

// Namespace is a QName factory but you can use QName directlydef bibtermYear = new QName('http://www.book-stuff.com/terms/', 'year')assert b[bibtermYear].text() == '2007'

// use QName with wildcardsdef anyYear = new QName('*', 'year')assert b[anyYear].text() == '2007'

import groovy.xml.*def book = new XmlParser().parseText(Books.XML)def rdf = new Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')def dc = new Namespace('http://purl.org/dc/elements/1.0/')def bibterm = new Namespace('http://www.book-stuff.com/terms/')def b = book[rdf.description][bibterm.book]assert b[dc.title].text() == 'Groovy in Action'assert b[bibterm.year].text() == '2007'

XmlParser and Namespaces

SpringOne2GX - 27

© A

SE

RT

2006-2

009

Page 28: XML and Web Services with Groovy

def book = new XmlSlurper().parseText(Books.XML)book.declareNamespace(

rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',dc: 'http://purl.org/dc/elements/1.0/',bibterm: 'http://www.book-stuff.com/terms/')

def b = book.'rdf:description'.'bibterm:book'assert b.'dc:title' == 'Groovy in Action'assert b.'bibterm:year' == '2007'

XmlSlurper and Namespaces

© A

SE

RT

2006-2

009

SpringOne2GX - 28

Page 29: XML and Web Services with Groovy

Other GPath Features• Similar syntax for XmlSlurper and DOMCategory

SpringOne2GX - 29

© A

SE

RT

2006-2

009

def trip = new XmlParser().parseText(Flights.XML)assert trip.'**'*.name() ==

['trip', 'flight', 'from', 'to', 'flight', 'from', 'to']assert trip.depthFirst()*.name() ==

['trip', 'flight', 'from', 'to', 'flight', 'from', 'to']assert trip.breadthFirst()*.name() ==

['trip', 'flight', 'flight', 'from', 'to', 'from', 'to']assert trip.'**'.from*.text() == ['Brisbane', 'Los Angeles']

Page 30: XML and Web Services with Groovy

What about non-XML?@Grab('nekohtml:nekohtml:1.9.6.2')

import org.cyberneko.html.parsers.SAXParser

def neko = new SAXParser()neko.setFeature('http://xml.org/sax/features/namespaces', false)def page = new XmlParser(neko).parse('http://groovy.codehaus.org/')def data = page.depthFirst().A.'@href'.grep{

it != null && it.endsWith('.html')}data.each { println it }

http://groovy.javanicus.com/search.html

http://www.dcs.napier.ac.uk/~cs05/groovy/groovy.html

http://www.ej-technologies.com/products/jprofiler/overview.html

© A

SE

RT

2006-2

009

SpringOne2GX - 30

def neko = new SAXParser() // alternate style

def page = new XmlSlurper(neko).parse('http://groovy.codehaus.org/')def data = page.depthFirst().grep{

it.name() == 'A' && [email protected]().endsWith('.html')}.'@href'data.each { println it }

Page 31: XML and Web Services with Groovy

Raw DOM

import groovy.xml.DOMBuilder

def trip = DOMBuilder.parse(Flights.reader).documentElementdef flights = trip.getElementsByTagName('flight')

def dest = flights.item(0).getElementsByTagName('to').item(0)assert dest.firstChild.nodeValue == 'Los Angeles'

assert flights.item(1).getAttribute('hours') == '4'

assert Flights.getCities(flights) ==['Brisbane', 'Los Angeles', 'New Orleans'] as Set

© A

SE

RT

2006-2

009

SpringOne2GX - 31

Page 32: XML and Web Services with Groovy

DOM plus metaprogramming

import groovy.xml.DOMBuilderimport org.w3c.dom.Element

def trip = DOMBuilder.parse(Flights.reader).documentElement

Element.metaClass.element = { t, i ->delegate.getElementsByTagName(t).item(i) }

Element.metaClass.text = {-> delegate.firstChild.nodeValue }

assert trip.element('flight', 0).element('to', 0).text() =='Los Angeles'

assert trip.element('flight', 1).getAttribute('hours') == '4'

© A

SE

RT

2006-2

009

SpringOne2GX - 32

Page 33: XML and Web Services with Groovy

DOMCategory

import groovy.xml.DOMBuilderimport groovy.xml.dom.DOMCategory

def doc = DOMBuilder.parse(Flights.reader)def trip = doc.documentElement

use(DOMCategory) {assert trip.flight[0].to[0].text() ==

'Los Angeles'assert trip.flight[1].'@hours' == '4'assert Flights.getCities(trip.flight) ==

['Brisbane', 'Los Angeles','New Orleans'] as Set

}

© A

SE

RT

2006-2

009

SpringOne2GX - 33

Page 34: XML and Web Services with Groovy

DOM4J

@Grab('dom4j:dom4j:1.6.1')import org.dom4j.io.SAXReader

def trip = new SAXReader().read(Flights.reader).rootElement

assert trip.elements()[0].elementText('to') == 'Los Angeles'assert trip.elements()[1].attributeValue('hours') == '4'

© A

SE

RT

2006-2

009

SpringOne2GX - 34

Page 35: XML and Web Services with Groovy

JDOM

@Grab('org.jdom:jdom:1.1')import org.jdom.input.SAXBuilder

def b = new SAXBuilder()def trip = b.build(Flights.reader).rootElement

assert trip.children[0].getChildText('to') == 'Los Angeles'assert trip.children[1].getAttribute('hours').value == '4'

© A

SE

RT

2006-2

009

SpringOne2GX - 35

Page 36: XML and Web Services with Groovy

XOM

@Grab('xom:xom:1.1')

import nu.xom.Builder

def doc = new Builder().build(Flights.reader)

def flights = doc.rootElement.childElements

def to = flights.get(0).getFirstChildElement('to')

assert to.value == 'Los Angeles'

def hours = flights.get(1).getAttribute('hours')

assert hours.value == '4'

© A

SE

RT

2006-2

009

SpringOne2GX - 36

Page 37: XML and Web Services with Groovy

StAXimport static javax.xml.stream.XMLInputFactory.newInstance as staxFactoryimport javax.xml.stream.XMLStreamReader as StaxReader

def flights = []def flightdef seenTagStaxReader.metaClass.attr = { s -> delegate.getAttributeValue(null, s) }

def reader = staxFactory().createXMLStreamReader(Flights.reader)while (reader.hasNext()) {

def name = reader.localNameif (reader.startElement) {

if (name == 'flight') flight = [hours:reader.attr('hours')]else if (name in ['from', 'to']) seenTag = name

} else if (reader.characters) {if (seenTag) flight[seenTag] = reader.text

} else if (reader.endElement) {if (name == 'flight') flights += flightseenTag = null

}reader.next()

}

assert flights[0].to == 'Los Angeles'assert flights[1].hours == '4'

© A

SE

RT

2006-2

009

SpringOne2GX - 37

Page 38: XML and Web Services with Groovy

import javax.xml.parsers.SAXParserFactoryimport org.xml.sax.*import org.xml.sax.helpers.DefaultHandler

class TripHandler extends DefaultHandler {def flights = []private flight, seenTag

void startElement(String ns, String localName, String qName, Attributes atts) {if (qName == 'flight') flight = [hours:atts.getValue('hours')]else if (qName in ['from', 'to']) seenTag = qName

}

public void endElement(String uri, String localName, String qName) {if (qName == 'flight') flights += flightseenTag = null

}

public void characters(char[] ch, int start, int length) {if (seenTag) flight[seenTag] = new String(ch, start, length)

}}

def handler = new TripHandler()def reader = SAXParserFactory.newInstance().newSAXParser().xMLReaderreader.setContentHandler(handler)reader.parse(new InputSource(Flights.reader))

assert handler.flights[0].to == 'Los Angeles'assert handler.flights[1].hours == '4'

SAX

© A

SE

RT

2006-2

009

SpringOne2GX - 38

Page 39: XML and Web Services with Groovy

XPath

import javax.xml.xpath.*import groovy.xml.DOMBuilder

def xpath = XPathFactory.newInstance().newXPath()def trip = DOMBuilder.parse(Flights.reader).documentElementassert xpath.evaluate('flight/to/text()', trip) ==

'Los Angeles'assert xpath.evaluate('flight[2]/@hours', trip) == '4'

def flights = xpath.evaluate( 'flight', trip,XPathConstants.NODESET )

def hoursAsInt = { n ->xpath.evaluate('@hours', n).toInteger() }

assert flights.collect(hoursAsInt).sum() == 17

assert Flights.getCities(flights) == ['Brisbane','Los Angeles', 'New Orleans'] as Set

© A

SE

RT

2006-2

009

SpringOne2GX - 39

Page 40: XML and Web Services with Groovy

XPath with DOMCategory

import groovy.xml.DOMBuilderimport groovy.xml.dom.DOMCategoryimport static javax.xml.xpath.XPathConstants.*

def trip = DOMBuilder.parse(Flight.reader).documentElementuse (DOMCategory) {

assert trip.xpath('flight/to/text()') == 'Los Angeles'assert trip.xpath('flight[2]/@hours', NUMBER) == 4flights = trip.xpath('flight', NODESET)def hoursAsNum = { n -> n.xpath('@hours', NUMBER) }assert flights.collect(hoursAsNum).sum() == 17

}

© A

SE

RT

2006-2

009

SpringOne2GX - 40

Page 41: XML and Web Services with Groovy

Xalan XPath

@Grab('xalan:xalan:2.7.1')import static org.apache.xpath.XPathAPI.*import groovy.xml.DOMBuilder

def trip = DOMBuilder.parse(Flights.reader).documentElement

assert eval(trip, 'flight/to/text()').str() =='Los Angeles'

assert eval(trip, 'flight[2]/@hours').str() == '4'

def flights = selectNodeList(trip, '//flight')def hoursAsInt = { n ->

eval(n, '@hours').str().toInteger() }assert flights.collect(hoursAsInt).sum() == 17

assert Flights.getCities(flights) == ['Brisbane','Los Angeles', 'New Orleans'] as Set

© A

SE

RT

2006-2

009

SpringOne2GX - 41

Page 42: XML and Web Services with Groovy

Jaxen XPath

@Grab('jaxen#jaxen;1.1.1')import org.jaxen.dom.DOMXPathimport groovy.xml.DOMBuilder

def trip = DOMBuilder.parse(Flights.reader).documentElementassert new DOMXPath('flight/to/text()').

stringValueOf(trip) == 'Los Angeles'assert new DOMXPath('flight[2]/@hours').

stringValueOf(trip) == '4'

def flights = new DOMXPath('flight').selectNodes(trip)def hoursAsInt = { n ->

new DOMXPath('@hours').numberValueOf(n) }assert flights.collect(hoursAsInt).sum() == 17

assert Flights.getCities(flights) == ['Brisbane','Los Angeles', 'New Orleans'] as Set

© A

SE

RT

2006-2

009

SpringOne2GX - 42

Page 43: XML and Web Services with Groovy

JSR 225 - XQJ

import net.sf.saxon.xqj.SaxonXQDataSourceimport javax.xml.xquery.XQSequenceXQSequence.metaClass.collect = { Closure c ->

def items = []while (delegate.next()) items += c(delegate)items

}def asString = { seq -> seq.getItemAsString(null) }def hourAttr = { it.item.node.getAttribute('hours') as int }def flights = "document { ${Flights.XML} }"def exp =

new SaxonXQDataSource().connection.createExpression()def seq = exp.executeQuery("$flights/trip/flight/to/text()")assert seq.collect(asString) == ['Los Angeles',

'New Orleans']seq = exp.executeQuery("$flights/trip/flight")assert seq.collect(hourAttr).sum() == 17

© A

SE

RT

2006-2

009

SpringOne2GX - 43

Page 44: XML and Web Services with Groovy

import static javax.xml.transform.TransformerFactory.newInstance as xsltFactoryimport javax.xml.transform.stream.*def xslt = '''<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:template match="/trip"><html><body><h1>Flights</h1><ul><xsl:apply-templates select="flight"/>

</ul></body>

</html></xsl:template><xsl:template match="flight"><li><xsl:value-of select="from"/> => <xsl:value-of select="to"/>

</li></xsl:template>

</xsl:stylesheet>'''.trim()def transformer = xsltFactory().newTransformer(

new StreamSource(new StringReader(xslt)))transformer.transform(new StreamSource(Flights.reader),

new StreamResult(System.out))

XSLT...

© A

SE

RT

2006-2

009

SpringOne2GX - 44

Page 45: XML and Web Services with Groovy

import static javax.xml.transform.TransformerFactory.newInstance as xsltFactoryimport javax.xml.transform.stream.*def xslt = '''<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:template match="/trip"><html><body><h1>Flights</h1><ul><xsl:apply-templates select="flight"/>

</ul></body>

</html></xsl:template><xsl:template match="flight"><li><xsl:value-of select="from"/> => <xsl:value-of select="to"/>

</li></xsl:template>

</xsl:stylesheet>'''.trim()def transformer = xsltFactory().newTransformer(

new StreamSource(new StringReader(xslt)))transformer.transform(new StreamSource(Flights.reader),

new StreamResult(System.out))

...XSLT

<html>

<body>

<h1>Flights</h1>

<ul>

<li>Brisbane =&gt; Los Angeles</li>

<li>Los Angeles =&gt; New Orleans</li>

</ul>

</body>

</html>

© A

SE

RT

2006-2

009

SpringOne2GX - 45

Page 46: XML and Web Services with Groovy

MarkupBuilder

import groovy.xml.MarkupBuilder

def writer = new StringWriter()def xml = new MarkupBuilder(writer)xml.flights {

flight(hours:13) {from('Brisbane')to('Los Angeles')

}flight(hours:4) {

from('Los Angeles')to('New Orleans')

}}println writer

© A

SE

RT

2006-2

009

SpringOne2GX - 46

Page 47: XML and Web Services with Groovy

StreamingMarkupBuilder

import groovy.xml.StreamingMarkupBuilder

def writer = new StreamingMarkupBuilder().bind {flights {

flight(hours: 13) {from('Brisbane')to('Los Angeles')

}flight(hours: 4) {

from('Los Angeles')to('New Orleans')

}}

}println writer

© A

SE

RT

2006-2

009

SpringOne2GX - 47

Page 48: XML and Web Services with Groovy

DOMBuilder

import groovy.xml.*

def builder = DOMBuilder.newInstance()def root = builder.flights {

flight(hours: 13) {from('Brisbane')to('Los Angeles')

}flight(hours: 4) {

from('Los Angeles')to('New Orleans')

}}new XmlNodePrinter().print(root)

© A

SE

RT

2006-2

009

SpringOne2GX - 48

Page 49: XML and Web Services with Groovy

MarkupBuilder with Namespaces

import groovy.xml.MarkupBuilder

def writer = new StringWriter()def xml = new MarkupBuilder(writer)xml.'rdf:description'(

'xmlns:bibterm': "http://www.book-stuff.com/terms/",'xmlns:dc': "http://purl.org/dc/elements/1.0/",'xmlns:rdf': "http://www.w3.org/1999/02/22-rdf-syntax-

ns#") {'bibterm:book' {

'dc:title'('Groovy in Action')'bibterm:year'('2007')

}}println writer

© A

SE

RT

2006-2

009

SpringOne2GX - 49

<rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/'

xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'

xmlns:bibterm='http://www.book-stuff.com/terms/'>

<bibterm:book>

<dc:title>Groovy in Action</dc:title>

<bibterm:year>2007</bibterm:year>

</bibterm:book>

</rdf:description>

Page 50: XML and Web Services with Groovy

StreamingMarkupBuilder with Namespaces

import groovy.xml.*

XmlUtil.serialize(new StreamingMarkupBuilder().bind {mkp.declareNamespace(

bibterm: "http://www.book-stuff.com/terms/",dc: "http://purl.org/dc/elements/1.0/",rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#")

'rdf:description' {'bibterm:book' {

'dc:title'('Groovy in Action')'bibterm:year'('2007')

}}

}, System.out)

© A

SE

RT

2006-2

009

SpringOne2GX - 50

<rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/'

xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'

xmlns:bibterm='http://www.book-stuff.com/terms/'>

<bibterm:book>

<dc:title>Groovy in Action</dc:title>

<bibterm:year>2007</bibterm:year>

</bibterm:book>

</rdf:description>

Page 51: XML and Web Services with Groovy

DOMBuilder with Namespaces

import groovy.xml.DOMBuilder

def b = DOMBuilder.newInstance()def root = b.'rdf:description'(

'xmlns:bibterm': "http://www.book-stuff.com/terms/",'xmlns:dc': "http://purl.org/dc/elements/1.0/",'xmlns:rdf': "http://www.w3.org/1999/02/22-rdf-syntax-ns#") {

'bibterm:book' {'dc:title'('Groovy in Action')'bibterm:year'('2007')

}}new XmlNodePrinter().print(root)

© A

SE

RT

2006-2

009

SpringOne2GX - 51

<rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/'

xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'

xmlns:bibterm='http://www.book-stuff.com/terms/'>

<bibterm:book>

<dc:title>Groovy in Action</dc:title>

<bibterm:year>2007</bibterm:year>

</bibterm:book>

</rdf:description>

Page 52: XML and Web Services with Groovy

DOMBuilder with NamespaceBuilder

import groovy.xml.*def b = NamespaceBuilder.newInstance(DOMBuilder.newInstance())b.namespace('http://www.book-stuff.com/terms/', 'bibterm')b.namespace('http://purl.org/dc/elements/1.0/', 'dc')b.namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf')

def root = b.'rdf:description' {'bibterm:book' {'dc:title'('Groovy in Action')'bibterm:year'('2007')

}}new XmlNodePrinter().print(root)

© A

SE

RT

2006-2

009

SpringOne2GX - 52

<?xml version="1.0" encoding="UTF-8"?>

<rdf:description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

<bibterm:book xmlns:bibterm="http://www.book-stuff.com/terms/">

<dc:title xmlns:dc="http://purl.org/dc/elements/1.0/">Groovy in Action</dc:title>

<bibterm:year>2007</bibterm:year>

</bibterm:book>

</rdf:description>

Page 53: XML and Web Services with Groovy

StaxBuilder

import javax.xml.stream.XMLOutputFactoryimport groovy.xml.StaxBuilder

def factory = XMLOutputFactory.newInstance()def writer = new StringWriter()def xmlwriter = factory.createXMLStreamWriter(writer)def builder = new StaxBuilder(xmlwriter)builder.flights {

flight(hours: 13) {from('Brisbane')to('Los Angeles')

}flight(hours: 4) {

from('Los Angeles')to('New Orleans')

}}println writer

© A

SE

RT

2006-2

009

SpringOne2GX - 53

Page 54: XML and Web Services with Groovy

StaxBuilder for non-XML (JSON)@Grab('org.codehaus.jettison#jettison;1.1')

import org.codehaus.jettison.mapped.*

import groovy.xml.StaxBuilder

def writer = new StringWriter()

def con = new MappedNamespaceConvention()

def mappedWriter = new MappedXMLStreamWriter(con,

writer)

def builder = new StaxBuilder(mappedWriter)

builder.flights {

flight(hours: 13) {

from('Brisbane')

to('Los Angeles')

}

flight(hours: 4) {

from('Los Angeles')

to('New Orleans')

}

}

println writer

© A

SE

RT

2006-2

009

SpringOne2GX - 54

{"flights":{"flight":[

{ "@hours":"13",

"from":"Brisbane",

"to":"Los Angeles" },

{ "@hours":"4",

"from":"Los Angeles",

"to":"New Orleans" }

]}}

Page 55: XML and Web Services with Groovy

Updating XML

<shopping>

<category type="groceries">

<item>Chocolate</item>

<item>Coffee</item>

</category>

<category type="supplies">

<item>Paper</item>

<item quantity="4">Pens</item>

</category>

<category type="present">

<item when="Aug 10">

Kathryn's Birthday

</item>

</category>

</shopping>

<shopping>

<category type="groceries">

<item>Luxury Chocolate</item>

<item>Luxury Coffee</item>

</category>

<category type="supplies">

<item>Paper</item>

<item quantity="6"

when="Urgent">Pens</item>

</category>

<category type="present">

<item>Mum's Birthday</item>

<item when="Oct 15">

Monica's Birthday

</item>

</category>

</shopping>

© A

SE

RT

2006-2

009

SpringOne2GX - 55

Page 56: XML and Web Services with Groovy

Updating with XmlParser

© A

SE

RT

2006-2

009

SpringOne2GX - 56

...def root = new XmlParser().parseText(Shopping.XML)

// modify groceries: luxury items pleaseroot.category.find{ it.@type == 'groceries' }.item.each{ g ->

g.value = 'Luxury ' + g.text()}

// modify supplies: we need extra pens nowroot.category.find{

it.@type == 'supplies'}.item.findAll{ it.text() == 'Pens' }.each{ p ->

p.@quantity = [email protected]() + 2p.@when = 'Urgent'

}

// modify presents: August has come and gonedef presents = root.category.find{ it.@type == 'present' }presents.children().clear()presents.appendNode('item', "Mum's Birthday")presents.appendNode('item', [when:'Oct 15'], "Monica's Birthday")...

Page 57: XML and Web Services with Groovy

Updating with XmlSlurper...// modify groceries: luxury items pleasedef groceries = root.category.find{ it.@type == 'groceries' }(0..<groceries.item.size()).each {

groceries.item[it] = 'Luxury ' + groceries.item[it]}

// modify supplies: we need extra pens nowroot.category.find{

it.@type == 'supplies'}.item.findAll{ it.text() == 'Pens' }.each { p ->

p.@quantity = ([email protected]() + 2).toString()p.@when = 'Urgent'

}

// modify presents: August has come and goneroot.category.find{ it.@type == 'present' }.replaceNode{ node ->

category(type:'present'){item("Mum's Birthday")item("Monica's Birthday", when:'Oct 15')

}}...

© A

SE

RT

2006-2

009

SpringOne2GX - 57

Page 58: XML and Web Services with Groovy

Updating with DOMCategoryuse(DOMCategory) {

// modify groceries: luxury items pleasedef groceries = root.category.find{ it.'@type' == 'groceries' }.itemgroceries.each { g ->

g.value = 'Luxury ' + g.text()}

// modify supplies: we need extra pens nowdef supplies = root.category.find{ it.'@type' == 'supplies' }.itemsupplies.findAll{ it.text() == 'Pens' }.each { p ->

p['@quantity'] = p.'@quantity'.toInteger() + 2p['@when'] = 'Urgent'

}

// modify presents: August has come and gonedef presents = root.category.find{ it.'@type' == 'present' }presents.item.each { presents.removeChild(it) }presents.appendNode('item', "Mum's Birthday")presents.appendNode('item', [when:'Oct 15'], "Monica's Birthday")...

}

© A

SE

RT

2006-2

009

SpringOne2GX - 58

Page 59: XML and Web Services with Groovy

Validating against a DTD...def xml = '''<!DOCTYPE records [

<!ELEMENT car (country,record)><!ATTLIST car

make NMTOKEN #REQUIREDname CDATA #REQUIREDyear NMTOKEN #REQUIRED

><!ELEMENT country (#PCDATA)><!ELEMENT record (#PCDATA)><!ATTLIST record type NMTOKEN #REQUIRED><!ELEMENT records (car+)>

]><records><car name="HSV Maloo" make="Holden" year="2006"><country>Australia</country><record

type="speed">Production Pickup Truck with speed of 271kph</record></car>...

</records>'''.trim()

© A

SE

RT

2006-2

009

SpringOne2GX - 59

Page 60: XML and Web Services with Groovy

...Validating against a DTD

def validating = truedef namespaceAware = false

© A

SE

RT

2006-2

009

SpringOne2GX - 60

new XmlParser(validating, namespaceAware).parseText(xml)

new XmlSlurper(validating, namespaceAware).parseText(xml)

import groovy.xml.DOMBuilderDOMBuilder.parse(new StringReader(xml), validating, namespaceAware)

Page 61: XML and Web Services with Groovy

Validating against a W3C Schema...def xsd = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

<xs:element name="records"><xs:complexType>

<xs:sequence><xs:element maxOccurs="unbounded" ref="car"/>

</xs:sequence></xs:complexType>

</xs:element><xs:element name="car">

<xs:complexType><xs:sequence>

<xs:element ref="country"/><xs:element ref="record"/>

</xs:sequence><xs:attribute name="make" use="required" type="xs:NCName"/><xs:attribute name="name" use="required"/><xs:attribute name="year" use="required" type="xs:integer"/>

</xs:complexType></xs:element><xs:element name="country" type="xs:string"/><xs:element name="record">

<xs:complexType mixed="true"><xs:attribute name="type" use="required" type="xs:NCName"/>

</xs:complexType></xs:element>

</xs:schema>'''.trim()

© A

SE

RT

2006-2

009

SpringOne2GX - 61

Page 62: XML and Web Services with Groovy

...Validating against a W3C Schema

import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URIimport javax.xml.transform.stream.StreamSourceimport javax.xml.validation.SchemaFactory

def factory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI)// println factory.isSchemaLanguageSupported(W3C_XML_SCHEMA_NS_URI)

def schema =factory.newSchema(new StreamSource(new StringReader(xsd)))

def validator = schema.newValidator()validator.validate(

new StreamSource(new StringReader(XmlExamples.CAR_RECORDS)))

© A

SE

RT

2006-2

009

SpringOne2GX - 62

Page 63: XML and Web Services with Groovy

Validating against a RelaxNG Schema...def rng = '''<grammar xmlns="http://relaxng.org/ns/structure/1.0"

datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"><start>

<ref name="records"/></start><define name="car">

<element name="car"><attribute name="make">

<data type="token"/></attribute><attribute name="name">

<text/></attribute><attribute name="year">

<data type="integer"/></attribute><ref name="country"/><ref name="record"/>

</element></define><define name="country">

<element name="country"><text/>

</element></define>...

© A

SE

RT

2006-2

009

SpringOne2GX - 63

...<define name="record">

<element name="record"><attribute name="type">

<data type="token"/></attribute><text/>

</element></define><define name="records">

<element name="records"><oneOrMore>

<ref name="car"/></oneOrMore>

</element></define>

</grammar>'''.trim()

Page 64: XML and Web Services with Groovy

...Validating against a RelaxNG Schema

// require isorelax.jar, isorelax-jaxp-bridge.jar// require one of Jing, MSV, ...import static javax.xml.XMLConstants.RELAXNG_NS_URIimport javax.xml.transform.stream.StreamSourceimport javax.xml.validation.SchemaFactory

def factory = SchemaFactory.newInstance(RELAXNG_NS_URI)def schema =

factory.newSchema(new StreamSource(new StringReader(rng)))def validator = schema.newValidator()validator.validate(new StreamSource(new StringReader(CAR_RECORDS)))

© A

SE

RT

2006-2

009

SpringOne2GX - 64

Page 65: XML and Web Services with Groovy

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

WEB SERVICES

Page 66: XML and Web Services with Groovy

Groovy and Web Services

• SOAP Web Services

– GroovySOAP using XFire for Java 1.4

– GroovyWS using CXF for Java 1.5+

– JAXB out of the box for Java 6

– CXF, Axis2, Spring Web Services

• RESTful Options– Restlet.org, RESTlet DSL, roll your own

– JAX-RS: Jersey, CXF, JBoss RESTeasy

• Frameworks layered upon SOA

– Synapse, Tuscany, ServiceMix

© A

SE

RT

2006-2

009

SpringOne2GX - 66

Page 67: XML and Web Services with Groovy

GroovySOAP

• XFire based

• Java 1.4

class MathService {double add(double a, double b) {

a + b}double square(double c) {

c * c}

} import groovy.net.soap.SoapServer

def server = new SoapServer('localhost', 6789)server.setNode('MathService')server.start()

import groovy.net.soap.SoapClient

def url = 'http://localhost:6789/MathServiceInterface?wsdl'def math = new SoapClient(url)assert math.add(1.0, 2.0) == 3.0assert math.square(3.0) == 9.0

© A

SE

RT

2006-2

009

SpringOne2GX - 67

Page 68: XML and Web Services with Groovy

GroovyWS

• CXF based

• Java 1.5+

class MathService {double add(double a, double b) {

a + b}double square(double c) {

c * c}

}import groovyx.net.ws.WSServerdef server = new WSServer()server.setNode MathService.name,

"http://localhost:6980/MathService"

import groovyx.net.ws.WSClientdef url = "http://localhost:6980/MathService?wsdl"def proxy = new WSClient(url, this.class.classLoader)def result = proxy.add(1.0d, 2.0d)assert result == 3.0dresult = proxy.square(3.0d)assert result == 9.0d

© A

SE

RT

2006-2

009

SpringOne2GX - 68

Page 69: XML and Web Services with Groovy

JAXB Server

import javax.xml.ws.Endpointimport javax.jws.WebServiceimport javax.jws.soap.SOAPBindingimport javax.jws.WebMethod

@WebService(name="Echo", serviceName="EchoService",targetNamespace="http://jaxws.asert.com")

@SOAPBinding(style=SOAPBinding.Style.RPC)class EchoImpl {

@WebMethod(operationName = "echo")String echo(String message) {

println "Received: $message""\nYou said: " + message

}}

Endpoint.publish("http://localhost:8080/Echo", new EchoImpl())println 'EchoService published and running ...'

© A

SE

RT

2006-2

009

SpringOne2GX - 69

Page 70: XML and Web Services with Groovy

JAXB Client

• JAXB Client

• Build instructions

import javax.xml.namespace.QNameimport com.asert.jaxws.EchoService

def url = new URL("http://localhost:8080/Echo?wsdl")def qname = new QName("http://jaxws.asert.com", "EchoService")def echoServer = new EchoService(url, qname).echoPortprintln echoServer.echo("Today is ${new Date()}")

wsimport -d ../build -p com.asert.jaxws http://localhost:8080/Echo?wsdl

© A

SE

RT

2006-2

009

SpringOne2GX - 70

Page 71: XML and Web Services with Groovy

Raw CXF• Apache CXF helps you build and develop

services. You can use frontend programming

APIs, like JAX-WS and support is provided for

SOAP, XML/HTTP, RESTful HTTP, ...

over HTTP, JMS, JBI, ...

– Follow instructions for Java but there is also

some special things you can do with Groovy

© A

SE

RT

2006-2

009

SpringOne2GX - 71

Page 72: XML and Web Services with Groovy

Axis2• Apache Axis is a comprehensive

implementation of SOAP

– Follow the instructions for Java but use

Groovy instead and precompile

– Use GroovyShell to call script at runtime

• Another article:

– http://www.developer.com/services/article.ph

p/10928_3570031_2

© A

SE

RT

2006-2

009

SpringOne2GX - 72

Page 73: XML and Web Services with Groovy

RESTful options• Several Options

– Already supported in discussed

frameworks, e.g. CXF

– Groovy Restlet DSLhttp://docs.codehaus.org/display/GROOVY/GroovyRestlet

– Jersey

http://wikis.sun.com/display/Jersey/Main

– restlet.org

http://www.restlet.org

© A

SE

RT

2006-2

009

SpringOne2GX - 73

Page 74: XML and Web Services with Groovy

restlet.orgimport org.restlet.*import org.restlet.data.*class MailboxResource extends Restlet {

void handle(Request request, Response response) {switch (request.method) {

case Method.GET:handleGet(request, response)break

case Method.PUT:handlePut(request, response)break

case Method.POST:handlePost(request, response)break

default:// The request method is not allowed; set an error statusresponse.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED)response.setAllowedMethods([Method.GET, Method.PUT, Method.POST] as Set)

}}void handleGet(request, response) {

response.setEntity("Hello, world!", MediaType.TEXT_PLAIN)}

// ...

© A

SE

RT

2006-2

009

SpringOne2GX - 74

Page 75: XML and Web Services with Groovy

GroovyRestlet DSLbuilder.component {current.servers.add(protocol.HTTP, 8182)application(uri: "") {router {def guard = guard(uri: "/docs", scheme: challengeScheme.HTTP_BASIC,

realm: "Restlet Tutorials")guard.secrets.put("scott", "tiger".toCharArray())guard.next = directory(root: "", autoAttach: false)restlet(uri: "/users/{user}", handle: {req, resp ->resp.setEntity("Account of user \"${req.attributes.get('user')}\"",

mediaType.TEXT_PLAIN)})restlet(uri: "/users/{user}/orders", handle: {req, resp ->resp.setEntity("Orders or user \"${req.attributes.get('user')}\"",

mediaType.TEXT_PLAIN)})restlet(uri: "/users/{user}/orders/{order}", handle: {req, resp ->def attrs = req.attributesdef message ="Order \"${attrs.get('order')}\" for User \"${attrs.get('user')}\""resp.setEntity(message, mediaType.TEXT_PLAIN)

})}

}}.start() Source: http://docs.codehaus.org/display/GROOVY/GroovyRestlet

© A

SE

RT

2006-2

009

SpringOne2GX - 75

Page 76: XML and Web Services with Groovy

Jersey...package com.asert

import javax.ws.rs.GETimport javax.ws.rs.Pathimport javax.ws.rs.Producesimport static com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory.*

@Path ("/helloworld")class HelloWorldResource {

@GET @Produces("text/plain")String getPlainMessage() {

"Hello World"}

}

def baseUri = "http://localhost:9998/"def initParams = ["com.sun.jersey.config.property.packages": "com.asert"]

println """Starting grizzly with Jersey...App WADL available at ${baseUri}application.wadlApp available at ${baseUri}helloworld"""create(baseUri, initParams)

© A

SE

RT

2006-2

009

SpringOne2GX - 76

Page 77: XML and Web Services with Groovy

...Jersey...import javax.ws.rs.PathParamimport javax.xml.bind.annotation.*

class PrettyXml {static print(node) {

def writer = new StringWriter()new XmlNodePrinter(new PrintWriter(writer)).print(node)writer.toString()

}}

@XmlRootElement@XmlAccessorType (XmlAccessType.FIELD)class FlightInfoBean {

@XmlAttribute String hours@XmlElement String from, tostatic populate(num) {

def trip = new XmlParser().parse(Flights.reader)def f = trip.flight[num as int]new FlightInfoBean(hours:f.@hours,

from:f.from.text(),to:f.to.text())

}}

© A

SE

RT

2006-2

009

SpringOne2GX - 77

Page 78: XML and Web Services with Groovy

...Jersey@Path("/flight/xml/{flightnum}")class FlightInfoXml {

@GET @Produces("text/xml")String getXmlMessage(@PathParam('flightnum') String num) {

def trip = new XmlParser().parse(Flights.reader)PrettyXml.print(trip.flight[num as int])

}}

@Path("/flight/json/{flightnum}")class FlightInfoJson {

@GET @Produces("application/json")FlightInfoBean getJsonMessage(@PathParam('flightnum') String num) {

FlightInfoBean.populate(num)}

}

@Path("/flight/atom/{flightnum}")class FlightInfoAtom {

@GET @Produces("application/atom")FlightInfoBean getAtomMessage(@PathParam('flightnum') String num) {

FlightInfoBean.populate(num)}

}

© A

SE

RT

2006-2

009

SpringOne2GX - 78

Page 79: XML and Web Services with Groovy

Jersey output

© A

SE

RT

2006-2

009

> curl http://localhost:9998/helloworld

Hello World

> curl http://localhost:9998/flight/xml/1

<flight hours="4">

<from>

Los Angeles

</from>

<to>

New Orleans

</to>

</flight>

> curl http://localhost:9998/flight/json/1

{"@hours":"4","from":"Los Angeles","to":"New Orleans"}

> curl http://localhost:9998/flight/atom/1

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<flightInfoBean hours="4">

<from>Los Angeles</from>

<to>New Orleans</to>

</flightInfoBean>

SpringOne2GX - 79

Page 80: XML and Web Services with Groovy

Synapse• Apache Synapse is a simple, lightweight and

high performance Enterprise Service Bus (ESB)

with support for XML, Web services, binary and

text formats

– Groovy scripting, endpoints, Synapse DSL

– https://svn.apache.org/repos/asf/synapse/

trunk/java/src/site/resources/presentations/

makingsoagroovyfremantle.pdf

© A

SE

RT

2006-2

009

SpringOne2GX - 80

Page 81: XML and Web Services with Groovy

ServiceMix• ServiceMix is an open source Enterprise Service

Bus (ESB) combining Service Oriented

Architecture (SOA), Event Driven Architecture

(EDA) and Java Business Integration (JBI)

functionality

– You can use ServiceMix Scripting

– You can use legacy ScriptComponent and

GroovyComponent

– You can write Groovy JBI components

© A

SE

RT

2006-2

009

SpringOne2GX - 81

Page 82: XML and Web Services with Groovy

Tuscany...• Tuscany embodies Service Component

Architecture (SCA) which defines a simple,

service-based model for construction, assembly

and deployment of a network of services

(existing and new ones) that are defined in a

language-neutral way.”

– You can define your services using Groovy

either using Java mechanisms

or Scripting integration

© A

SE

RT

2006-2

009

SpringOne2GX - 82

Page 83: XML and Web Services with Groovy

...Tuscany...

<composite ...>

<component name="CalculatorServiceComponent" .../>

<component name="AddServiceComponent" .../>

<component name="SubtractServiceComponent">

<tuscany:implementation.java

class="calculator.SubtractServiceImpl"/>

</component>

<component name="MultiplyServiceComponent">

<tuscany:implementation.script language="groovy">

def multiply(n1, n2) {

n1 * n2

}

</tuscany:implementation.script>

</component>

<component name="DivideServiceComponent">

<tuscany:implementation.script

script="calculator/DivideServiceImpl.groovy"/>

</component>

</composite>

Compile your Groovy using groovyc

(with or without annotations) then

treat just like normal Java. Need

groovy jar in your runtime classpath.

© A

SE

RT

2006-2

009

SpringOne2GX - 83

Page 84: XML and Web Services with Groovy

...Tuscany

<composite ...>

<component name="CalculatorServiceComponent" .../>

<component name="AddServiceComponent" .../>

<component name="SubtractServiceComponent">

<tuscany:implementation.java

class="calculator.SubtractServiceImpl"/>

</component>

<component name="MultiplyServiceComponent">

<tuscany:implementation.script language="groovy">

def multiply(n1, n2) {

n1 * n2

}

</tuscany:implementation.script>

</component>

<component name="DivideServiceComponent">

<tuscany:implementation.script

script="calculator/DivideServiceImpl.groovy"/>

</component>

</composite>

With Groovy scripts either

embedded or in files – no

compilation necessary.

© A

SE

RT

2006-2

009

SpringOne2GX - 84

Page 85: XML and Web Services with Groovy

More Information: on the web

• Web sites– http://groovy.codehaus.org

– http://grails.codehaus.org

– http://pleac.sourceforge.net/pleac_groovy (many examples)

– http://www.asert.com.au/training/java/GV110.htm (workshop)

• Mailing list for users– [email protected]

• Information portals– http://www.aboutgroovy.org

– http://www.groovyblogs.org

• Documentation (1000+ pages)– Getting Started Guide, User Guide, Developer Guide, Testing

Guide, Cookbook Examples, Advanced Usage Guide

• Books– Several to choose from ...

© A

SE

RT

2006-2

009

SpringOne2GX - 85

Page 86: XML and Web Services with Groovy

More Information: Groovy in Action

© A

SE

RT

2006-2

009

SpringOne2GX - 86