Broadcast on Broadcast off
The Documentation for Project Zero has moved. Please update your bookmarks to: http://www.projectzero.org/documentation/
Table of
Contents...
Hide

Project Zero Developer’s Guide

Concepts and components
Basic concepts overview
Event processing
Writing Java handlers
Writing Groovy handlers
Firing events
Global Context
Global Context reference
Application directory layout
Virtualized directories
Assemble
PHP
Features and configuration
Configuration
Debugging
Dependencies
Packaging
Application classpath
Logging and tracing
RESTful resources
RESTful documentation
File serving
Response rendering
Validators and validation
HTTP error handling
Calling a remote resource
Using the Connection API
Sending an email using EmailConnection
Configuring destinations
Configuring protocols
Configuring connection handlers
Creating a connection handler
Creating a custom protocol transport
Simple logging connection handlers
Protocol reference
Client programming with Dojo
Runtime options
Deployment modifications
HTTP configuration
SSL configuration
Proxy configuration
Extending the CLI
Security considerations
Authentication
OpenID authentication
Extending security
Security tokens
CSRF prevention support
Extending token support
Leveraging TAI
User service
File based user service
LDAP user service
Extending user service
Security Utilities
Leveraging XOREncoder
Extensions
Atom support
RSS support
JSON support
XMLEncoder
REST to SOAP extension
URIUtils
Developer Web tools
Database setup tools
Configuring data access
Common query patterns
Advanced query patterns
Update patterns
Local database transactions
Extending data access
Configuration vendor differences
PHP data access
Resource model
Configuring ZRM
Resource model declaration
Programmatic model API
HTTP REST API
A ZRM mini tutorial
Active content filtering support
Default filters
Custom filters
Runtime management
Management commands
Zero socket opener
Other extension modules
Amazon E-commerce service
Flickr service
WeatherZero forecast service
Wikipedia service
Reference
Zero command line interface
JavaDoc - Public API
JavaDoc - Public SPI
JavaDoc - All Classes

 

Writing Groovy handlers

Groovy can be used to implement handlers within Zero applications. The following sections of this article provide information about writing Groovy handlers.

Configuration

Groovy scripts and templates are generally used without explicit configuration in zero.config. For example, these files are generally served from the public folder, processed as resource handlers, and used as renderers. Such usage just requires that the file be placed in the appropriate directories.

For those advanced cases where you want to register a Groovy script or template as an event handler in zero.config (e.g. if you want to use a Groovy script to implement a start event handler), see the configuration guide for details.

Groovy scripts and classes

Groovy-based event handlers may be scripts or classes. Scripts may be a unstructured, such as:

println "Hello World"

or written as a set of event-specific methods, such as:

def onGET() {
    println "Hello World"
}

Most events support a "method-then-script" invocation strategy: That is, the unstructured script is invoked only if the corresponding method is not found. The exception is the "resource events" (i.e. "list", "retrieve", etc.), which support only method-based invocation. So, Groovy-based resource handlers must be either scripts with methods or classes.

Note that the "invoke events" (i.e. "GET", "POST", etc) are treated as a group in regards to "method-then-script" invocation. Thus, if any of the group methods are defined (e.g. onGET), then the request can only be served by a method -- the unstructured script will not be invoked.

Groovy classes include the more formal decorations of an object-oriented programming model, such as:

import zero.core.groovysupport.ZeroObject

public class MyHandler implements ZeroObject {
  public void onGET() {
    println "Hello World"
  }
}

ZeroObject is a marker interface. Implementations of ZeroObject and Groovy scripts obtain special Zero support in the form of Zero bindings and print and println bound to the Zero writer.

Bindings

Groovy supports bindings as a mechanism to set variables and methods on a script. Zero provides default bindings and a mechanism for you to add additional bindings.'

Bindings do not work within static methods and blocks because the check to see if they are defined is done at compile-time when they are not yet available.

Default bindings

Name Description
app Global Context accessor bound to /app .
config Global Context accessor bound to /config .
event Global Context accessor bound to /event .
headers Global Context accessor bound to /request/headers .
request Global Context accessor bound to /request .
user Global Context accessor bound to /user .
zget() Set of convenience methods from GlobalContext
zput()
zputs()
zpost()
zdelete()
zlist()
zlistAll()
zcontains()
zdump()
logger Instance of zero.core.logging.GroovyLogger for logging from Groovy scripts
render() Invokes zero.core.views.ViewEngine.render()
getRelativeUri() Set of convenience methods from URIUtils
getAbsoluteUri()
getRequestedUri()
getVFile() Returns a File reference based upon the virtualized directories. The method is bound to zero.core.utils.VDirectory.getVFile(String, List)
listFiles() Returns a list of File found within a virtualized directory. The method is bound to zero.core.utils.VDirectory.listFiles(String)

Additional bindings

Defining additional bindings is a two-step process. First, you must provide a Java implementation of zero.core.groovysupport.bindings.BindingHandler to define the bindings. Examples can be found in the Zero source code within the zero.core.groovysupport.bindings package.

The second step is to register your BindingHandler with a script type (based upon file suffix, such as .groovy or .gt). For example:

/config/bindings/.groovy += ["zero.core.groovysupport.bindings.DefaultBindings"]

Global Context accessors

Global Context accessors are objects that support Groovy-friendly interactions with the Global Context. These objects support GPath syntax for read and write, as demonstrated below:

Global Context API Groovy equivalent
zget("/request/method") def m == request.method[]
zget("/request/params/name#1") def name == request.params.name[1]
zput("/request/status", 204) request.status == 204

In general, a Global Context URI is structured as /<zone>/<path>[#<value_path>]. Global Context accessors support GPath notation for the zone/path portion; the value path is expressed within brackets (without the '#').

Details about value pathing within the Global Context are found in the Global Context section.

Groovy scripts invoking Groovy scripts

Groovy scripts in the public and app/resources virtualized directories can access other Groovy scripts and classes from the app/scripts virtualized directory.

Invoking a Groovy class

To use a Groovy class defined in the scripts folder, import the appropriate class name (including package names). You can either instantiate the class or invoke static methods in the class. In the example below, we define a class called Helper in a file called app/scripts/help/support/Helper.groovy.

package help.support

class Helper {
    def help() {
        return "Helping"
    }
}

This class can be used from another script with the following snippet of code:

import help.support.Helper

h = new Helper()
h.help()

Invoking a Groovy script

The steps to define and import a Groovy script from the app/scripts virtualized directory are similar. Groovy scripts may be invoked as an unstructured script (invokeScript) or by method (invokeMethod). For example, define a script in file app/scripts/helper.groovy:

print "Helper Script"

def helperMethod() {
   print "Helper Method"
}

def helperMethodWithArgs(foo, bar) {
   print "Helper Method with $foo $bar"
}

This script may be invoked by the following:

// To run the unstructured script:  results are "Helper Script"
invokeScript ( "helper.groovy" )

// To invoke a specific method:  results are "Helper Method"
invokeMethod ( "helper.groovy", "helperMethod", null )

// To invoke a specific method with args:  results are "Helper Method x y"
invokeMethod ( "helper.groovy", "helperMethod", "x", "y" )

Using Groovy templates

Zero treats files with a .gt suffix as Groovy templates. Groovy templates can be used when a file predominantly contains static text content. Zero uses Groovy's SimpleTemplateEngine to provide template support.

Here is an example of a Groovy template :

<html>
     <body>
         <h1>
            Today is <%= new Date() %>
         </h1>
         <% for (name in ['john', 'jack', 'joe']) { %>
               <ul>
                  <li>${name}</li>
               </ul>
          <% } %>
     </body>
</html>

Groovy statements are enclosed with a <% and %>. Groovy expressions that evaluate to strings can be placed within <%= and %>.

Rendering templates to the output stream

The View renderer renders a template directly to the output stream. This is useful when you're invoking the template in situ for the response.

The View renderer is invoked from a Groovy template as:

<%
 request.view="otherTemplate.gt"
 render()
%>

Rendering templates to a String

Templates may be used to render Strings for other processing, such as content items passed into the Atom renderer. This is accomplished with the invokeTemplate method, such as:

def content = invokeTemplate("foo/bar/mytemplate.gt")
// process content

Similar to the View renderer, the path (e.g., "foo/bar/template.gt") must be relative to your application's app/views virtualized directory.

Logging from a Groovy Script

Groovy scripts and templates have a binding for logger, which is an instance of zero.core.logging.GroovyLogger. logger supports two forms of invocation.

In each invocation form, the log message is specified as a Closure. The Closure is not evaluated unless the specified log level is met.

Invoking with a Closure

This is the simpler form of the logging API. The sourceClass and sourceMethod are derived from the Closure.

File: <appRoot>/public/a/b/test.groovy

package a.b

def onGET() {
   logger.FINE { "Hello world." }
}

Sample excerpt from <appRoot>/config/logging.properties

This sample shows logging specified for exactly this Groovy artifact.

a.b.test.level=ALL

Sample log results

2007-08-09 21:42:08 a.b.test::onGET Thread-10
   FINE [ Hello world. ]

Invoking with named parameters

This invocation form allows the caller to optionally specify the sourceClass and sourceMethod. If not specified, sourceClass and sourceMethod are derived from the Closure.

File: <appRoot>/public/a/b/test.groovy

The following example shows a possible usage that enables arbitrary grouping of Groovy artifacts, which might be handy for specifying consolidated log levels.

package a.b

def onGET() {
   logger.FINE ( clazz: "groovy.a.b.test", method: "boo", msg: { "Hello world." })
}

Sample excerpt from <appRoot>/config/logging.properties

groovy.level=ALL

Sample log results

9:42:23 PM groovy.a.b.test::boo Thread-11
   FINE [ Hello world. ]

Refer to the troubleshooting section for more information about logging and tracing.

Troubleshooting

Why is my Groovy script failing with "...InvokerInvocationException: No such property: ..."?

Missing classes might be reported as "No such property", due to Groovy's attempt to interpret the package as a GPath expression. For example, the following misspelled package:

zero.kore.utils.URIUtils.getRelativeUri("")

results in

"...InvokerInvocationException: No such property: zero"

r45 - 05 Feb 2008 - 19:27:53 - ngawor
Syndicate this site RSS ATOM
Copyright 2007 © IBM Corporation | Privacy | Terms of Use | About this site