|
|
|
Configuration
Properties and behavior of a Project Zero application may be specified in configuration files.
Zero configuration file: zero.config
The configuration of a Zero application is set in the config zone of the Global Context. Values are set into the config zone via configuration files. Configuration files for the application and its dependencies are processed at application startup.
Configuration files are effectively "scripts" that set and append values into the config zone. The syntax is based upon a simple grammar of GC URIs and JSON data structures.
While processing configuration files, entries in the config zone are handled with a "first one wins" strategy:
- Values may be set once (subsequent attempts to set a value at an existent GC URI are denied)
- Values may be appended to arrays
- Key/value pairs may be appended to objects, provided that the key is not already set in that object
After processing the configuration files, the config zone should be considered read only. (Although the values could be changed by application code, not all changes affect the running application. For example, the application must be restarted for changes in /config/http/port to take affect.)
For example:
Example zero.config file
# Value set
/config/http/port = 8080
# List set
/config/resources/defaultExtensions = [".groovy"]
# List append
/config/bindings/.groovy += ["zero.core.groovysupport.bindings.DefaultBindings"]
# Map set
/config/test/map = { "a" : "b", "c" : "d" }
# Map append
/config/test/mapappend += { "a" : "b", "c" : "d" }
/config/test/mapappend += { "x" : "y", "w" : "z" }
# Event handler
/config/handlers += [{
"events" : "GET",
"handler" : "custom.Handler.class"
}]
# Value reference (insert value read at config-load time)
/config/property/myPrefix = "/foo/bar"
/config/test/value = "${/config/property/myPrefix}/bat"
# Variable set/value reference
myPrefix = "/foo/bar"
/config/test/value = "${myPrefix}/bat"
# Include
@include "${/config/dependencies/zero.core}/config/security/form.config"
{ "formLoginPage" : "/login" }
Config syntax
| Syntax | Description | Example |
GC_URI = JSON_value | Set a value at GC URI See zput for details | /config/http/port = 8080 |
GC_URI += JSON_value | Set/append a value at GC URI See zpost for details | /config/bindings/.groovy += ["zero.core.groovysupport.bindings.DefaultBindings"] |
variable = JSON_value | Variable set | myPrefix = "/foo/bar" |
${GC_URI} | GC value reference Value is read at configuration-load time | /config/longname = "Application: ${/config/name}" |
${variable} | Variable value reference | /config/contextRoot = ${myPrefix} |
@include JSON_string [JSON_object] | Process another configuration file, with optional variables specified as a JSON_object | @include "${/config/dependencies/zero.core}/config/security/form.config" { "formLoginPage" : "/login" } |
# comment | Comments | # This is a comment |
JSON_value could be any of the valid JSON types: object, array, string, number, true, false, and null.
GC_URI is of the form /<zone>/<path>.
variable consists of alphanumeric characters (a-z, A-Z, 0-9) and underscore.
Value references (variable and GC) may be used anywhere a JSON object is expected (e.g. /config/contextRoot = ${myPrefix}). Value references that refer to string types may be embedded within a JSON string (e.g. /config/longname = "Application: ${/config/name}").
Resolved dependency locations
Root directories of resolved dependencies are available as Global Context value references. The location is ${/config/dependencies/moduleName}, where the module name of the dependency matches the name specified in the corresponding ivy.xml files (e.g. zero.core).
Advanced You can obtain the root directory for each dependency from the Global Context as follows:
List<String> listOfDependencies = zget("/config/dependencies");
for (String dependency : listOfDependencies) {
String dependencyRoot = zget("/config/dependencies/" + dependency);
// Operate on the dependencyRoot (e.g. load files)
}
Include
Example @include "${/config/dependencies/zero.core}/config/security/form.config"
Zero processes includeFile as a configuration file. includeFile may be an absolute or relative file reference. Relative references are relative to the including file. Included files are now virtualized, so the above could be rewritten as
Example @include "security/form.config"
This would resolve to form.config in the config/security sub-directory of a dependent project.
Optional arguments can be passed as a JSON_Object.
@include "${/config/dependencies/zero.core}/config/security/form.config"
{ "formLoginPage" : "/login" }
Configuration properties set within includeFile are scoped to that file and any files included by it. Properties are immutable within their scope, so "first one wins."
Comments
Lines that begin with a hash (#) are comments.
Storage formats
The following table describes how JSON types from configuration files are stored in the GC:
Event-handler registration
Note to M1/M2/M3 users: The Event handler registration has been changed in M4. Please update your configuration files to conform to the syntax below to allow applications to start up. For a summary of the changes in Event handler registration, refer to the Event handler registration changes article.
Event handlers are registered via configuration files. The complete syntax has the following form:
/config/handlers += [{
"events" : JSON_string or JSON_array(JSON_string),
"handler" : JSON_string,
"conditions" : JSON_string,
"instanceData" : JSON_object
}]
where
- events is the name (or list of names) of the events handled by this handler
- handler is the name of the handler, including a suffix that must match a registered
Interpreter type. The default list of registered types is:
-
.class for Java (the value is the fully-qualified class name with a ".class" suffix, e.g. "your.pkg.Handler.class")
-
.groovy for Groovy scripts (searched in app/scripts; use slashes for path delimiters, e.g. "foo/bar/handler.groovy")
-
.gt for Groovy templates (searched in app/views; use slashes for path delimiters, e.g. "foo/bar/handler.gt")
-
.php for PHP scripts (searched in app/scripts; use slashes for path delimiter, eg "foo/bar/handler.php")
- conditions is optional. The value of the
conditions, computed at run time. If not specified, then the handler is always a match for the corresponding event.
- instanceData is optional. This data is provided to the handler in the
event zone.
Condition operators
-
Global Context URI -
true only if the Global Context contains the specified key. Example: "conditions" : "/request/status"
-
== - Selector pattern match. Named groups are specified as
{name}; matches may be qualified, such as {name:any}. Values of named groups are set into the event zone for the handler. Example: "/request/path == /foo/bar/{next}]; the value of next is available to the invoked handler in the Global Context at /event/next contains value.
Qualifiers:
-
-
any - Matches to the end.
Example: If /request/path == /a/b/c, then "/request/path == /a/{remainder:any}" evaluates to true and the handler will be invoked with /event/matchedURI == /a and /event/remainder == b/c.
The pipe character | will also match to the end of the URI and, additionally, set /event/pathInfo. Example: If /request/path == /a/b/c, then "/request/path == /a|" evaluates to true and the handler will be invoked with /event/matchedURI == /a and /event/pathInfo == /b/c.
Note: | is only valid as the last character in the selector pattern or last except for right brackets. For example, "/request/path == /a/b|" and "/request/path == /a[/b|]" are valid; "/request/path == /a|/b" is not.
-
-
element - Matches to the next slash.
-
-
digit - Matches one or more digits: [0-9].
-
-
word - Matches one or more word characters: [a-zA-Z_0-9].
-
=~ - Regex pattern match, based upon the regular expression support in the JDK.
Example: "/request/path =~ /foo/.*" Example: "/event/resolvingEvent =~ (GET|POST|DELETE|PUT)"
-
! - Negates the condition value; placed before the operator it modifies.
Example: "!(/request/status)"
-
!= - Not URI matches
Example: "/request/path != /a/b"
-
!~ - Not matches
Example: "/event/resolvingEvent !~ (GET|POST)"
-
&& - Logical AND
Example: "(/request/path != /a/b) && (/event/resolvingEvent !~ (GET|POST))"
-
|| - Logical OR Example:
"(/request/path == /a/b) || (/event/resolvingEvent =~ (GET|POST))"
Configuration templates
A combination of @include and configuration properties can be used to build configuration templates.
For example, security support in zero.core uses configuration templates.
Configuration template example: config/security/rule.config
authType=""
users=[]
groups=[]
roles=[]
requireSSL=false
csrfProtect=true
@include "requireSSL.config"{
"conditions": ${conditions},
"requireSSL": ${requireSSL}
}
csrfProtect=${csrfProtect}
/config/handlers += [{
"events" : "secure",
"handler" : "zero.core.security.SecurityHandler.class",
"conditions": ${conditions},
"instanceData" : {
"authType" : ${authType},
"groups" : ${groups},
"users" : ${users},
"roles" : ${roles},
"csrfProtect" : ${csrfProtect}
}
}
]
/config/handlers += [{
"events" : "retrieveCredentials",
"handler" : "zero.core.security.${authType}UserInfoResolver.class",
"conditions": ${conditions}
}]
/config/handlers += [{
"events" : "authorize",
"handler" : "zero.core.security.authorization.AuthorizationHandler.class",
"conditions": ${conditions}
}]
Using a configuration template
@include "security/rule.config"{
"conditions" : "(/request/path =~ /formauth/getonly(/.*)?) && (/request/method == GET)",
"authType" : "Form",
"groups" : ["ALL_AUTHENTICATED_USERS"]
}
Type-handler registration
Type handlers are registered via configuration files or programmatically. Each new type handler is registered by appending it to the list. For example:
/config/typeHandlers += {
"zero.core.context.types.commands.Command" : "zero.core.context.types.CommandTypeHandler"
}
Order of processing
Zero enforces a "first one wins" strategy with configuration processing to ensure consistency throughout the application. As a result, you might need to understand the order in which configuration files are processed in cases involving overwrites.
By default, Zero first processes <apphome>/config/zero.config, then processes config/zero.config for each dependency. The order in which dependencies are processed is described in the Virtualized directories documentation. Although the config directory is not a virtualized directory, the order of processing configuration files is identical to the search order through dependencies within a virtualized directory.
Pre- and post-configuration files
Deployers may want to override application configuration settings without modifying any of the application files. This can be accomplished with pre- and post-configuration files. (Pre- and post- refer to the main configuration processing step: pre- happens before the main configuration processing; post- occurs after.)
In Eclipse, you specify an alternate configuration file by modifying the Run profile for that Zero application to set the Program Arguments to: [-pre <preConfigFile>] [-post <postConfigFile>] <applicationRootDirectory>
From the command line:
zero run [-args "-pre <preConfigFile>"]
<configFile> may be an absolute or relative file reference. Relative file references are relative to the current working directory.
|