Migration notes for M3

This page summarizes key changes from the previous milestone.

Configuration

The configuration syntax changed for M3. The new syntax is based upon a simple grammar of Global Context URIs and JSON data structures. This change was intended to improve clarity by leveraging a known data format.

The new syntax is documented on the Configuration page of the Developer's Guide. This section summarizes changes from the previous syntax.

Tips for porting from M2

Semantic Old syntax New syntax
Value set [/config/http]
port=8080
/config/http/port=8080
List append [/config/bindings/.groovy[]]
zero.core.groovysupport.bindings.DefaultBindings
/config/bindings/.groovy+=["zero.core.groovysupport.bindings.DefaultBindings"]
Variable set [@properties]
myProp=/foo/bar
myProp="/foo/bar"
Variable reference [/config/test]
value=${myProp}/bat
/config/test/value="${myProp}/bat"
Includes [@include ${zero.core}/f.config]
formLoginPage=/login
@include "${/config/dependencies/zero.core}/f.config" {"formLoginPage":"/login"}

Other changes

  • Zero no longer fires a config event during config load.
  • Dependency information is stored in a different way:
    • /config/dependencies/list is now at /config/dependencies
    • /config/dependencies#dep is now at /config/dependencies/dep
  • Resolved properties have changed to GC value references. For example, ${zero.core] from the old syntax is now specified as ${/config/dependencies/zero.core}.

GC changes

The GC has been modified to simplify configuration processing. The details are probably interesting only to those who deal with the internals of Zero, such as the run-time team. Other users are not affected by these changes.

First, the GC APIs and internal constructs have been separated. Instances of the new zero.core.context.Context represent all the internal constructs, including zone and type handlers; zero.core.context.GlobalContext is still a set of static APIs, but they now operate on an instance of Context set with GlobalContext.setContext(Context).

Second, the new zero.core.config.ConfigLoader contains a set of utility methods for loading .zeroresolved.properties files and processing config files. An example of creating a new GC and loading all config files (application then dependencies) is shown below:

GlobalContext.setContext(new Context());

ConfigLoader.loadResolvedProperties(_applicationRootDirectory);

List<String> listOfDependencies = zget(Config.Dependencies._self);
for (String dependency : listOfDependencies) {
    String dependencyRoot = zget(Config.Dependencies._self + "/" + dependency);
    File configFile = new File(dependencyRoot + "/config/zero.config");
    ConfigLoader.loadFile(configFile.getAbsolutePath());
}

Global Context

Objectives for the changes:

  • Provide a common GC API across programming languages (Java, Groovy, PHP). We're close already. By renaming methods in a few places, we'll be the same.
  • Clarify the use of the GCAccessor, which is the Groovy shortcut for GC access. Use of the GCAccessor is optional.
  • Improve usability of the GC APIs. For example:
    • Simpler get(): GlobalContext.zget(uri) will return null if the uri is not found (rather than throwing an IllegalArgumentException).
    • Simpler "walking": GlobalContext.zlist(uri) will return a list of child URIs. Thus, zlist() will be useful for "walking" through the GC.

Summary of changes

Revised GC APIs

The GC APIs now have a "z" prefix as a simple means of reducing namespace collisions.

The following sections describe the new syntax and behavior changes in the GC API. We'll use 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]) zget("/config/foo/a") == "b"
zget("/config/foo") == null (M2: threw an exception)
List zlist(String uriPrefix [, boolean includePrefix]) Returns a list of children of uriPrefix
(M2: returned all uris that started with uriPrefix).

zlist("/") == ["/config"]
zlist("/config/foo") == ["/config/foo/a", "/config/foo/b"]
zlist("/config", false) == ["foo", "map"]
boolean zcontains(String uri) Was containsKey(uri) in M2
Handles value path (M2:  no value path)
=zcontains("/config") == true

zcontains("/config/map#a") == true
T zpost(String uri, V value) Same as M2.
T zput(String uri, V value) Same as M2.
Map zputs(String uriPrefix, Map payload) Was available in Groovy for M2.
map.put("w", "z")
zputs("/config/bar", map)
zget("/config/bar/w") == "z"
void zdelete(String uri [, boolean deleteChildren]) Same as M2.
String zdump(String uri) Same as M2.

Java: Using static imports

Java code can be a clean demonstration of the GC APIs by using static imports, as follows:

Java example

import static zero.core.context.GlobalContext.*;
public class MyHandler {
  public void onGET() {
    String qvalue = zget("/request/params/qname");
  }
}

Groovy: Added method bindings for GC APIs

All .groovy scripts, as well as classes that implement ZeroObject , receive bindings for the GC APIs. So, there's no need to import GlobalContext.

Revised exception conditions

In M2, GlobalContext.get(uri) threw an IllegalArgumentException if uri was not found. Most of the other APIs were more friendly, returning default/empty values, even if uri was ill-formed.

In M3, zget(uri) returns null if uri is not found. This is equivalent to zget(uri, null).

Another significant change in M3 is that all of 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("")

Groovy: Clarified GCAccessor

GCAccessor is the support behind the GPath-like interactions with the GC. An example from M2:
def id = request.params.userId.get()
request.status = 202

This approach was rather confusing because we tried to use the GCAccessor to represent data, but it didn't always work that way (note the occasional need for .get()). Also, there were other use cases where we wanted to extract the GC URI or an accessor object from the data (ref. [[http://www.projectzero.org/wiki/bin/view/Community/JasonsBlog/BlogEntry5][.toPath() and .toGPath()]), which stretched the intuition.

For M3, GCAccessor has been reworked to be just that: An accessor object. It's been integrated into the Groovy syntax, as summarized here:

GC API Groovy shortcut
zget(uri) Always ends with brackets; empty brackets are valid.
def m = request.method[]
def id = request.params.userId[2]
zget(uri, defaultValue) def id = request.params.userId.zget('anonymous')
zlist(uriPrefix) request.headers.in.zlist()
request.headers.in.zlist(true)
zcontains(uri) request.headers.in.zcontains('X-METHOD-OVERRIDE')
zpost(uri) request.headers.out.MyHeader << ['MyValue']
zput(uri) request.method = 204
zputs(uri, payload) request.headers.out.zputs([MyHeader : 'MyValue'])
zdelete(uri) user.counter.zdelete()
zdump(uri) request.zdump()

The following property bindings are GCAccessor objects available by default to all .groovy scripts and class implementations of ZeroObject:

  • app
  • config
  • event
  • headers
  • request
  • user

Additional bindings may be registered using the same method as for M2.

A more complete set of examples are available in the zero.core.tests unit test cases.

Groovy: Removed _gc binding

Use method bindings (e.g. zget('/request/method')) or GCAccessor bindings (e.g. request.method[]) instead.

Zone handlers

Changes for ZoneHandler implementations:
  • No longer implement containsKey(); this is now handled in the GlobalContext implementation.
  • Must implement isAvailable(). Currently used to control access; may be removed early next week. Depends on whether the zone handlers can be self-protecting on the normal ZoneHandler APIs without inadvertent auto-activation.

Changes for ThreadLocalZoneHandler implementations:

  • That interface has been removed; replaced with ActivatableZoneHandler interface.

Tips for porting from M2

  • Search .groovy and .gt files for instances of .get(); replace with [] for GC accessors.
  • Search .groovy and .gt files for .condGet(uri, null); replace with [].

While debugging, if you find that a variable comes through with what looks like a path instead of a value (e.g. /request/status instead of 200), then you're probably missing a [] on the property binding. That is, you probably have def x = request.status where you should have def x = request.status[].

r1 - 14 Dec 2007 - 21:27:55 - steveims
Syndicate this site RSS ATOM
Copyright 2007 © IBM Corporation | Privacy | Terms of Use | About this site