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

 

Global context

The global context, as the name implies, provides a central construct for applications to store and retrieve environment information. Scripts in Project Zero run in the context of an HTTP request, the request zone therefore provides access to the HTTP request data. All the information the application has been configured with (including port numbers, directory locations and dependencies) is provided through the config zone. APIs for the global context are available for Java, Groovy and PHP. See the Global context reference for a list of the attributes available, by default, in the global context. The following sections of this article provide information about global context and the APIs:

HELP Note to M1/M2/M3 users: The global context has changed since the M1, M2 and M3 builds. See the migration and other information about this change, provided in the Changes in the global context article.

The Zones

Project Zero provides a default set of zone handlers for applications. Each zone handler provides different lifetime and scope behavior. The Global Gontext can be extended with additional zone handlers as described in the Extending the global context section.

Config zone

Data in the /config zone is generally loaded from configuration files. This data is globally visible and is available for the lifetime of the application.

App zone

Data in the app zone is globally visible and is available for the lifetime of the application.

Request zone

Data in the request zone is visible to the thread that is processing the HTTP request and is available for the duration of request processing (until the response is sent back to the client).

User zone

Data in the user zone is visible to all threads that are processing requests belonging to the same HTTP session (determined by the zsessionid cookie).

At this time, the default user zone is based upon in-memory persistence. Data is available until the application is restarted. While data is saved at the end of each request, it is not guaranteed to be saved before the next request comes in. Additional commands are available for direct manipulation of the user zone:

Command Description
zpost("/user#save", true) Force an immediate synchronous save of the user zone.
zpost("/user#invalidate", true) Invalidate the session.

Event zone

Data in the event zone is visible to the thread on which a handler was dispatched. Data is available for the duration of the event handler procedure call. Changes made to the event zone by one handler are not visible to other handlers of the same event.

Accessing the global context

The global context is available from all parts of a Zero application. How you access the global context varies depending on the language of the artifact.

Global context APIs

Values in the GC are addressed with a "key" reference, which has the following syntax: /<zone>/<path>[#<value_path>].

The GC APIs are summarized with examples based on the following GC contents:

/config/foo/a = b
/config/foo/x = y
/config/map = ["a" : "b", "x" : "y"]

Syntax Comments/examples
T zget(String uri [, T defaultValue]) Returns the value stored at uri; if none, then returns null or defaultValue.

zget("/config/foo/a") == "b"
zget("/config/foo") == null (M2: threw an exception)
boolean zput(String uri, V value) Create/replace the stored value with value. Elements of a stored value may be replaced with Value "pathing" appended to the uri.
boolean zpost(String uri, V value) Create/append value to the stored value. Appends are handled by a TypeHandler; details are summarized in the Value "pathing" section.
void zdelete(String uri [, boolean deleteChildren]) Deletes the specified key; optionally removes all keys that start with uri.
   
boolean zcontains(String uri) Indicates whether a value is stored at uri.

zcontains("/config") == true
zcontains("/config/map#a") == true
List zlist(String uriPrefix [, boolean includePrefix]) Returns a list of children of uriPrefix

zlist("/") == ["/config"]
zlist("/config/foo") == ["/config/foo/a", "/config/foo/b"]
zlist("/config", false) == ["foo", "map"]
List zlistAll(String uriPrefix [, boolean includePrefix]) Returns a list of all GC URIs that start with uriPrefix

zlistAll("/") == ["/config/foo/a", "/config/foo/x", "/config/map"]
String zdump(String uri) Renders the content of all keys that start with uri using toString().
   
Map zputs(String uriPrefix, Map payload) Convenience method for creating GC entries from key/value pairs in the payload.

map.put("w", "z")
zputs("/config/bar", map)
zget("/config/bar/w") == "z"

Value "pathing"

Value pathing is a compact means of referring to elements within a stored value. Value paths are specified by appending fragment identifiers to the key. Details about the fragment (syntax and meaning) are dependent on the type handler associated with the value.

Before we get into the details of type handlers, it may be useful to summarize the support for zput and zpost within the GC APIs:

  • zput() means create (if not defined) or replace (otherwise)
  • zpost() means create (if not defined) or append (otherwise)

Exception conditions

The GC APIs throw an IllegalArgumentException if the uri is ill-formed. A valid GC uri has the following characterics:
Description Valid example Invalid example (throws IllegalArgumentException)
Starts with a slash zget("/") zget("config")
Path does not end with a slash zget("/") is valid zget("/config/")
zget("/config/#any")
Not null zget("/config") zget(null)
Not empty zget("/") zget("")
No value paths with zlist() zlist("/config") zlist("/app/foo#bar)

Maps

The Map type handler supports the #<key> fragment. It refers to the value mapped to <key>.

Java API Groovy API Description Can create entry
zput("/app/myMap", map) app.myMap = map Create/replace existing map DONE
zput("/app/myMap#foo", "bar") app.myMap['foo'] = 'bar' Add/replace entry; map must exist  
       
zpost("/app/myMap", map) zpost("/app/myMap", map) Create/merge into existing map; replaces existing keys DONE
       
zget("/app/myMap") x = app.myMap[] Returns the map  
zget("/app/myMap#foo") x = app.myMap['foo'] Returns entry at key foo  
       
zdelete("/app/myMap") zdelete("/app/myMap") Deletes map  
zdelete("/app/myMap#foo") zdelete('/app/myMap#foo') Removes entry  

Note: Posts to a Map entry are not supported (e.g. zpost("/app/myMap#foo", "bar")).

Lists

The List type handler supports the #<N> fragment. It refers to the N-th element in the list.

Java API Groovy API Description Can create entry
zput("/app/myList", list) app.myList = list Create/replace existing list DONE
zput("/app/myList#0", "bar") app.myList[0] Set/replace list element; list must exist  
       
zpost("/app/myList", list) zpost("/app/myList", list) Create/append to list DONE
zpost("/app/myList", "bar") zpost("/app/myList", "bar") Append to list; list must exist  
       
zget("/app/myList") x = app.myList[] Returns the list  
zget("/app/myList#0") x = app.myList[0] Returns 0th element  
       
zdelete("/app/myList") zdelete("/app/myList") Deletes list  
zdelete("/app/myList#0") zdelete("/app/myList#0") Removes first entry  

FirstElementList

FirstElementList is a variant of List that supports access to the first element as a simple object (without specifying the index). This simplifies handling of values, like query parameters, that are properly stored as lists but are most commonly retrieved as single values.

Within the default zones, only /request/params/<parmName>, /request/headers/in/<headerName>, and /request/headers/out/<parmName> are instances of FirstElementList.

The FirstElementList type handler supports the #<N> fragment. It refers to the N-th element in the list.

Java API Groovy API Description Can create entry
zput("/request/params/p", list) request.params.p = list Create list; list does not exist DONE
zput("/request/params/p#*", list) request.params.p['*'] = list Replace list; list must exist DONE
zput("/request/params/p", "bar") request.params.p = "bar" Set/replace first element; list must exist  
zput("/request/params/p#0", "bar") request.params.p[0] Set/replace list element; list must exist  
       
zpost("/request/params/p", list) request.params.p << list Create list; list does not exist DONE
zpost("/request/params/p#*", "bar") request.params.p['*'] << "bar" Append to list; list must exist  
       
zget("/request/params/p") x = request.params.p[] Returns first element  
zget("/request/params/p#0") x = request.params.p[0] Returns first element  
zget("/request/params/p#*") x = request.params.p['*'] Returns full list  
       
zdelete("/request/params/p#*") zdelete("/request/params/p#*") Deletes list  
zdelete("/request/params/p#0") zdelete("/request/params/p#0") Removes first entry  

Objects (default)

Java API Groovy API Description Can create entry
zput("/app/myObj", o) app.myObj = o Create/replace object DONE
       
zget("/app/myObj") x = app.myObj[] Returns object  
       
zdelete("/app/myObj") zdelete("/app/myObj") Deletes object  

Note: post is not a valid operation on Objects.

Nested

Value manipulation can be nested for zget() zcontains(); all other operations support up to one level of value manipulation. Parameters for value manipulation are delimited by a slash (/) as shown in the following example:

Map<String, String> innerMap0 = new HashMap<String, String>();
innerMap0.put("im0a", "a");
innerMap0.put("im0b", "b");
      
Map<String, String> innerMap1 = new HashMap<String, String>();
innerMap1.put("im1c", "c");
innerMap1.put("im1d", "d");

List<Map<String, String>> list = new ArrayList<Map<String, String>>();
list.add(innerMap0);
list.add(innerMap1);
      
Map<String, List<Map<String, String>>> map
    = new HashMap<String, List<Map<String, String>>>();
map.put("x", list);
      
zput("/config/nested", map);

      
assertEquals("b", zget("/config/nested#x/0/im0b"));
assertEquals("c", zget("/config/nested#x/1/im1c"));

Commands

The Command type handler delegates all operations to the implementation of Command stored in the accessed GlobalContext location. This allows you to provide your own implementation of Command and implement the actions to be taken on a GET, PUT, POST, and DELETE. For convenience, Zero provides a zero.core.context.types.commands.BaseCommandImpl with implementations of GET, PUT, POST, and DELETE which return Context.NO_ZONE_UPDATE. Returning Context.NO_ZONE_UPDATE causes no operation to take place.

Because the Command type already has a registered type handler, you do not need to add new type handlers when providing your own Command implementations.

Commands can be used to implement your own behavior. For example, you could defer evaluation of an expensive value until a get is actually called as follows:

   GlobalContext.zput(Request.remoteHost, new BaseCommandImpl() {
           Object value = null;
           
           public <T> T get(ParsedURI parsedUri) {
              // null is not a valid return value for InetAddress.getHostName()
              if (value == null) {
                 value = req.getRemoteHostName();
              }
              return (T) value;
           }
        
        });

assertEquals(req.getRemoteHostName(), GlobalContext.zget(Request.remoteHost));

Another usage of Command would be to implement post to carry out your own custom action.

When using the default implementation of Command provided by BaseCommandImpl Command objects can not be replaced or deleted from the global context. If you need this behavior, you can override the corresponding methods in Command to allow it. For example, the following implementation allows the Command object to be deleted:

  @Test
    public void testDeleteableCommand() {
      GlobalContext.zput("/test/deleteablecmd", new BaseCommandImpl() {
         Object value = null;
         
         public <T> T get(ParsedURI parsedUri) {
            if (value == null) {
                 value = "original value";
              }
              return (T)value;
         }

         @Override
         public <T> T delete(ParsedURI parsedUri) {
            return (T) Context.NO_VALUE;
         }
        });
      
      assertEquals(true, GlobalContext.zcontains("/test/deleteablecmd"));
      GlobalContext.zdelete("/test/deleteablecmd");
      assertEquals(false, GlobalContext.zcontains("/test/deleteablecmd"));
    }

Extending the global context

You can extend the global context with additional zone and type handlers. Zone handlers store the data and are responsible for scope and lifetime of that data. Type handlers handle value "pathing".

Zone handlers

The global context APIs treat the first path element of an access key as the name of a ZoneHandler ( /<zone>/<path>[#<value_path>] ). GC APIs then delegate store/retrieve operations to the corresponding zone handler.

Zone handlers are Java implementations of zero.core.context.zones.ZoneHandler . Zone handlers are registered via configuration, such as:

/config/zoneHandlers += {
   "user" : "zero.core.context.zones.UserZoneHandler"
}

Zone handlers may also register for deactivation on an event. The DeactivateHandler is provided as a convenience utility for this purpose. For example, the default user zone handler is deactivated at the end of the "request" lifecycle as a result of the following configuration snippet:

/config/handlers += {
   "events" : "requestEnd",
   "handler" : "zero.core.handlers.DeactivateHandler.class",
   "instanceData" : { "zoneName" : "user" }
}

Type handlers

Type handlers are responsible for value manipulation, including appends. Type handlers are Java implementations of zero.core.context.zones.TypeHandler

To maintain support for nested value paths, implementations must consume their corresponding parameter from the value path and advance the valuePathOffset in parsedUri. See the source for zero.core.context.types.MapTypeHandler or zero.core.context.types.ListTypeHandler for specific examples.

Type handlers are registered by appending type/handler implementation key/value pairs to the map in the global context at /config/typeHandlers. For example, the handler implementation (zero.core.context.types.CommandTypeHandler) for the Command type (zero.core.context.types.commands.Command) is specified in configuration as:

/config/typeHandlers += {
   "zero.core.context.types.commands.Command" : "zero.core.context.types.CommandTypeHandler"
}

r53 - 04 Feb 2008 - 18:03:59 - madhu
Syndicate this site RSS ATOM
Copyright 2007 © IBM Corporation | Privacy | Terms of Use | About this site