Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kenneth A. Kousen - Making Java Groovy - 2014.pdf
Скачиваний:
50
Добавлен:
19.03.2016
Размер:
15.36 Mб
Скачать

42

CHAPTER 2 Groovy by example

assert stadium.longitude > -123 && stadium.longitude < -71

}

}

@Test

void testGetGame() {

GameResult gr = ggd.getGame 'bos','col','1' assert 'Boston Red Sox' == gr.away

assert 'Colorado Rockies' == gr.home assert 4 == gr.aScore.toInteger() assert 3 == gr.hScore.toInteger()

}

}

Check the World Series game

This is a standard JUnit 4 test case. I have much more to say about Groovy testing capabilities in chapter 6 on testing, but here’s a simple example. There’s nothing inherently Groovy about this class except that (1) I used the map-based constructor to instantiate the fixture, (2) optional parentheses were left out wherever possible, and

(3) no explicit public or private keywords were needed. Otherwise, this is just a regular test case, and it works as usual.

What have I discussed in this section?

Groovy has a convenient syntax for maps.

XML parsing and extracting data are easy, as in the previous section.

Groovy has a slashy syntax for regular expressions.

Groovy classes work with JUnit tests.

There’s one final piece of the puzzle needed, which is the driver used to call the system for each date. I use a “groovlet” for this purpose in the next section.

2.3.3HTML builders and groovlets

The classes used so far access XML box score information and convert it into a series of game result objects. For the view layer, however, I need objects in a form that can be processed by JavaScript. There are several ways to accomplish this, but one of them is to use an XML builder to write out the information in XML form.11

GENERATING XML

The standard Groovy library includes a class called groovy.xml.MarkupBuilder,12 which is one of several builders (much like the SwingBuilder shown at the beginning of this chapter) in the standard library. Each of the builders intercepts method calls that don’t exist (so-called pretended methods) and constructs nodes out of them to make a tree structure. The tree is then exported appropriately for that kind of builder.

This is actually easier to see than to explain. Consider the GameResult class from the previous section, which held the home and away team names and scores and a reference to a Stadium object. Here’s the syntax for creating XML out of that object:

11The data could just as easily be written in JSON format. Other JSON examples are used throughout the book.

12I would bet that if this class were created today, it would be called XmlBuilder instead.

www.it-ebooks.info

Groovy Baseball

43

MarkupBuilder builder = new MarkupBuilder() builder.games {

results.each { g -> game(

outcome:"$g.away $g.aScore, $g.home $g.hScore", lat:g.stadium.latitude,

lng:g.stadium.longitude

)

}

}

After instantiating the MarkupBuilder and calling the reference builder, the second line invokes the games method on it. It may not look like a method, but recall that in Groovy, if a closure is the last argument to a method it can be placed outside the parentheses, and here I’m using optional parentheses. Of course, there’s no method called games in MarkupBuilder. That makes it a pretended method, and the builder intercepts that method call and creates a node out of it. In a MarkupBuilder that means it will ultimately create an XML element called games. The closure syntax implies that the next elements will be child elements of games.

Inside the closure the code iterates over each contained result, assigning it to the dummy variable g. For each GameResult g, the builder creates an element called game. The parentheses on game imply that game will contain attributes. In this case, each game has an outcome, a lat, and a lng.

Here’s the output of the MarkupBuilder:

<games>

<game outcome='Boston Red Sox 4, Colorado Rockies 3' lat='39.7564956' lng='-104.9940163' />

</games>

If there had been a dozen games that day there would a <game> element for each one of them. The bottom line is that in Groovy, generating XML is about as easy as parsing it.

SERVER-SIDE PROCESSING WITH GROOVLETS

To drive the whole system I need a server-side component that receives the needed date and calls the GetGameData class to retrieve the games, which are then returned in XML form. Groovy has a component known as a groovlet to make that all easy.

A groovlet is a script that is executed by a class called groovy.servlet.GroovyServlet. This class is part of the Groovy standard library. Like any servlet, it needs to be declared in the web.xml deployment descriptor for a web application and mapped to a particular URL pattern. In this case I chose the pattern *.groovy. Here’s the excerpt from the deployment descriptor:

<servlet> <servlet-name>GroovyServlet</servlet-name>

<servlet-class>groovy.servlet.GroovyServlet</servlet-class> </servlet>

www.it-ebooks.info

44

CHAPTER 2 Groovy by example

<servlet-mapping> <servlet-name>GroovyServlet</servlet-name> <url-pattern>*.groovy</url-pattern>

</servlet-mapping>

The Groovy Baseball application will therefore send all URLs ending in .groovy through the GroovyServlet, which will execute them. Groovlets executed this way are deployed as source code rather than as compiled classes under WEB-INF.13 Groovlets also contain a set of implicit objects representing the request, response, input parameters, and more.

The following listing contains the complete content of the groovlet that drives the Groovy Baseball system.

Listing 2.10 GameServlet.groovy: a groovlet for Groovy Baseball

import beans.GameResult; import beans.Stadium; import service.GetGameData;

response.contentType = 'text/xml' def month = params.month

def day = params.day def year = params.year

Set the content type of the response

Extract input parameters

m = month.toInteger() < 10 ? '0' + month : month d = day.toInteger() < 10 ? '0' + day : day

y = year.toInteger() + ''

ggd = new GetGameData(month:m,day:d,year:y) results = ggd.games

Retrieve games for that date

html.games {

 

Use a builder to

 

results.each { g ->

generate XML

game(

 

outcome:"$g.away $g.aScore, $g.home $g.hScore", lat:g.stadium.latitude,

lng:g.stadium.longitude

)

}

}

The groovlet can set response headers, here setting the output to XML. Input parameters populate a map of strings called params, which can be accessed in the usual way. The URL requires two-digit days and two-digit months, so a zero is prepended when necessary. After retrieving the games for that date the output is generated using the implicit MarkupBuilder. There’s no need to instantiate a MarkupBuilder in this case, because groovlets already contain one, called html.

The groovlet is called from a regular web page, using a URL of the form http://.../ groovybaseball/GroovyService.groovy?month=10&day=28&year=2007. The XML data is written to the output stream, which can then be processed by JavaScript.

13 The details are discussed in chapter 10 on web applications.

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]