
- •Credits
- •About the Authors
- •About the Reviewers
- •www.PacktPub.com
- •Table of Contents
- •Preface
- •Introduction
- •Installing Groovy on Windows
- •Installing Groovy on Linux and OS X
- •Executing Groovy code from the command line
- •Using Groovy as a command-line text file editor
- •Running Groovy with invokedynamic support
- •Building Groovy from source
- •Managing multiple Groovy installations on Linux
- •Using groovysh to try out Groovy commands
- •Starting groovyConsole to execute Groovy snippets
- •Configuring Groovy in Eclipse
- •Configuring Groovy in IntelliJ IDEA
- •Introduction
- •Using Java classes from Groovy
- •Embedding Groovy into Java
- •Compiling Groovy code
- •Generating documentation for Groovy code
- •Introduction
- •Searching strings with regular expressions
- •Writing less verbose Java Beans with Groovy Beans
- •Inheriting constructors in Groovy classes
- •Defining code as data in Groovy
- •Defining data structures as code in Groovy
- •Implementing multiple inheritance in Groovy
- •Defining type-checking rules for dynamic code
- •Adding automatic logging to Groovy classes
- •Introduction
- •Reading from a file
- •Reading a text file line by line
- •Processing every word in a text file
- •Writing to a file
- •Replacing tabs with spaces in a text file
- •Deleting a file or directory
- •Walking through a directory recursively
- •Searching for files
- •Changing file attributes on Windows
- •Reading data from a ZIP file
- •Reading an Excel file
- •Extracting data from a PDF
- •Introduction
- •Reading XML using XmlSlurper
- •Reading XML using XmlParser
- •Reading XML content with namespaces
- •Searching in XML with GPath
- •Searching in XML with XPath
- •Constructing XML content
- •Modifying XML content
- •Sorting XML nodes
- •Serializing Groovy Beans to XML
- •Introduction
- •Parsing JSON messages with JsonSlurper
- •Constructing JSON messages with JsonBuilder
- •Modifying JSON messages
- •Validating JSON messages
- •Converting JSON message to XML
- •Converting JSON message to Groovy Bean
- •Using JSON to configure your scripts
- •Introduction
- •Creating a database table
- •Connecting to an SQL database
- •Modifying data in an SQL database
- •Calling a stored procedure
- •Reading BLOB/CLOB from a database
- •Building a simple ORM framework
- •Using Groovy to access Redis
- •Using Groovy to access MongoDB
- •Using Groovy to access Apache Cassandra
- •Introduction
- •Downloading content from the Internet
- •Executing an HTTP GET request
- •Executing an HTTP POST request
- •Constructing and modifying complex URLs
- •Issuing a REST request and parsing a response
- •Issuing a SOAP request and parsing a response
- •Consuming RSS and Atom feeds
- •Using basic authentication for web service security
- •Using OAuth for web service security
- •Introduction
- •Querying methods and properties
- •Dynamically extending classes with new methods
- •Overriding methods dynamically
- •Adding performance logging to methods
- •Adding transparent imports to a script
- •DSL for executing commands over SSH
- •DSL for generating reports from logfiles
- •Introduction
- •Processing collections concurrently
- •Downloading files concurrently
- •Splitting a large task into smaller parallel jobs
- •Running tasks in parallel and asynchronously
- •Using actors to build message-based concurrency
- •Using STM to atomically update fields
- •Using dataflow variables for lazy evaluation
- •Index

Chapter 7
14,
'50 Superfoods Recipes', 'Rebecca Fallon',
2012)
...
}
The previous example shows withBatch used with a batch size value of 20. For each 20 INSERTs, the JDBC's executeBatch will be automatically called. Also in this case, the withBatch operation works only if the database driver supports it.
See also
ff http://groovy.codehaus.org/api/groovy/sql/Sql.html
Calling a stored procedure
Stored procedure implementation in most SQL database servers is vendor-specific. JDBC offers a generic way for calling those and Groovy's Sql class helps to simplify that task.
This recipe will demonstrate how to utilize the Sql class to make stored procedure calls.
Getting ready
Let's use the same cookbook database, created and populated, like in the Querying an SQL database recipe:
import static DBUtil.* import groovy.sql.Sql
def server = startServer() createSchema()
populate()
Let's also assume we have defined a stored procedure with the following structure:
CREATE PROCEDURE INGREDIENT_USAGE(
OUT INGREDIENTS_RATE INTEGER,
IN INGREDIENT_NAME VARCHAR(100))
READS SQL DATA
BEGIN ATOMIC
SELECT COUNT(*)
239
www.it-ebooks.info

Working with Databases in Groovy
INTO INGREDIENTS_RATE
FROM INGREDIENT
WHERE NAME LIKE '%' || INGREDIENT_NAME || '%';
END
The INGREDIENT_USAGE procedure declares one IN parameter and one OUT parameter. The input parameter determines what kind of ingredient we are searching for, and the output parameter returns the number of times that ingredient appears in our recipes.
You can use the same approach we used for other DDL statements in the Creating a database table recipe to append a new stored procedure definition to the database schema.
How to do it...
The following simple steps demonstrate how we can accomplish our recipe's goal:
1.In order to call a stored procedure you need to create a list of parameter types and values first:
def params = [ Sql.INTEGER, 'sugar' ]
2.Then by using the call method and JDBC syntax we can invoke the desired procedure in the database:
def sql = Sql.newInstance(dbSettings) sql.call(
'{ CALL INGREDIENT_USAGE(:rate, :pattern) }', params) { rate ->
println "Sugar usage: $rate"
}
3.The script should print something similar to:
Sugar usage: 2
How it works...
We have specified two values in the list passed to the call method. The first value is the type of the OUT parameter that we expect to receive, and the second one is the value for the IN parameter that we pass to the procedure. Sql.DOUBLE is a constant (of groovy.sql. OutParameter type) defined in the groovy.sql.Sql class. There is a constant for every standard JDBC type.
OUT parameter values received back from the procedure are passed to the closure given to the call method as a second parameter. Inside that closure, you are free to manipulate received values, for example, by printing them.
240
www.it-ebooks.info

Chapter 7
There's more...
If a stored procedure contains several OUT, IN, or even INOUT parameters, then invoking that does not look much more complex. Let's assume we have the following stored procedure signature:
CREATE PROCEDURE INGREDIENT_USAGE2( IN COOKBOOK_ID INTEGER,
OUT INGREDIENTS_RATE INTEGER, INOUT INGREDIENT_NAME VARCHAR(100))
READS SQL DATA BEGIN ATOMIC
...
END
Calling that procedure will look as follows:
def params = [1, Sql.INTEGER, Sql.inout(Sql.VARCHAR('sugar'))]
sql.call(
'{ CALL INGREDIENT_USAGE2(:cookbook_id, :rate, :pattern)}', params) { rate, pattern ->
println rate println pattern
}
The difference from our original snippet is that we pass the INOUT parameter with the help of the Sql.inout(Sql.VARCHAR('sugar')) construct and that final closure runs over two output parameters, rate and pattern.
See also
ff Creating a database table ff Querying an SQL database
ff http://docs.oracle.com/javase/tutorial/jdbc/basics/ storedprocedures.html
ff http://groovy.codehaus.org/api/groovy/sql/Sql.html
ff http://groovy.codehaus.org/api/groovy/sql/InParameter.html ff http://groovy.codehaus.org/api/groovy/sql/OutParameter.html
ff http://groovy.codehaus.org/api/groovy/sql/InOutParameter.html
241
www.it-ebooks.info

Working with Databases in Groovy
Reading BLOB/CLOB from a database
Large binary object types are meant to store data, which is otherwise not splittable into relational tables and columns, or which is easier to store in a binary form for applicationspecific or performance needs. Groovy does not offer any special methods for handling SQL's large binary objects, but, on the other hand, this recipe will show how to apply Groovy's I/O API extensions to make the code more readable.
Getting ready
Let's again use the database model we created in the Creating a database table recipe. In the RECIPE table, we have the DESCRIPTION column of CLOB type and the IMAGE column of BLOB type.
How to do it...
To read the data, we can just use the same query methods we used in the Querying an SQL database recipe:
sql.eachRow('SELECT * FROM RECIPE') { recipe ->
println recipe.description.characterStream.text
def recipeImage = new File("recipe-${recipe.id}.jpg") recipeImage.delete()
recipeImage << recipe.image.binaryStream
}
How it works...
The types of recipe.description and recipe.image fields are java.jdbc.Clob and java.jdbc.Blob respectively. Those are standard JDBC types used to handle large binary data. By using instances of those types, you can create an InputStream to get the actual data from the database. And that's what happens in the previous code snippet. The only difference between the fields is that they serve different stream types. We just make use
of Clob.getCharacterStream and Blob.getBinaryStream methods.
Thanks to the Groovy extensions of standard Java API, we can transform an InputStream directly into String with the help of the getText method (or simply text). We can as well send another stream directly to a file with the help of the leftShift method
(or simply << operator) available in java.io.File extension.
242
www.it-ebooks.info

Chapter 7
There's more...
You can also write BLOB/CLOB data into the database with simple insert statements. Let's assume we have the following recipe information stored in a Map:
def recipe = [
id: 1000, chapter_id: 100, title: 'steak indian-style', description: '''\
TO START Get all your ingredients and equipment ready. Put a griddle pan on a high heat...
''',
image: Sql.BLOB(new File('steak.jpg').bytes)
]
As you can see we defined the CLOB data of description field as simple string and wrapped the binary image file data into a groovy.sql.InParameter instance with the help of Sql. BLOB method. Now you can just call the execute method to insert data as we did in the
Modifying data in an SQL database recipe:
sql.execute(
'INSERT INTO RECIPE ' +
'VALUES(:id, :chapter_id, :title, :description, :image)', recipe
)
It is important to consider if the data persisted using a BLOB is small enough to comply
with your memory usage requirements. If the size of the BLOB is large then you risk getting a dreaded OutOfMemoryException. To avoid any memory related issue, you have to use plain old JDBC API and stream data into the database.
Also, if CLOB/BLOB support in your database driver is not optimal you need to consider using native support. For example, the Oracle JDBC driver is widely known to require handling of BLOB/CLOB in a native way that is bypassing generic JDBC classes and interfaces, using classes of your driver implementation directly.
See also
ff Creating a database table ff Querying an SQL database
ff http://docs.oracle.com/javase/6/docs/api/java/sql/Blob.html ff http://docs.oracle.com/javase/6/docs/api/java/sql/Clob.html ff http://groovy.codehaus.org/groovy-jdk/java/io/File.html
ff http://groovy.codehaus.org/groovy-jdk/java/io/InputStream.html
243
www.it-ebooks.info