SlideShare a Scribd company logo
1 of 86
Download to read offline
XML and Web
Services with Groovy
Dr Paul King, ASERT: @paulk_asert, paulk@asert.com.au
                                                SpringOne2GX - 1
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.”
© ASERT 2006-2009




                     Groovy = Java –   boiler plate code
                                   +   optional dynamic typing
                                   +   closures
                                   +   domain specific languages
                                   +   builders
                                   +   metaprogramming
                                                               SpringOne2GX - 2
Growing Acceptance …
  A slow and steady start but now gaining in
  momentum, maturity and mindshare




Now free
… Growing Acceptance …
© ASERT 2006-2009




                                             SpringOne2gx_Oct2009 - 4
… Growing Acceptance …
© ASERT 2006-2009




                     Groovy and Grails downloads:
                     70-90K per month and growing   SpringOne2gx_Oct2009 - 5
… Growing Acceptance …
© ASERT 2006-2009




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




                                                      Source: http://www.grailspodcast.com/
                                                                           SpringOne2gx_Oct2009 - 6
… Growing Acceptance …
© ASERT 2006-2009




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




                                                               http://www.java.net
                                                                               SpringOne2gx_Oct2009 - 7
… Growing Acceptance …
                What alternative JVM language are you using or intending to use
© ASERT 2006-2009




                                 http://www.leonardoborges.com/writings
                                                                          SpringOne2gx_Oct2009 - 8
… Growing Acceptance …
© ASERT 2006-2009




                    http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo.com)
                                                                                                                          SpringOne2gx_Oct2009 - 9
… Growing Acceptance
© ASERT 2006-2009




                                           SpringOne2gx_Oct2009 - 10
Better XML Manipulation...


                    <records>                                                                     records.xml
                       <car name='HSV Maloo' make='Holden' year='2006'>
                         <country>Australia</country>
                         <record type='speed'>Production Pickup Truck with speed of 271kph</record>
                       </car>
© ASERT 2006-2009




                       <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>




                                                                                                      AUG 2009 - 11
...Better XML Manipulation...
                    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) {
© ASERT 2006-2009




                            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();
                            }
                        }
                    }
                                                                                                            AUG 2009 - 12
...Better XML Manipulation...
                    import   org.w3c.dom.Document;
                    import   org.w3c.dom.NodeList;
                    import   org.w3c.dom.Node;                                          boilerplate
                    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) {
© ASERT 2006-2009




                            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();
                            }
                        }
                    }
                                                                                                            AUG 2009 - 13
...Better XML Manipulation



                    def records = new XmlParser().parse("records.xml")
                    records.car.each {
© ASERT 2006-2009




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



                                                   year = 2006
                                                   year = 1962
                                                   year = 1931


                                                                 AUG 2009 - 14
XML


      SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
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.
© ASERT 2006-2009




                    • Creating XML
                      – Special Groovy support:
                        MarkupBuilder and StreamingMarkupBuilder
                      – Or again, enhanced syntax for your current
                        favorites

                                                            SpringOne2GX - 16
... Groovy and XML ...
                    • Updating XML
                      – Using above: read followed by create
                      – Can be done with XmlParser, XmlSlurper,
                        DOMCategory
                      – Or with your Java favorites
© ASERT 2006-2009




                    • Verifying XML
                      – Also DTD, W3C XML Schema, Relax NG in a
                        similar fashion to Java mechanisms for these
                        features




                                                             SpringOne2GX - 17
... 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
© ASERT 2006-2009




                        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



                                                              SpringOne2GX - 18
An Xml Example ...
                    import groovy.xml.dom.DOMCategory

                    class Flights {
                        static final String XML = '''
                            <trip>
                                <flight hours="13">
                                    <from>Brisbane</from>
© ASERT 2006-2009




                                    <to>Los Angeles</to>
                                </flight>
                                <flight hours="4">
                                    <from>Los Angeles</from>
                                    <to>New Orleans</to>
                                </flight>
                            </trip>
                        '''
                    ...
                                                               SpringOne2GX - 19
... An Xml Example
                    ...
                          static final Reader getReader() {
                              new StringReader(XML)
                          }
                          static final Set getCities(flights) {
                              Set cities = []
© ASERT 2006-2009




                              use(DOMCategory) {
                                  flights.each { f ->
                                      cities += f.to[0].text()
                                      cities += f.from[0].text()
                                  }
                              }                    You can mostly ignore
                              cities               the details here for now.
                          }                        We’ll cover DOMCategory
                    }                                  in more detail shortly.

                                                                         SpringOne2GX - 20
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()
© ASERT 2006-2009




                    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

                                                               SpringOne2GX - 21
XmlParser – Under the covers
                    • For a JavaBean, this Groovy expression:
                       trip.flight[0].to[0].text()

                    • Is “roughly” converted to:
                       trip.getflight().get(0).getTo().get(0).text()
© ASERT 2006-2009




                      where getFlight() and getTo() return a List
                    • But for XML Parser, it overrides this mechanism
                      and “roughly” converts to:
                       trip.getByName('flight').get(0).
                                getByName('to').get(0).text()

                      where getByName is a Groovy method similar to
                      getElementsByTagName in org.w3c.dom.Element
                                                                SpringOne2GX - 22
XmlSlurper...
                    • The same again using XmlSlurper
                      – Mostly identical syntax and capabilities
                    def trip = new XmlSlurper().parseText(Flights.XML)
                    assert trip.flight[0].to.text() == 'Los Angeles'
                    assert trip.flight[1].@hours == '4'
© ASERT 2006-2009




                    Set cities = trip.flight.from*.text() +
                            trip.flight.to*.text()
                    assert cities == ['Brisbane', 'Los Angeles',
                                      'New Orleans'] as Set

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

                      – But features lazy evaluation of expressions
                      – Consider this for streaming scenarios         SpringOne2GX - 23
...XmlSlurper...
                    • What does Lazy mean?

                     def   trip = new XmlSlurper().parseText(Flights.XML)
                     def   moreThanFiveHours = { f -> f.@hours.toInteger() > 5 }
                     def   arrivingLax = { f -> f.to == 'Los Angeles' }
                     def   departingOz = { f -> f.from == 'Brisbane' }
© ASERT 2006-2009




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




                                                                          SpringOne2GX - 24
...XmlSlurper
                    Light-weight scanning here

                     def   trip = new XmlSlurper().parseText(Flights.XML)
                     def   moreThanFiveHours = { f -> f.@hours.toInteger() > 5 }
                     def   arrivingLax = { f -> f.to == 'Los Angeles' }
                     def   departingOz = { f -> f.from == 'Brisbane' }
© ASERT 2006-2009




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


                                                        Lazy expression storage
                       Usage triggers evaluation         but deferred evaluation

                    • This may look puzzling at first
                      – But the good news is you don’t normally haveSpringOne2GX - 25
                                                                     to care
A Namespace Example
                    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>
© ASERT 2006-2009




                            <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>
                      ''' ...
                                                                           SpringOne2GX - 26
XmlParser and Namespaces
                    • Recommended syntax:
                       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'
© ASERT 2006-2009




                    • 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 directly
                       def bibtermYear = new QName('http://www.book-stuff.com/terms/', 'year')
                       assert b[bibtermYear].text() == '2007'

                       // use QName with wildcards
                       def anyYear = new QName('*', 'year')
                       assert b[anyYear].text() == '2007'
                                                                                      SpringOne2GX - 27
XmlSlurper and Namespaces

                    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'
© ASERT 2006-2009




                    assert b.'dc:title' == 'Groovy in Action'
                    assert b.'bibterm:year' == '2007'




                                                                      SpringOne2GX - 28
Other GPath Features
                    • Similar syntax for XmlSlurper and DOMCategory

                      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() ==
© ASERT 2006-2009




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




                                                                            SpringOne2GX - 29
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')
                     }
© ASERT 2006-2009




                     data.each { println it }

                     def neko = new SAXParser() // alternate style
                     def page = new XmlSlurper(neko).parse('http://groovy.codehaus.org/')
                     def data = page.depthFirst().grep{
                         it.name() == 'A' && it.@href.toString().endsWith('.html')
                     }.'@href'
                     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
                                                                                      SpringOne2GX - 30
Raw DOM

                    import groovy.xml.DOMBuilder

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

                    def dest = flights.item(0).getElementsByTagName('to').item(0)
© ASERT 2006-2009




                    assert dest.firstChild.nodeValue == 'Los Angeles'

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

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




                                                                          SpringOne2GX - 31
DOM plus metaprogramming

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

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

                    Element.metaClass.element = { t, i ->
© ASERT 2006-2009




                            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'




                                                                        SpringOne2GX - 32
DOMCategory
                    import groovy.xml.DOMBuilder
                    import groovy.xml.dom.DOMCategory

                    def doc = DOMBuilder.parse(Flights.reader)
                    def trip = doc.documentElement
© ASERT 2006-2009




                    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
                    }

                                                            SpringOne2GX - 33
DOM4J


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

                    def trip = new SAXReader().read(Flights.reader).rootElement
© ASERT 2006-2009




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




                                                                        SpringOne2GX - 34
JDOM


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

                    def b = new SAXBuilder()
                    def trip = b.build(Flights.reader).rootElement
© ASERT 2006-2009




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




                                                                       SpringOne2GX - 35
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')
© ASERT 2006-2009




                    assert to.value == 'Los Angeles'
                    def hours = flights.get(1).getAttribute('hours')
                    assert hours.value == '4'




                                                                 SpringOne2GX - 36
StAX
                    import static javax.xml.stream.XMLInputFactory.newInstance as staxFactory
                    import javax.xml.stream.XMLStreamReader as StaxReader

                    def flights = []
                    def flight
                    def seenTag
                    StaxReader.metaClass.attr = { s -> delegate.getAttributeValue(null, s) }

                    def reader = staxFactory().createXMLStreamReader(Flights.reader)
                    while (reader.hasNext()) {
                        def name = reader.localName
© ASERT 2006-2009




                        if (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 += flight
                            seenTag = null
                        }
                        reader.next()
                    }

                    assert flights[0].to == 'Los Angeles'
                    assert flights[1].hours == '4'
                                                                                     SpringOne2GX - 37
SAX
                    import javax.xml.parsers.SAXParserFactory
                    import 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
                        }
© ASERT 2006-2009




                        public void endElement(String uri, String localName, String qName) {
                            if (qName == 'flight') flights += flight
                            seenTag = 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().xMLReader
                    reader.setContentHandler(handler)
                    reader.parse(new InputSource(Flights.reader))

                    assert handler.flights[0].to == 'Los Angeles'
                    assert handler.flights[1].hours == '4'
                                                                                               SpringOne2GX - 38
XPath
                    import javax.xml.xpath.*
                    import groovy.xml.DOMBuilder

                    def xpath = XPathFactory.newInstance().newXPath()
                    def trip = DOMBuilder.parse(Flights.reader).documentElement
                    assert xpath.evaluate('flight/to/text()', trip) ==
                            'Los Angeles'
                    assert xpath.evaluate('flight[2]/@hours', trip) == '4'
© ASERT 2006-2009




                    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


                                                                        SpringOne2GX - 39
XPath with DOMCategory


                    import groovy.xml.DOMBuilder
                    import groovy.xml.dom.DOMCategory
                    import static javax.xml.xpath.XPathConstants.*

                    def trip = DOMBuilder.parse(Flight.reader).documentElement
© ASERT 2006-2009




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




                                                                       SpringOne2GX - 40
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() ==
© ASERT 2006-2009




                            '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


                                                                         SpringOne2GX - 41
Jaxen XPath
                    @Grab('jaxen#jaxen;1.1.1')
                    import org.jaxen.dom.DOMXPath
                    import groovy.xml.DOMBuilder

                    def trip = DOMBuilder.parse(Flights.reader).documentElement
                    assert new DOMXPath('flight/to/text()').
                            stringValueOf(trip) == 'Los Angeles'
© ASERT 2006-2009




                    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

                                                                        SpringOne2GX - 42
JSR 225 - XQJ
                    import net.sf.saxon.xqj.SaxonXQDataSource
                    import javax.xml.xquery.XQSequence
                    XQSequence.metaClass.collect = { Closure c ->
                        def items = []
                        while (delegate.next()) items += c(delegate)
                        items
                    }
                    def asString = { seq -> seq.getItemAsString(null) }
© ASERT 2006-2009




                    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


                                                                        SpringOne2GX - 43
XSLT...
                    import static javax.xml.transform.TransformerFactory.newInstance as xsltFactory
                    import 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>
© ASERT 2006-2009




                          </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))
                                                                                       SpringOne2GX - 44
...XSLT
                    import static javax.xml.transform.TransformerFactory.newInstance as xsltFactory
                    import javax.xml.transform.stream.*
                    def xslt = '''
                                                           <html>
                    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
                      <xsl:template match="/trip">           <body>
                        <html>                                 <h1>Flights</h1>
                          <body>                               <ul>
                            <h1>Flights</h1>                     <li>Brisbane =&gt; Los Angeles</li>
                            <ul>                                 <li>Los Angeles =&gt; New Orleans</li>
                                                               </ul>
                              <xsl:apply-templates select="flight"/>
                            </ul>                            </body>
© ASERT 2006-2009




                          </body>                          </html>
                        </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))
                                                                                           SpringOne2GX - 45
MarkupBuilder

                    import groovy.xml.MarkupBuilder

                    def writer = new StringWriter()
                    def xml = new MarkupBuilder(writer)
                    xml.flights {
                      flight(hours:13) {
© ASERT 2006-2009




                        from('Brisbane')
                        to('Los Angeles')
                      }
                      flight(hours:4) {
                        from('Los Angeles')
                        to('New Orleans')
                      }
                    }
                    println writer



                                                          SpringOne2GX - 46
StreamingMarkupBuilder

                    import groovy.xml.StreamingMarkupBuilder

                    def writer = new StreamingMarkupBuilder().bind {
                      flights {
                        flight(hours: 13) {
                          from('Brisbane')
© ASERT 2006-2009




                          to('Los Angeles')
                        }
                        flight(hours: 4) {
                          from('Los Angeles')
                          to('New Orleans')
                        }
                      }
                    }
                    println writer



                                                                  SpringOne2GX - 47
DOMBuilder

                    import groovy.xml.*

                    def builder = DOMBuilder.newInstance()
                    def root = builder.flights {
                        flight(hours: 13) {
                          from('Brisbane')
© ASERT 2006-2009




                          to('Los Angeles')
                        }
                        flight(hours: 4) {
                          from('Los Angeles')
                          to('New Orleans')
                        }
                    }
                    new XmlNodePrinter().print(root)




                                                             SpringOne2GX - 48
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-
© ASERT 2006-2009




                    ns#") {
                      'bibterm:book' {
                        'dc:title'('Groovy in Action')
                        'bibterm:year'('2007')
                      }
                                     <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/'
                    }                    xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
                    println writer       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>
                                                                                       SpringOne2GX - 49
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' {
© ASERT 2006-2009




                        'bibterm:book' {
                          'dc:title'('Groovy in Action')
                          'bibterm:year'('2007')
                        }
                      }              <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/'
                                         xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
                    }, System.out)
                                             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>
                                                                                        SpringOne2GX - 50
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')
© ASERT 2006-2009




                        'bibterm:year'('2007')
                      }
                    }
                    new XmlNodePrinter().print(root)

                                       <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>
                                                                                        SpringOne2GX - 51
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')
© ASERT 2006-2009




                        'bibterm:year'('2007')
                      }
                    }
                    new XmlNodePrinter().print(root)

                    <?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>

                                                                                               SpringOne2GX - 52
StaxBuilder
                    import javax.xml.stream.XMLOutputFactory
                    import groovy.xml.StaxBuilder

                    def factory = XMLOutputFactory.newInstance()
                    def writer = new StringWriter()
                    def xmlwriter = factory.createXMLStreamWriter(writer)
                    def builder = new StaxBuilder(xmlwriter)
                    builder.flights {
© ASERT 2006-2009




                      flight(hours: 13) {
                        from('Brisbane')
                        to('Los Angeles')
                      }
                      flight(hours: 4) {
                        from('Los Angeles')
                        to('New Orleans')
                      }
                    }
                    println writer

                                                                     SpringOne2GX - 53
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)
© ASERT 2006-2009




                    builder.flights {
                      flight(hours: 13) {
                        from('Brisbane')                 {"flights":{"flight":[
                        to('Los Angeles')                 { "@hours":"13",
                      }                                     "from":"Brisbane",
                      flight(hours: 4) {                    "to":"Los Angeles" },
                        from('Los Angeles')               { "@hours":"4",
                        to('New Orleans')                   "from":"Los Angeles",
                      }                                     "to":"New Orleans" }
                    }                                    ]}}
                    println writer
                                                                         SpringOne2GX - 54
Updating XML

                                                       <shopping>
                    <shopping>                           <category type="groceries">
                      <category type="groceries">          <item>Luxury Chocolate</item>
                        <item>Chocolate</item>             <item>Luxury Coffee</item>
                        <item>Coffee</item>              </category>
                      </category>                        <category type="supplies">
                      <category type="supplies">           <item>Paper</item>
                        <item>Paper</item>                 <item quantity="6"
© ASERT 2006-2009




                        <item quantity="4">Pens</item>            when="Urgent">Pens</item>
                      </category>                        </category>
                      <category type="present">          <category type="present">
                        <item when="Aug 10">               <item>Mum's Birthday</item>
                          Kathryn's Birthday               <item when="Oct 15">
                        </item>                              Monica's Birthday
                      </category>                          </item>
                    </shopping>                          </category>
                                                       </shopping>




                                                                                 SpringOne2GX - 55
Updating with XmlParser
                    ...
                    def root = new XmlParser().parseText(Shopping.XML)

                    // modify groceries: luxury items please
                    root.category.find{ it.@type == 'groceries' }.item.each{ g ->
                        g.value = 'Luxury ' + g.text()
                    }

                    // modify supplies: we need extra pens now
                    root.category.find{
© ASERT 2006-2009




                        it.@type == 'supplies'
                    }.item.findAll{ it.text() == 'Pens' }.each{ p ->
                        p.@quantity = p.@quantity.toInteger() + 2
                        p.@when = 'Urgent'
                    }

                    // modify presents: August has come and gone
                    def 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")
                    ...

                                                                                    SpringOne2GX - 56
Updating with XmlSlurper
                    ...
                    // modify groceries: luxury items please
                    def 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 now
                    root.category.find{
                        it.@type == 'supplies'
© ASERT 2006-2009




                    }.item.findAll{ it.text() == 'Pens' }.each { p ->
                        p.@quantity = (p.@quantity.toInteger() + 2).toString()
                        p.@when = 'Urgent'
                    }

                    // modify presents: August has come and gone
                    root.category.find{ it.@type == 'present' }.replaceNode{ node ->
                        category(type:'present'){
                            item("Mum's Birthday")
                            item("Monica's Birthday", when:'Oct 15')
                        }
                    }
                    ...
                                                                                 SpringOne2GX - 57
Updating with DOMCategory
                    use(DOMCategory) {
                       // modify groceries: luxury items please
                       def groceries = root.category.find{ it.'@type' == 'groceries' }.item
                       groceries.each { g ->
                          g.value = 'Luxury ' + g.text()
                       }

                        // modify supplies: we need extra pens now
                        def supplies = root.category.find{ it.'@type' == 'supplies' }.item
                        supplies.findAll{ it.text() == 'Pens' }.each { p ->
© ASERT 2006-2009




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

                        // modify presents: August has come and gone
                        def 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")
                        ...
                    }


                                                                                   SpringOne2GX - 58
Validating against a DTD...
                    def xml = '''
                    <!DOCTYPE records [
                        <!ELEMENT car (country,record)>
                        <!ATTLIST car
                            make NMTOKEN #REQUIRED
                            name CDATA #REQUIRED
                            year NMTOKEN #REQUIRED
                        >
                        <!ELEMENT country (#PCDATA)>
                        <!ELEMENT record (#PCDATA)>
© ASERT 2006-2009




                        <!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()


                                                                                      SpringOne2GX - 59
...Validating against a DTD

                    def validating = true
                    def namespaceAware = false




                    new XmlParser(validating, namespaceAware).parseText(xml)
© ASERT 2006-2009




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




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




                                                                                SpringOne2GX - 60
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>
© ASERT 2006-2009




                            <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()
                                                                                               SpringOne2GX - 61
...Validating against a W3C Schema

                    import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI
                    import javax.xml.transform.stream.StreamSource
                    import javax.xml.validation.SchemaFactory

                    def factory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI)
                    // println factory.isSchemaLanguageSupported(W3C_XML_SCHEMA_NS_URI)
© ASERT 2006-2009




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




                                                                                 SpringOne2GX - 62
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>                             <define name="record">
                                <attribute name="name">
© ASERT 2006-2009




                                                                             <element name="record">
                                    <text/>                                      <attribute name="type">
                                </attribute>                                         <data type="token"/>
                                <attribute name="year">                          </attribute>
                                    <data type="integer"/>                       <text/>
                                </attribute>                                 </element>
                                <ref name="country"/>                    </define>
                                <ref name="record"/>                     <define name="records">
                            </element>                                       <element name="records">
                        </define>                                                <oneOrMore>
                        <define name="country">                                      <ref name="car"/>
                            <element name="country">                             </oneOrMore>
                                <text/>                                      </element>
                            </element>                                   </define>
                        </define>                                    </grammar>
                        ...                                          '''.trim()
                                                                                               SpringOne2GX - 63
...Validating against a RelaxNG Schema

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

                    def factory = SchemaFactory.newInstance(RELAXNG_NS_URI)
© ASERT 2006-2009




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




                                                                              SpringOne2GX - 64
WEB SERVICES


      SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
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
© ASERT 2006-2009




                    • RESTful Options
                      – Restlet.org, RESTlet DSL, roll your own
                      – JAX-RS: Jersey, CXF, JBoss RESTeasy
                    • Frameworks layered upon SOA
                      – Synapse, Tuscany, ServiceMix


                                                                  SpringOne2GX - 66
GroovySOAP
                    class MathService {                   • XFire based
                       double add(double a, double b) {
                          a + b                           • Java 1.4
                       }
                       double square(double c) {
                          c * c
                       }
                    }       import groovy.net.soap.SoapServer
© ASERT 2006-2009




                            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.0
                    assert math.square(3.0) == 9.0
                                                                        SpringOne2GX - 67
GroovyWS
                    class MathService {                         • CXF based
                        double add(double a, double b) {
                            a + b                               • Java 1.5+
                        }
                        double square(double c) {
                            c * c
                        }
                    }
                    import groovyx.net.ws.WSServer
© ASERT 2006-2009




                    def server = new WSServer()
                    server.setNode MathService.name,
                        "http://localhost:6980/MathService"

                           import groovyx.net.ws.WSClient
                           def 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.0d
                           result = proxy.square(3.0d)
                           assert result == 9.0d
                                                                             SpringOne2GX - 68
JAXB Server
                    import   javax.xml.ws.Endpoint
                    import   javax.jws.WebService
                    import   javax.jws.soap.SOAPBinding
                    import   javax.jws.WebMethod

                    @WebService(name="Echo", serviceName="EchoService",
                                targetNamespace="http://jaxws.asert.com")
                    @SOAPBinding(style=SOAPBinding.Style.RPC)
© ASERT 2006-2009




                    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 ...'



                                                                            SpringOne2GX - 69
JAXB Client
                    • JAXB Client
                    import javax.xml.namespace.QName
                    import 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).echoPort
© ASERT 2006-2009




                    println echoServer.echo("Today is ${new Date()}")



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




                                                                                     SpringOne2GX - 70
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
© ASERT 2006-2009




                         some special things you can do with Groovy




                                                                SpringOne2GX - 71
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:
© ASERT 2006-2009




                      – http://www.developer.com/services/article.ph
                        p/10928_3570031_2




                                                                SpringOne2GX - 72
RESTful options
                    • Several Options
                      – Already supported in discussed
                        frameworks, e.g. CXF
                      – Groovy Restlet DSL
                        http://docs.codehaus.org/display/GROOVY/GroovyRestlet
                      – Jersey
© ASERT 2006-2009




                        http://wikis.sun.com/display/Jersey/Main
                      – restlet.org
                        http://www.restlet.org




                                                                          SpringOne2GX - 73
restlet.org
  import 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)
© ASERT 2006-2009




                            break

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

                        default:
                            // The request method is not allowed; set an error status
                            response.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)
      }
  // ...
                                                                                          SpringOne2GX - 74
GroovyRestlet DSL
                    builder.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)
© ASERT 2006-2009




                          })
                          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.attributes
                            def 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
                                                                                       SpringOne2GX - 75
Jersey...
                    package com.asert

                    import   javax.ws.rs.GET
                    import   javax.ws.rs.Path
                    import   javax.ws.rs.Produces
                    import   static com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory.*

                    @Path ("/helloworld")
                    class HelloWorldResource {
                        @GET @Produces("text/plain")
© ASERT 2006-2009




                        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.wadl
                    App available at ${baseUri}helloworld
                    """
                    create(baseUri, initParams)

                                                                                             SpringOne2GX - 76
...Jersey...
                    import javax.ws.rs.PathParam
                    import javax.xml.bind.annotation.*

                    class PrettyXml {
                        static print(node) {
                            def writer = new StringWriter()
                            new XmlNodePrinter(new PrintWriter(writer)).print(node)
                            writer.toString()
                        }
                    }
© ASERT 2006-2009




                    @XmlRootElement
                    @XmlAccessorType (XmlAccessType.FIELD)
                    class FlightInfoBean {
                        @XmlAttribute String hours
                        @XmlElement String from, to
                        static 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())
                        }
                    }
                                                                                SpringOne2GX - 77
...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}")
© ASERT 2006-2009




                    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)
                        }
                    }
                                                                                     SpringOne2GX - 78
Jersey output
                    > curl http://localhost:9998/helloworld
                    Hello World

                    > curl http://localhost:9998/flight/xml/1
                    <flight hours="4">
                     <from>
                       Los Angeles
                     </from>
                     <to>
                       New Orleans
© ASERT 2006-2009




                     </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
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/
© ASERT 2006-2009




                         trunk/java/src/site/resources/presentations/
                         makingsoagroovyfremantle.pdf




                                                              SpringOne2GX - 80
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
© ASERT 2006-2009




                       – You can use legacy ScriptComponent and
                         GroovyComponent
                       – You can write Groovy JBI components




                                                              SpringOne2GX - 81
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.”
© ASERT 2006-2009




                       – You can define your services using Groovy
                         either using Java mechanisms
                         or Scripting integration




                                                             SpringOne2GX - 82
...Tuscany...
                    <composite ...>
                        <component name="CalculatorServiceComponent" .../>
                        <component name="AddServiceComponent" .../>
                        <component name="SubtractServiceComponent">
                            <tuscany:implementation.java
                                class="calculator.SubtractServiceImpl"/>
                        </component>
                        <component name="MultiplyServiceComponent">
© ASERT 2006-2009




                            <tuscany:implementation.script language="groovy">
                                def multiply(n1, n2) { using groovyc
                                  Compile your Groovy
                                }
                                   (with*or without annotations) then
                                      n1   n2

                            </tuscany:implementation.script> Need
                                    treat just like normal Java.
                        </component>
                                 groovy jar in your runtime classpath.
                        <component name="DivideServiceComponent">
                            <tuscany:implementation.script
                                script="calculator/DivideServiceImpl.groovy"/>
                        </component>
                    </composite>

                                                                       SpringOne2GX - 83
...Tuscany
                    <composite ...>
                                                    With Groovy scripts either
                        <component name="CalculatorServiceComponent" .../>
                        <component name="AddServiceComponent" .../> files – no
                                                     embedded or in
                        <component name="SubtractServiceComponent">
                                                      compilation necessary.
                            <tuscany:implementation.java
                                class="calculator.SubtractServiceImpl"/>
                        </component>
                        <component name="MultiplyServiceComponent">
© ASERT 2006-2009




                            <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>

                                                                       SpringOne2GX - 84
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
                      – user@groovy.codehaus.org
© ASERT 2006-2009




                    • 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 ...
                                                                              SpringOne2GX - 85
More Information: Groovy in Action
© ASERT 2006-2009




                                                    SpringOne2GX - 86

More Related Content

What's hot

JAX-RS JavaOne Hyderabad, India 2011
JAX-RS JavaOne Hyderabad, India 2011JAX-RS JavaOne Hyderabad, India 2011
JAX-RS JavaOne Hyderabad, India 2011Shreedhar Ganapathy
 
Getting Started with WebSocket and Server-Sent Events in Java
Getting Started with WebSocket and Server-Sent Events in JavaGetting Started with WebSocket and Server-Sent Events in Java
Getting Started with WebSocket and Server-Sent Events in JavaArun Gupta
 
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJRealize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJLeonardo Balter
 
Spark IT 2011 - Developing RESTful Web services with JAX-RS
Spark IT 2011 - Developing RESTful Web services with JAX-RSSpark IT 2011 - Developing RESTful Web services with JAX-RS
Spark IT 2011 - Developing RESTful Web services with JAX-RSArun Gupta
 
a Running Tour of Cloud Foundry
a Running Tour of Cloud Foundrya Running Tour of Cloud Foundry
a Running Tour of Cloud FoundryJoshua Long
 
Professional Frontend Engineering
Professional Frontend EngineeringProfessional Frontend Engineering
Professional Frontend EngineeringNate Koechley
 
Using Web Standards to create Interactive Data Visualizations for the Web
Using Web Standards to create Interactive Data Visualizations for the WebUsing Web Standards to create Interactive Data Visualizations for the Web
Using Web Standards to create Interactive Data Visualizations for the Webphilogb
 
ClubAJAX Basics - Server Communication
ClubAJAX Basics - Server CommunicationClubAJAX Basics - Server Communication
ClubAJAX Basics - Server CommunicationMike Wilcox
 
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur! Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur! David Delabassee
 
Getting Started with WebSockets and Server-Sent Events
Getting Started with WebSockets and Server-Sent EventsGetting Started with WebSockets and Server-Sent Events
Getting Started with WebSockets and Server-Sent EventsArun Gupta
 
Web Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the futureWeb Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the futureToru Kawamura
 
Web Standards: Fueling Innovation [Web Design World Boston '08]
Web Standards: Fueling Innovation [Web Design World Boston '08]Web Standards: Fueling Innovation [Web Design World Boston '08]
Web Standards: Fueling Innovation [Web Design World Boston '08]Aaron Gustafson
 
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
Java EE 7 (Lyon JUG & Alpes JUG  - March 2014)Java EE 7 (Lyon JUG & Alpes JUG  - March 2014)
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)David Delabassee
 
Taiwan Web Standards Talk 2011
Taiwan Web Standards Talk 2011Taiwan Web Standards Talk 2011
Taiwan Web Standards Talk 2011Zi Bin Cheah
 
What's next for Java API for WebSocket (JSR 356)
What's next for Java API for WebSocket (JSR 356)What's next for Java API for WebSocket (JSR 356)
What's next for Java API for WebSocket (JSR 356)Pavel Bucek
 
2015 JavaOne EJB/CDI Alignment
2015 JavaOne EJB/CDI Alignment2015 JavaOne EJB/CDI Alignment
2015 JavaOne EJB/CDI AlignmentDavid Blevins
 

What's hot (19)

JAX-RS JavaOne Hyderabad, India 2011
JAX-RS JavaOne Hyderabad, India 2011JAX-RS JavaOne Hyderabad, India 2011
JAX-RS JavaOne Hyderabad, India 2011
 
Getting Started with WebSocket and Server-Sent Events in Java
Getting Started with WebSocket and Server-Sent Events in JavaGetting Started with WebSocket and Server-Sent Events in Java
Getting Started with WebSocket and Server-Sent Events in Java
 
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJRealize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
 
Spark IT 2011 - Developing RESTful Web services with JAX-RS
Spark IT 2011 - Developing RESTful Web services with JAX-RSSpark IT 2011 - Developing RESTful Web services with JAX-RS
Spark IT 2011 - Developing RESTful Web services with JAX-RS
 
Open Social Summit Korea
Open Social Summit KoreaOpen Social Summit Korea
Open Social Summit Korea
 
a Running Tour of Cloud Foundry
a Running Tour of Cloud Foundrya Running Tour of Cloud Foundry
a Running Tour of Cloud Foundry
 
Professional Frontend Engineering
Professional Frontend EngineeringProfessional Frontend Engineering
Professional Frontend Engineering
 
Using Web Standards to create Interactive Data Visualizations for the Web
Using Web Standards to create Interactive Data Visualizations for the WebUsing Web Standards to create Interactive Data Visualizations for the Web
Using Web Standards to create Interactive Data Visualizations for the Web
 
ClubAJAX Basics - Server Communication
ClubAJAX Basics - Server CommunicationClubAJAX Basics - Server Communication
ClubAJAX Basics - Server Communication
 
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur! Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
 
Require js training
Require js trainingRequire js training
Require js training
 
Getting Started with WebSockets and Server-Sent Events
Getting Started with WebSockets and Server-Sent EventsGetting Started with WebSockets and Server-Sent Events
Getting Started with WebSockets and Server-Sent Events
 
Web Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the futureWeb Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the future
 
Web Standards: Fueling Innovation [Web Design World Boston '08]
Web Standards: Fueling Innovation [Web Design World Boston '08]Web Standards: Fueling Innovation [Web Design World Boston '08]
Web Standards: Fueling Innovation [Web Design World Boston '08]
 
Edge of the Web
Edge of the WebEdge of the Web
Edge of the Web
 
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
Java EE 7 (Lyon JUG & Alpes JUG  - March 2014)Java EE 7 (Lyon JUG & Alpes JUG  - March 2014)
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
 
Taiwan Web Standards Talk 2011
Taiwan Web Standards Talk 2011Taiwan Web Standards Talk 2011
Taiwan Web Standards Talk 2011
 
What's next for Java API for WebSocket (JSR 356)
What's next for Java API for WebSocket (JSR 356)What's next for Java API for WebSocket (JSR 356)
What's next for Java API for WebSocket (JSR 356)
 
2015 JavaOne EJB/CDI Alignment
2015 JavaOne EJB/CDI Alignment2015 JavaOne EJB/CDI Alignment
2015 JavaOne EJB/CDI Alignment
 

Viewers also liked

concurrency gpars
concurrency gparsconcurrency gpars
concurrency gparsPaul King
 
Gpars concepts explained
Gpars concepts explainedGpars concepts explained
Gpars concepts explainedVaclav Pech
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More GroovyPaul King
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy PluginsPaul King
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Paul King
 

Viewers also liked (6)

concurrency gpars
concurrency gparsconcurrency gpars
concurrency gpars
 
Gpars concepts explained
Gpars concepts explainedGpars concepts explained
Gpars concepts explained
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More Groovy
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
 
GroovyDSLs
GroovyDSLsGroovyDSLs
GroovyDSLs
 

Similar to XML and Web Services with Groovy

RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009Roland Tritsch
 
XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>Arun Gupta
 
Django deployment with PaaS
Django deployment with PaaSDjango deployment with PaaS
Django deployment with PaaSAppsembler
 
New Features Coming in Browsers (RIT '09)
New Features Coming in Browsers (RIT '09)New Features Coming in Browsers (RIT '09)
New Features Coming in Browsers (RIT '09)jeresig
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy TutorialPaul King
 
.NET @ apache.org
 .NET @ apache.org .NET @ apache.org
.NET @ apache.orgTed Husted
 
NSA for Enterprises Log Analysis Use Cases
NSA for Enterprises   Log Analysis Use Cases NSA for Enterprises   Log Analysis Use Cases
NSA for Enterprises Log Analysis Use Cases WSO2
 
Event-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 EngineEvent-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 EngineRicardo Silva
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Enginecatherinewall
 
Introductiontoapachecamel 110131060022-phpapp01
Introductiontoapachecamel 110131060022-phpapp01Introductiontoapachecamel 110131060022-phpapp01
Introductiontoapachecamel 110131060022-phpapp01dheeraj kumar
 
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5Sadaaki HIRAI
 
What’s new in cas 4.2
What’s new in cas 4.2 What’s new in cas 4.2
What’s new in cas 4.2 Misagh Moayyed
 
Hammock, a Good Place to Rest
Hammock, a Good Place to RestHammock, a Good Place to Rest
Hammock, a Good Place to RestStratoscale
 
2013 05-multicloud-paas-interop-scenarios-fia-dublin
2013 05-multicloud-paas-interop-scenarios-fia-dublin2013 05-multicloud-paas-interop-scenarios-fia-dublin
2013 05-multicloud-paas-interop-scenarios-fia-dublinAlex Heneveld
 
Best Practices with WSO2 Developer Studio
Best Practices with WSO2 Developer Studio Best Practices with WSO2 Developer Studio
Best Practices with WSO2 Developer Studio WSO2
 
Groovy Power Features
Groovy Power FeaturesGroovy Power Features
Groovy Power FeaturesPaul King
 
Paulking groovy
Paulking groovyPaulking groovy
Paulking groovyd0nn9n
 

Similar to XML and Web Services with Groovy (20)

RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009
 
XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>
 
Django deployment with PaaS
Django deployment with PaaSDjango deployment with PaaS
Django deployment with PaaS
 
Spring.io
Spring.ioSpring.io
Spring.io
 
New Features Coming in Browsers (RIT '09)
New Features Coming in Browsers (RIT '09)New Features Coming in Browsers (RIT '09)
New Features Coming in Browsers (RIT '09)
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy Tutorial
 
.NET @ apache.org
 .NET @ apache.org .NET @ apache.org
.NET @ apache.org
 
NSA for Enterprises Log Analysis Use Cases
NSA for Enterprises   Log Analysis Use Cases NSA for Enterprises   Log Analysis Use Cases
NSA for Enterprises Log Analysis Use Cases
 
Event-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 EngineEvent-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 Engine
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
 
Introductiontoapachecamel 110131060022-phpapp01
Introductiontoapachecamel 110131060022-phpapp01Introductiontoapachecamel 110131060022-phpapp01
Introductiontoapachecamel 110131060022-phpapp01
 
Java Cloud and Container Ready
Java Cloud and Container ReadyJava Cloud and Container Ready
Java Cloud and Container Ready
 
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
 
What’s new in cas 4.2
What’s new in cas 4.2 What’s new in cas 4.2
What’s new in cas 4.2
 
Hammock, a Good Place to Rest
Hammock, a Good Place to RestHammock, a Good Place to Rest
Hammock, a Good Place to Rest
 
2013 05-multicloud-paas-interop-scenarios-fia-dublin
2013 05-multicloud-paas-interop-scenarios-fia-dublin2013 05-multicloud-paas-interop-scenarios-fia-dublin
2013 05-multicloud-paas-interop-scenarios-fia-dublin
 
How Akamai Made ESI Testing Simpler
How Akamai Made ESI Testing SimplerHow Akamai Made ESI Testing Simpler
How Akamai Made ESI Testing Simpler
 
Best Practices with WSO2 Developer Studio
Best Practices with WSO2 Developer Studio Best Practices with WSO2 Developer Studio
Best Practices with WSO2 Developer Studio
 
Groovy Power Features
Groovy Power FeaturesGroovy Power Features
Groovy Power Features
 
Paulking groovy
Paulking groovyPaulking groovy
Paulking groovy
 

More from Paul King

awesome groovy
awesome groovyawesome groovy
awesome groovyPaul King
 
groovy databases
groovy databasesgroovy databases
groovy databasesPaul King
 
groovy transforms
groovy transformsgroovy transforms
groovy transformsPaul King
 
tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovyPaul King
 
groovy rules
groovy rulesgroovy rules
groovy rulesPaul King
 
functional groovy
functional groovyfunctional groovy
functional groovyPaul King
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing GroovyPaul King
 
Agile Testing Practices
Agile Testing PracticesAgile Testing Practices
Agile Testing PracticesPaul King
 
groovy DSLs from beginner to expert
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expertPaul King
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrencyPaul King
 
Dynamic Language Practices
Dynamic Language PracticesDynamic Language Practices
Dynamic Language PracticesPaul King
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing GroovyPaul King
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009Paul King
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...Paul King
 

More from Paul King (15)

awesome groovy
awesome groovyawesome groovy
awesome groovy
 
groovy databases
groovy databasesgroovy databases
groovy databases
 
groovy transforms
groovy transformsgroovy transforms
groovy transforms
 
tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovy
 
groovy rules
groovy rulesgroovy rules
groovy rules
 
functional groovy
functional groovyfunctional groovy
functional groovy
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
 
Agile Testing Practices
Agile Testing PracticesAgile Testing Practices
Agile Testing Practices
 
groovy DSLs from beginner to expert
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expert
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrency
 
Dynamic Language Practices
Dynamic Language PracticesDynamic Language Practices
Dynamic Language Practices
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing Groovy
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
 

Recently uploaded

COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a WebsiteCOMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Websitedgelyza
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsSafe Software
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAshyamraj55
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...Aggregage
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdfPedro Manuel
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URLRuncy Oommen
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaborationbruanjhuli
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Brian Pichman
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxMatsuo Lab
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024D Cloud Solutions
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 

Recently uploaded (20)

COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a WebsiteCOMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Website
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
201610817 - edge part1
201610817 - edge part1201610817 - edge part1
201610817 - edge part1
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URL
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 

XML and Web Services with Groovy

  • 1. XML and Web Services with Groovy Dr Paul King, ASERT: @paulk_asert, paulk@asert.com.au SpringOne2GX - 1
  • 2. 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.” © ASERT 2006-2009 Groovy = Java – boiler plate code + optional dynamic typing + closures + domain specific languages + builders + metaprogramming SpringOne2GX - 2
  • 3. Growing Acceptance … A slow and steady start but now gaining in momentum, maturity and mindshare Now free
  • 4. … Growing Acceptance … © ASERT 2006-2009 SpringOne2gx_Oct2009 - 4
  • 5. … Growing Acceptance … © ASERT 2006-2009 Groovy and Grails downloads: 70-90K per month and growing SpringOne2gx_Oct2009 - 5
  • 6. … Growing Acceptance … © ASERT 2006-2009 Source: http://www.micropoll.com/akira/mpresult/501697-116746 Source: http://www.grailspodcast.com/ SpringOne2gx_Oct2009 - 6
  • 7. … Growing Acceptance … © ASERT 2006-2009 http://www.jroller.com/scolebourne/entry/devoxx_2008_whiteboard_votes http://www.java.net SpringOne2gx_Oct2009 - 7
  • 8. … Growing Acceptance … What alternative JVM language are you using or intending to use © ASERT 2006-2009 http://www.leonardoborges.com/writings SpringOne2gx_Oct2009 - 8
  • 9. … Growing Acceptance … © ASERT 2006-2009 http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo.com) SpringOne2gx_Oct2009 - 9
  • 10. … Growing Acceptance © ASERT 2006-2009 SpringOne2gx_Oct2009 - 10
  • 11. Better XML Manipulation... <records> records.xml <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> <record type='speed'>Production Pickup Truck with speed of 271kph</record> </car> © ASERT 2006-2009 <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> AUG 2009 - 11
  • 12. ...Better XML Manipulation... 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) { © ASERT 2006-2009 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(); } } } AUG 2009 - 12
  • 13. ...Better XML Manipulation... import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; boilerplate 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) { © ASERT 2006-2009 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(); } } } AUG 2009 - 13
  • 14. ...Better XML Manipulation def records = new XmlParser().parse("records.xml") records.car.each { © ASERT 2006-2009 println "year = ${it.@year}" } year = 2006 year = 1962 year = 1931 AUG 2009 - 14
  • 15. XML SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
  • 16. 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. © ASERT 2006-2009 • Creating XML – Special Groovy support: MarkupBuilder and StreamingMarkupBuilder – Or again, enhanced syntax for your current favorites SpringOne2GX - 16
  • 17. ... Groovy and XML ... • Updating XML – Using above: read followed by create – Can be done with XmlParser, XmlSlurper, DOMCategory – Or with your Java favorites © ASERT 2006-2009 • Verifying XML – Also DTD, W3C XML Schema, Relax NG in a similar fashion to Java mechanisms for these features SpringOne2GX - 17
  • 18. ... 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 © ASERT 2006-2009 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 SpringOne2GX - 18
  • 19. An Xml Example ... import groovy.xml.dom.DOMCategory class Flights { static final String XML = ''' <trip> <flight hours="13"> <from>Brisbane</from> © ASERT 2006-2009 <to>Los Angeles</to> </flight> <flight hours="4"> <from>Los Angeles</from> <to>New Orleans</to> </flight> </trip> ''' ... SpringOne2GX - 19
  • 20. ... An Xml Example ... static final Reader getReader() { new StringReader(XML) } static final Set getCities(flights) { Set cities = [] © ASERT 2006-2009 use(DOMCategory) { flights.each { f -> cities += f.to[0].text() cities += f.from[0].text() } } You can mostly ignore cities the details here for now. } We’ll cover DOMCategory } in more detail shortly. SpringOne2GX - 20
  • 21. 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() © ASERT 2006-2009 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 SpringOne2GX - 21
  • 22. XmlParser – Under the covers • For a JavaBean, this Groovy expression: trip.flight[0].to[0].text() • Is “roughly” converted to: trip.getflight().get(0).getTo().get(0).text() © ASERT 2006-2009 where getFlight() and getTo() return a List • But for XML Parser, it overrides this mechanism and “roughly” converts to: trip.getByName('flight').get(0). getByName('to').get(0).text() where getByName is a Groovy method similar to getElementsByTagName in org.w3c.dom.Element SpringOne2GX - 22
  • 23. XmlSlurper... • The same again using XmlSlurper – Mostly identical syntax and capabilities def trip = new XmlSlurper().parseText(Flights.XML) assert trip.flight[0].to.text() == 'Los Angeles' assert trip.flight[1].@hours == '4' © ASERT 2006-2009 Set cities = trip.flight.from*.text() + trip.flight.to*.text() assert cities == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set assert trip.flight.@hours.list() == ['13', '4'] assert trip.flight.@hours*.toInteger().sum() == 17 – But features lazy evaluation of expressions – Consider this for streaming scenarios SpringOne2GX - 23
  • 24. ...XmlSlurper... • What does Lazy mean? def trip = new XmlSlurper().parseText(Flights.XML) def moreThanFiveHours = { f -> f.@hours.toInteger() > 5 } def arrivingLax = { f -> f.to == 'Los Angeles' } def departingOz = { f -> f.from == 'Brisbane' } © ASERT 2006-2009 def longFlights = trip.flight.findAll(moreThanFiveHours) def longLaxFlights = longFlights.findAll(arrivingLax) def longOzLaxFlights = longLaxFlights.findAll(departingOz) assert longOzLaxFlights.@hours == '13' SpringOne2GX - 24
  • 25. ...XmlSlurper Light-weight scanning here def trip = new XmlSlurper().parseText(Flights.XML) def moreThanFiveHours = { f -> f.@hours.toInteger() > 5 } def arrivingLax = { f -> f.to == 'Los Angeles' } def departingOz = { f -> f.from == 'Brisbane' } © ASERT 2006-2009 def longFlights = trip.flight.findAll(moreThanFiveHours) def longLaxFlights = longFlights.findAll(arrivingLax) def longOzLaxFlights = longLaxFlights.findAll(departingOz) assert longOzLaxFlights.@hours == '13' Lazy expression storage Usage triggers evaluation but deferred evaluation • This may look puzzling at first – But the good news is you don’t normally haveSpringOne2GX - 25 to care
  • 26. A Namespace Example 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> © ASERT 2006-2009 <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> ''' ... SpringOne2GX - 26
  • 27. XmlParser and Namespaces • Recommended syntax: 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' © ASERT 2006-2009 • 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 directly def bibtermYear = new QName('http://www.book-stuff.com/terms/', 'year') assert b[bibtermYear].text() == '2007' // use QName with wildcards def anyYear = new QName('*', 'year') assert b[anyYear].text() == '2007' SpringOne2GX - 27
  • 28. XmlSlurper and Namespaces 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' © ASERT 2006-2009 assert b.'dc:title' == 'Groovy in Action' assert b.'bibterm:year' == '2007' SpringOne2GX - 28
  • 29. Other GPath Features • Similar syntax for XmlSlurper and DOMCategory 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() == © ASERT 2006-2009 ['trip', 'flight', 'flight', 'from', 'to', 'from', 'to'] assert trip.'**'.from*.text() == ['Brisbane', 'Los Angeles'] SpringOne2GX - 29
  • 30. 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') } © ASERT 2006-2009 data.each { println it } def neko = new SAXParser() // alternate style def page = new XmlSlurper(neko).parse('http://groovy.codehaus.org/') def data = page.depthFirst().grep{ it.name() == 'A' && it.@href.toString().endsWith('.html') }.'@href' 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 SpringOne2GX - 30
  • 31. Raw DOM import groovy.xml.DOMBuilder def trip = DOMBuilder.parse(Flights.reader).documentElement def flights = trip.getElementsByTagName('flight') def dest = flights.item(0).getElementsByTagName('to').item(0) © ASERT 2006-2009 assert dest.firstChild.nodeValue == 'Los Angeles' assert flights.item(1).getAttribute('hours') == '4' assert Flights.getCities(flights) == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set SpringOne2GX - 31
  • 32. DOM plus metaprogramming import groovy.xml.DOMBuilder import org.w3c.dom.Element def trip = DOMBuilder.parse(Flights.reader).documentElement Element.metaClass.element = { t, i -> © ASERT 2006-2009 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' SpringOne2GX - 32
  • 33. DOMCategory import groovy.xml.DOMBuilder import groovy.xml.dom.DOMCategory def doc = DOMBuilder.parse(Flights.reader) def trip = doc.documentElement © ASERT 2006-2009 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 } SpringOne2GX - 33
  • 34. DOM4J @Grab('dom4j:dom4j:1.6.1') import org.dom4j.io.SAXReader def trip = new SAXReader().read(Flights.reader).rootElement © ASERT 2006-2009 assert trip.elements()[0].elementText('to') == 'Los Angeles' assert trip.elements()[1].attributeValue('hours') == '4' SpringOne2GX - 34
  • 35. JDOM @Grab('org.jdom:jdom:1.1') import org.jdom.input.SAXBuilder def b = new SAXBuilder() def trip = b.build(Flights.reader).rootElement © ASERT 2006-2009 assert trip.children[0].getChildText('to') == 'Los Angeles' assert trip.children[1].getAttribute('hours').value == '4' SpringOne2GX - 35
  • 36. 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') © ASERT 2006-2009 assert to.value == 'Los Angeles' def hours = flights.get(1).getAttribute('hours') assert hours.value == '4' SpringOne2GX - 36
  • 37. StAX import static javax.xml.stream.XMLInputFactory.newInstance as staxFactory import javax.xml.stream.XMLStreamReader as StaxReader def flights = [] def flight def seenTag StaxReader.metaClass.attr = { s -> delegate.getAttributeValue(null, s) } def reader = staxFactory().createXMLStreamReader(Flights.reader) while (reader.hasNext()) { def name = reader.localName © ASERT 2006-2009 if (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 += flight seenTag = null } reader.next() } assert flights[0].to == 'Los Angeles' assert flights[1].hours == '4' SpringOne2GX - 37
  • 38. SAX import javax.xml.parsers.SAXParserFactory import 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 } © ASERT 2006-2009 public void endElement(String uri, String localName, String qName) { if (qName == 'flight') flights += flight seenTag = 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().xMLReader reader.setContentHandler(handler) reader.parse(new InputSource(Flights.reader)) assert handler.flights[0].to == 'Los Angeles' assert handler.flights[1].hours == '4' SpringOne2GX - 38
  • 39. XPath import javax.xml.xpath.* import groovy.xml.DOMBuilder def xpath = XPathFactory.newInstance().newXPath() def trip = DOMBuilder.parse(Flights.reader).documentElement assert xpath.evaluate('flight/to/text()', trip) == 'Los Angeles' assert xpath.evaluate('flight[2]/@hours', trip) == '4' © ASERT 2006-2009 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 SpringOne2GX - 39
  • 40. XPath with DOMCategory import groovy.xml.DOMBuilder import groovy.xml.dom.DOMCategory import static javax.xml.xpath.XPathConstants.* def trip = DOMBuilder.parse(Flight.reader).documentElement © ASERT 2006-2009 use (DOMCategory) { assert trip.xpath('flight/to/text()') == 'Los Angeles' assert trip.xpath('flight[2]/@hours', NUMBER) == 4 flights = trip.xpath('flight', NODESET) def hoursAsNum = { n -> n.xpath('@hours', NUMBER) } assert flights.collect(hoursAsNum).sum() == 17 } SpringOne2GX - 40
  • 41. 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() == © ASERT 2006-2009 '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 SpringOne2GX - 41
  • 42. Jaxen XPath @Grab('jaxen#jaxen;1.1.1') import org.jaxen.dom.DOMXPath import groovy.xml.DOMBuilder def trip = DOMBuilder.parse(Flights.reader).documentElement assert new DOMXPath('flight/to/text()'). stringValueOf(trip) == 'Los Angeles' © ASERT 2006-2009 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 SpringOne2GX - 42
  • 43. JSR 225 - XQJ import net.sf.saxon.xqj.SaxonXQDataSource import javax.xml.xquery.XQSequence XQSequence.metaClass.collect = { Closure c -> def items = [] while (delegate.next()) items += c(delegate) items } def asString = { seq -> seq.getItemAsString(null) } © ASERT 2006-2009 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 SpringOne2GX - 43
  • 44. XSLT... import static javax.xml.transform.TransformerFactory.newInstance as xsltFactory import 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> © ASERT 2006-2009 </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)) SpringOne2GX - 44
  • 45. ...XSLT import static javax.xml.transform.TransformerFactory.newInstance as xsltFactory import javax.xml.transform.stream.* def xslt = ''' <html> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/trip"> <body> <html> <h1>Flights</h1> <body> <ul> <h1>Flights</h1> <li>Brisbane =&gt; Los Angeles</li> <ul> <li>Los Angeles =&gt; New Orleans</li> </ul> <xsl:apply-templates select="flight"/> </ul> </body> © ASERT 2006-2009 </body> </html> </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)) SpringOne2GX - 45
  • 46. MarkupBuilder import groovy.xml.MarkupBuilder def writer = new StringWriter() def xml = new MarkupBuilder(writer) xml.flights { flight(hours:13) { © ASERT 2006-2009 from('Brisbane') to('Los Angeles') } flight(hours:4) { from('Los Angeles') to('New Orleans') } } println writer SpringOne2GX - 46
  • 47. StreamingMarkupBuilder import groovy.xml.StreamingMarkupBuilder def writer = new StreamingMarkupBuilder().bind { flights { flight(hours: 13) { from('Brisbane') © ASERT 2006-2009 to('Los Angeles') } flight(hours: 4) { from('Los Angeles') to('New Orleans') } } } println writer SpringOne2GX - 47
  • 48. DOMBuilder import groovy.xml.* def builder = DOMBuilder.newInstance() def root = builder.flights { flight(hours: 13) { from('Brisbane') © ASERT 2006-2009 to('Los Angeles') } flight(hours: 4) { from('Los Angeles') to('New Orleans') } } new XmlNodePrinter().print(root) SpringOne2GX - 48
  • 49. 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- © ASERT 2006-2009 ns#") { 'bibterm:book' { 'dc:title'('Groovy in Action') 'bibterm:year'('2007') } <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/' } xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' println writer 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> SpringOne2GX - 49
  • 50. 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' { © ASERT 2006-2009 'bibterm:book' { 'dc:title'('Groovy in Action') 'bibterm:year'('2007') } } <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' }, System.out) 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> SpringOne2GX - 50
  • 51. 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') © ASERT 2006-2009 'bibterm:year'('2007') } } new XmlNodePrinter().print(root) <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> SpringOne2GX - 51
  • 52. 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') © ASERT 2006-2009 'bibterm:year'('2007') } } new XmlNodePrinter().print(root) <?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> SpringOne2GX - 52
  • 53. StaxBuilder import javax.xml.stream.XMLOutputFactory import groovy.xml.StaxBuilder def factory = XMLOutputFactory.newInstance() def writer = new StringWriter() def xmlwriter = factory.createXMLStreamWriter(writer) def builder = new StaxBuilder(xmlwriter) builder.flights { © ASERT 2006-2009 flight(hours: 13) { from('Brisbane') to('Los Angeles') } flight(hours: 4) { from('Los Angeles') to('New Orleans') } } println writer SpringOne2GX - 53
  • 54. 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) © ASERT 2006-2009 builder.flights { flight(hours: 13) { from('Brisbane') {"flights":{"flight":[ to('Los Angeles') { "@hours":"13", } "from":"Brisbane", flight(hours: 4) { "to":"Los Angeles" }, from('Los Angeles') { "@hours":"4", to('New Orleans') "from":"Los Angeles", } "to":"New Orleans" } } ]}} println writer SpringOne2GX - 54
  • 55. Updating XML <shopping> <shopping> <category type="groceries"> <category type="groceries"> <item>Luxury Chocolate</item> <item>Chocolate</item> <item>Luxury Coffee</item> <item>Coffee</item> </category> </category> <category type="supplies"> <category type="supplies"> <item>Paper</item> <item>Paper</item> <item quantity="6" © ASERT 2006-2009 <item quantity="4">Pens</item> when="Urgent">Pens</item> </category> </category> <category type="present"> <category type="present"> <item when="Aug 10"> <item>Mum's Birthday</item> Kathryn's Birthday <item when="Oct 15"> </item> Monica's Birthday </category> </item> </shopping> </category> </shopping> SpringOne2GX - 55
  • 56. Updating with XmlParser ... def root = new XmlParser().parseText(Shopping.XML) // modify groceries: luxury items please root.category.find{ it.@type == 'groceries' }.item.each{ g -> g.value = 'Luxury ' + g.text() } // modify supplies: we need extra pens now root.category.find{ © ASERT 2006-2009 it.@type == 'supplies' }.item.findAll{ it.text() == 'Pens' }.each{ p -> p.@quantity = p.@quantity.toInteger() + 2 p.@when = 'Urgent' } // modify presents: August has come and gone def 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") ... SpringOne2GX - 56
  • 57. Updating with XmlSlurper ... // modify groceries: luxury items please def 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 now root.category.find{ it.@type == 'supplies' © ASERT 2006-2009 }.item.findAll{ it.text() == 'Pens' }.each { p -> p.@quantity = (p.@quantity.toInteger() + 2).toString() p.@when = 'Urgent' } // modify presents: August has come and gone root.category.find{ it.@type == 'present' }.replaceNode{ node -> category(type:'present'){ item("Mum's Birthday") item("Monica's Birthday", when:'Oct 15') } } ... SpringOne2GX - 57
  • 58. Updating with DOMCategory use(DOMCategory) { // modify groceries: luxury items please def groceries = root.category.find{ it.'@type' == 'groceries' }.item groceries.each { g -> g.value = 'Luxury ' + g.text() } // modify supplies: we need extra pens now def supplies = root.category.find{ it.'@type' == 'supplies' }.item supplies.findAll{ it.text() == 'Pens' }.each { p -> © ASERT 2006-2009 p['@quantity'] = p.'@quantity'.toInteger() + 2 p['@when'] = 'Urgent' } // modify presents: August has come and gone def 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") ... } SpringOne2GX - 58
  • 59. Validating against a DTD... def xml = ''' <!DOCTYPE records [ <!ELEMENT car (country,record)> <!ATTLIST car make NMTOKEN #REQUIRED name CDATA #REQUIRED year NMTOKEN #REQUIRED > <!ELEMENT country (#PCDATA)> <!ELEMENT record (#PCDATA)> © ASERT 2006-2009 <!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() SpringOne2GX - 59
  • 60. ...Validating against a DTD def validating = true def namespaceAware = false new XmlParser(validating, namespaceAware).parseText(xml) © ASERT 2006-2009 new XmlSlurper(validating, namespaceAware).parseText(xml) import groovy.xml.DOMBuilder DOMBuilder.parse(new StringReader(xml), validating, namespaceAware) SpringOne2GX - 60
  • 61. 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> © ASERT 2006-2009 <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() SpringOne2GX - 61
  • 62. ...Validating against a W3C Schema import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI import javax.xml.transform.stream.StreamSource import javax.xml.validation.SchemaFactory def factory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI) // println factory.isSchemaLanguageSupported(W3C_XML_SCHEMA_NS_URI) © ASERT 2006-2009 def schema = factory.newSchema(new StreamSource(new StringReader(xsd))) def validator = schema.newValidator() validator.validate( new StreamSource(new StringReader(XmlExamples.CAR_RECORDS))) SpringOne2GX - 62
  • 63. 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> <define name="record"> <attribute name="name"> © ASERT 2006-2009 <element name="record"> <text/> <attribute name="type"> </attribute> <data type="token"/> <attribute name="year"> </attribute> <data type="integer"/> <text/> </attribute> </element> <ref name="country"/> </define> <ref name="record"/> <define name="records"> </element> <element name="records"> </define> <oneOrMore> <define name="country"> <ref name="car"/> <element name="country"> </oneOrMore> <text/> </element> </element> </define> </define> </grammar> ... '''.trim() SpringOne2GX - 63
  • 64. ...Validating against a RelaxNG Schema // require isorelax.jar, isorelax-jaxp-bridge.jar // require one of Jing, MSV, ... import static javax.xml.XMLConstants.RELAXNG_NS_URI import javax.xml.transform.stream.StreamSource import javax.xml.validation.SchemaFactory def factory = SchemaFactory.newInstance(RELAXNG_NS_URI) © ASERT 2006-2009 def schema = factory.newSchema(new StreamSource(new StringReader(rng))) def validator = schema.newValidator() validator.validate(new StreamSource(new StringReader(CAR_RECORDS))) SpringOne2GX - 64
  • 65. WEB SERVICES SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
  • 66. 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 © ASERT 2006-2009 • RESTful Options – Restlet.org, RESTlet DSL, roll your own – JAX-RS: Jersey, CXF, JBoss RESTeasy • Frameworks layered upon SOA – Synapse, Tuscany, ServiceMix SpringOne2GX - 66
  • 67. GroovySOAP class MathService { • XFire based double add(double a, double b) { a + b • Java 1.4 } double square(double c) { c * c } } import groovy.net.soap.SoapServer © ASERT 2006-2009 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.0 assert math.square(3.0) == 9.0 SpringOne2GX - 67
  • 68. GroovyWS class MathService { • CXF based double add(double a, double b) { a + b • Java 1.5+ } double square(double c) { c * c } } import groovyx.net.ws.WSServer © ASERT 2006-2009 def server = new WSServer() server.setNode MathService.name, "http://localhost:6980/MathService" import groovyx.net.ws.WSClient def 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.0d result = proxy.square(3.0d) assert result == 9.0d SpringOne2GX - 68
  • 69. JAXB Server import javax.xml.ws.Endpoint import javax.jws.WebService import javax.jws.soap.SOAPBinding import javax.jws.WebMethod @WebService(name="Echo", serviceName="EchoService", targetNamespace="http://jaxws.asert.com") @SOAPBinding(style=SOAPBinding.Style.RPC) © ASERT 2006-2009 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 ...' SpringOne2GX - 69
  • 70. JAXB Client • JAXB Client import javax.xml.namespace.QName import 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).echoPort © ASERT 2006-2009 println echoServer.echo("Today is ${new Date()}") • Build instructions wsimport -d ../build -p com.asert.jaxws http://localhost:8080/Echo?wsdl SpringOne2GX - 70
  • 71. 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 © ASERT 2006-2009 some special things you can do with Groovy SpringOne2GX - 71
  • 72. 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: © ASERT 2006-2009 – http://www.developer.com/services/article.ph p/10928_3570031_2 SpringOne2GX - 72
  • 73. RESTful options • Several Options – Already supported in discussed frameworks, e.g. CXF – Groovy Restlet DSL http://docs.codehaus.org/display/GROOVY/GroovyRestlet – Jersey © ASERT 2006-2009 http://wikis.sun.com/display/Jersey/Main – restlet.org http://www.restlet.org SpringOne2GX - 73
  • 74. restlet.org import 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) © ASERT 2006-2009 break case Method.POST: handlePost(request, response) break default: // The request method is not allowed; set an error status response.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) } // ... SpringOne2GX - 74
  • 75. GroovyRestlet DSL builder.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) © ASERT 2006-2009 }) 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.attributes def 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 SpringOne2GX - 75
  • 76. Jersey... package com.asert import javax.ws.rs.GET import javax.ws.rs.Path import javax.ws.rs.Produces import static com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory.* @Path ("/helloworld") class HelloWorldResource { @GET @Produces("text/plain") © ASERT 2006-2009 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.wadl App available at ${baseUri}helloworld """ create(baseUri, initParams) SpringOne2GX - 76
  • 77. ...Jersey... import javax.ws.rs.PathParam import javax.xml.bind.annotation.* class PrettyXml { static print(node) { def writer = new StringWriter() new XmlNodePrinter(new PrintWriter(writer)).print(node) writer.toString() } } © ASERT 2006-2009 @XmlRootElement @XmlAccessorType (XmlAccessType.FIELD) class FlightInfoBean { @XmlAttribute String hours @XmlElement String from, to static 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()) } } SpringOne2GX - 77
  • 78. ...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}") © ASERT 2006-2009 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) } } SpringOne2GX - 78
  • 79. Jersey output > curl http://localhost:9998/helloworld Hello World > curl http://localhost:9998/flight/xml/1 <flight hours="4"> <from> Los Angeles </from> <to> New Orleans © ASERT 2006-2009 </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
  • 80. 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/ © ASERT 2006-2009 trunk/java/src/site/resources/presentations/ makingsoagroovyfremantle.pdf SpringOne2GX - 80
  • 81. 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 © ASERT 2006-2009 – You can use legacy ScriptComponent and GroovyComponent – You can write Groovy JBI components SpringOne2GX - 81
  • 82. 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.” © ASERT 2006-2009 – You can define your services using Groovy either using Java mechanisms or Scripting integration SpringOne2GX - 82
  • 83. ...Tuscany... <composite ...> <component name="CalculatorServiceComponent" .../> <component name="AddServiceComponent" .../> <component name="SubtractServiceComponent"> <tuscany:implementation.java class="calculator.SubtractServiceImpl"/> </component> <component name="MultiplyServiceComponent"> © ASERT 2006-2009 <tuscany:implementation.script language="groovy"> def multiply(n1, n2) { using groovyc Compile your Groovy } (with*or without annotations) then n1 n2 </tuscany:implementation.script> Need treat just like normal Java. </component> groovy jar in your runtime classpath. <component name="DivideServiceComponent"> <tuscany:implementation.script script="calculator/DivideServiceImpl.groovy"/> </component> </composite> SpringOne2GX - 83
  • 84. ...Tuscany <composite ...> With Groovy scripts either <component name="CalculatorServiceComponent" .../> <component name="AddServiceComponent" .../> files – no embedded or in <component name="SubtractServiceComponent"> compilation necessary. <tuscany:implementation.java class="calculator.SubtractServiceImpl"/> </component> <component name="MultiplyServiceComponent"> © ASERT 2006-2009 <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> SpringOne2GX - 84
  • 85. 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 – user@groovy.codehaus.org © ASERT 2006-2009 • 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 ... SpringOne2GX - 85
  • 86. More Information: Groovy in Action © ASERT 2006-2009 SpringOne2GX - 86