Global Context and zero.config WebSphere sMash applications consist of a collection of related but separate modules that respond to application and user request events.. Figure 4.1 WebSph
Trang 1This page intentionally left blank
Trang 263
In the previous chapter, we talked about favoring convention over configuration In this chapter,
we discuss what to do when you need to override convention and tell the system or your
applica-tion how to behave This chapter describes exactly how to do that in the WebSphere sMash
envi-ronment This chapter gives you the “tools” and the know-how to configure the WebSphere
sMash environment and your applications
Configuration in WebSphere sMash can be roughly categorized as affecting either the
application or the environment, as shown in Figure 4.1 The list of files shown is not exhaustive; it
merely shows the files we will be discussing in this chapter We defer discussion of some types of
configuration, such as database, PHP, and security, to chapters that deal specifically with those
subjects In this chapter, we focus on creating custom configuration data for your application and
on configuring the runtime environment
Application Configuration
The following sections concern the settings that are specific to a single application The files and
settings involved are located within the application directory tree
Global Context and zero.config
WebSphere sMash applications consist of a collection of related but separate modules that
respond to application and user request events All data for these events is stored in a global data
structure called the Global Context (GC) Although we discuss the Global Context in detail in
Chapter 5, “Global Context,” it is important to understand its role in configuration The Global
Context is a URI-addressable tree with predefined root nodes called zones Each zone has a
par-ticular purpose One of these zones is used for application configuration It is called, naturally, the
config zone, and entries in this zone are addressed using the pattern /config/<path>
Configuration Files
Explained
Trang 3Figure 4.1 WebSphere sMash configuration
The config zone is populated at runtime by processing zero.config files stored in the config
directories of WebSphere sMash modules The majority of configuration you need to worry about
as a developer of WebSphere sMash applications is contained in the zero.config file Every
Web-Sphere sMash application or module has a zero.config file by default, even if it’s empty When a
WebSphere sMash application starts, the zero.config files for the application, and all its
depend-encies, are merged to populate the config zone of the Global Context for the application The
appli-cation can query the appropriate Global Context URI to find the configuration values it needs
WebSphere sMash is intended to be a dynamic, script-oriented environment As such, most
configuration changes are picked up automatically when a new request comes in to the
applica-tion An application restart is not usually required
Custom Configuration Data
For most applications, you will have some custom configuration data that you need to read from
somewhere zero.config is the place to put your application’s custom configuration data This
file has a flexible, easy-to-use format for specifying configuration data Users of your application
will also know where to look for your configuration data, because most application configuration
is consolidated in this file
From an initial glance, the zero.config file looks to be a collection of key/value pairs If
you look a little closer, however, you see that it is actually a sequence of modifications to the
Global Context Each entry in the zero.config file consists of a Global Context key, an append
Trang 4or set operation, and a JSON-legal entity The Global Context is a hierarchy of URIs pointing to
JSON values, arrays, or objects JSON values can be numbers, quoted strings, or one of the
liter-als: true, false, or null Quoted strings can use single or double quotes You can make assignments
with any of these types using the = operator or append to arrays and objects using the += operator
See Listing 4.1 for an example
Listing 4.1 Example Assignments
# Comments begin with a hash mark
/config/myapp/myvar = 'test'
/config/myapp/myarray = [ 'value1', 'value2', 'value3' ]
/config/myapp/myobject = { 'attr1':100,'attr2':'hello','attr3':false }
/config/myapp/myarray += [ 'value4', 'value5','value6' ]
/config/myapp/myobject += { 'attr4':true, 'attr5':null, 'attr6':500 }
There are a few important rules about how these operations are processed The statements
in the zero.config for the application are processed first in sequential order, followed by
state-ments in the zero.config files for the application’s dependencies During this processing, the
first assignment for a URI wins; all other assignments are ignored This approach ensures that
your application wins when it overrides config values that are specified in dependencies For
objects, you can only append an attribute that hasn’t already been set
With the concepts of overrides, operators, arrays, and objects, you have a lot of flexibility in
defining your application’s configuration If you are developing a module for use by others, you
can offer extensibility through configuration For example, someone extending your module
could decorate one of your configuration objects with additional attributes that are then processed
by an additional handler that is chained to yours You could also create a wrapper application that
contains database information for a specific test environment that overrides the local development
database
Variable Substitution
The zero.config file supports variable substitution within the file This feature is useful if you
have repetitive paths in your configuration or if your configuration needs to be more dynamic
These text substitutions are processed at configuration load time In your zero.config file, you
can set a substitution variable as follows:
<variableName> = <Global Context URI or JSON entity>
For example:
my_data = "/config/myapp"
Trang 5You can then reference this elsewhere by using the syntax ${variableName} You can also
reference a location in the Global Context directly using the syntax ${Global Context URI}—
for example:
${my_data}/myVar = "value1"
${my_data}/myVar2 = 400
${my_data}/myVar3 = ${/config/http/port}
Include Files
If your configuration is complex, you may want to partition your configuration by topics
Some-times you need to include configuration information from an external file into your application’s
zero.config For both of these cases, include files can be used For example, WebSphere sMash
provides a configuration template for security configuration for your application To include a
con-figuration template, WebSphere sMash provides an include directive It takes the following form:
@include "<file name>" [JSON object of variables to define]
For example:
@include "test/template.config" {
"param1" : "value1",
"param2" : "value2"
}
The filename parameter is relative to the location of the current config file The virtual file
system is used, so files from dependencies can be included as well If you want to locate a file in a
specific dependency’s directory, you can use a GC variable of the form, as follows:
${/config/dependencies/<dependency name>}
For example:
@include "${/config/dependencies/foo}/config/template.config"
{
"param1" : "value1",
"param2" : "value2"
}
The optional parameters in the include statement are defined as variables for use by the include
file The include file can reference them just like other variables, such as ${param1} or ${param2}
WebSphere sMash security uses include files for configuration See Chapter 9, “Security
Model,” for more information
Handler Configuration
In the last chapter, we introduced the notion of event handlers Usually, the default REST handler
naming convention is sufficient to route events to your handler However, if you want to configure
Trang 6Table 4.1 Handler/Bonding Files
/app/resources/users.groovy Handler for users resources
/app/resources/bookmarks.groovy Handler for bookmarks resources
/app/resources/bookmarks.bnd Bonding file to nest bookmarks within users
A bonding file is created with your /app/resources directory with the same name as your
handler with a bnd extension In the preceding example, you might have the files shown in Table 4.1
The bonding file contains pseudo-code for your URI path bookmarks.bnd would have
the following content, based on the preceding URI structure:
/resources/users
/resources/users/bookmarks
Note that we provided the URI for users and bookmarks Without the first line, we would
not be able to handle events for the users resources independently of events associated with the
bookmarks resources.
The <handler>/<id> pattern is implied in the bonding file In your handler code, you can
access the IDs through a Global Context URI generated in the request zone by concatenating the
han-dler name and Id For example, given the request URI, /resources/users/1234/bookmarks/
2002, the following GC URI values are set:
/request/params/usersId = 1234
/request/params/bookmarksId = 2002
If, however, your desired URI path does not follow the WebSphere sMash convention of
/resources/{handler}/{id}, you can configure a different path sequence in one of two
ways The first is to configure a bonding file; the second is to explicitly declare your handler in
the zero.config file
However, some handlers (such as the WebSphere sMash authentication handlers) require
configuration You might also want to create your own custom handler that is only invoked under
certain conditions If, for example, your desired URI path does not follow the WebSphere sMash
convention of /resources/{handler}/{id}, you can configure a different path sequence
Listing 4.2 displays an example event handler declaration, which adds to the existing list of
handlers
Listing 4.2 Example Event Handler Declaration
/config/handlers += [{
"events" : "GET",
"handler" : "myhandler.groovy",
"conditions": "/request/path == /myhandler|",
"instanceData" : { " testparm" : "testval" }
}
Trang 7Table 4.2 Sample Event Zone Conditions
Condition
Sample /request/path Global Context URI Value
“/request/path == /a/b|” /a/b/c/d/e /event/matchedURI /a/b
/event/pathInfo /c/d/e
events is a JSON string for a single event, or a JSON array for a list of events Valid values
are as follows:
[ "GET", "PUT", "POST", "DELETE", "requestBegin",
"re-questEnd", "log" ]
handler is a JSON string that specifies a handler file The string can include a relative path
for a Groovy script, Groovy template, or PHP script For Groovy and PHP scripts, the path is
rel-ative to the /app/scripts directory For Groovy templates, the path is relative to the
/app/views directory If the handler is a Java class, specify the full Java class name, like
com.myco.MyHandler.class
conditions is an optional expression that further filters events based on input values from
the Global Context A typical usage is to check the /request/path against some value The
event is passed to the handler only if it is one of the specified events and the specified condition
evaluates to true The conditions expression takes one of the forms shown in Listing 4.3
Listing 4.3 Conditions Expression
<GC URI> == <selector pattern>
<GC URI> != <selector pattern>
<GC URI> =~ <Java regular expression>
<GC URI> !~ <Java regular expression>
!(condition)
(condition1) && (condition2)
(condition1) || (condition2)
The selector pattern syntax is typically specified in one of two ways: using a vertical bar or
a variable substitution The vertical bar ends a pattern match and creates the delineation between
the matched URI and the request path info If you need to match a path segment in the middle of
a URI, you can use a variable substitution with braces If you need even more complex matching,
you can use a Java regular expression When the event is routed to the handler, values will be set
in the event zone of the Global Context corresponding to the matching URI segments Table 4.2
displays some example conditions and how they are evaluated
instanceData is an optional JSON object that is set as /event/instanceData in the
Global Context
Trang 8“/request/path ==
/a/b/{somevar}/c/d”
/a/b/foo/c/d /event/matchedURI /a/b
/event/pathInfo /c/d/e
/event/somevar foo
“/request/path =~ /a/b/.*” /a/b/c/d /event/matchedURI /a/b
/event/pathInfo /c/d/e
Dependency Management with Ivy
In the last chapter, we introduced the WebSphere sMash dependency management system, which
is based on an Apache project called Ivy WebSphere sMash applications and libraries are
pack-aged into Ivy modules, which are ZIP files containing code, and an Ivy metadata file that describes
the package and the modules it requires The Ivy metadata file is called an “Ivy file,” and is always
named ivy.xml The modules that are required by the package are called dependencies.
From a packaging perspective, there is little difference between an application and a
dependency An application can be distributed as a module For example, the WebSphere sMash
samples are applications packaged as Ivy modules and distributed through an Ivy repository
Ivy modules are created by running the package command against an application When the
package is created, it can be published to an Ivy repository or distributed through other means
Ivy Modules
An Ivy module is a ZIP file that is described by an ivy.xml metadata file In a WebSphere sMash
module, the ivy.xml file is embedded in the ZIP file in the /config directory When the module
is published to an Ivy repository, the ivy.xml file is extracted
Ivy Files
Listing 4.4 shows the fields within an Ivy file
Listing 4.4 Sample Ivy File
<ivy-module version="1.3">
<info module="Bookmarks" organisation="zero" revision="1.0.0">
<license name="type of license" url="http://license.page"/>
<ivyauthor name="author name" url="http://authors.home.page"/>
<description homepage="http://module.description.page"/>
</info>
<publications>
<artifact type="zip"/>
</publications>
Trang 9<dependencies>
<dependency org="zero" name="zero.core" rev="[1.0.0.0, 3.0.0.0["/>
</dependencies>
</ivy-module>
These fields are as follows:
• ivy-module version—It is important to note that the “version” attribute here refers to the
Ivy version, not the version of this module The default value of 1.3 should not be changed
• info—The info stanza contains metadata about the package
• module—The module attribute specifies the name of the module By WebSphere
sMash convention, the module name is identical to the application’s root directory The
module name can contain alphanumeric characters and periods Most WebSphere
sMash modules have a module name that begins with zero., such as zero.core
• organisation—The organisation attribute specifies the name of the organization
that created the module WebSphere sMash defaults this attribute to zero
• revision—The revision attribute specifies the version number of this particular
module When other packages declare a dependency on this module, they specify a
revi-sion range that is compared against the revirevi-sion attribute of matching modules
Web-Sphere sMash uses a four-digit revision scheme for its modules, but the default for user
applications is three digits
• license, ivyauthor, description—These fields are attributes that are fairly
self-explanatory The values are provided for informational purposes only WebSphere
sMash does not use these attributes
• publications—The publications stanza refers to the type of files that are
described by this Ivy file In WebSphere sMash, you do not need to modify this list
• dependencies—The dependencies stanza lists patterns that describe the modules
on which this module depends There is one dependency stanza for each module
• org—The organization name of the required module
• name—The name of the required module
• rev—A pattern describing the acceptable range of revisions for this dependency.
Revision patterns generally take the following form:
[lower-bound, upper-bound]
The left bracket before the bound means “everything greater than or equal to
lower-bound.” The left bracket after the upper-bound means “everything up to but not including the
Trang 10upper-bound.” A right bracket would include the upper-bound You can leave off the upper-bound
and ending bracket if you only want to include modules greater than or equal to the lower bound
The best way to specify this range is to use the same pattern as specified by the module that
you are depending on For example, if the child module uses three-stanza revisions (for example,
1.0.0), you would specify your dependency as [1.0.0,2.0.0] If it uses four-stanza revisions
(for example, 1.0.0.0), you would specify your dependency as [1.0.0.0,2.0.0.0] When
WebSphere sMash searches for dependencies matching the pattern, it does a numerical
compari-son on each individual stanza If an individual stanza contains a letter, a string compare is used
instead The following example show how different version numbers would be compared:
1.0.0 < 1.0.0.0 < 1.0.0.0.29102 < 1.0.0.0.29102B
Resolution and Resolvers
After you have declared your application’s dependencies, they need to be resolved “Resolving
dependencies” means telling WebSphere sMash to find specific versions of modules that match
the dependency patterns declared in the Ivy file WebSphere sMash searches a series of local and
remote repositories for matching modules.
Local repositories are repositories on your local file system They are simply directory
structures that follow the Ivy format In general, you shouldn’t need to understand the format of a
repository The repository structure is managed by the WebSphere sMash tooling Repositories
can contain multiple revisions of the same module
By default, the WebSphere sMash repository is stored in a directory called
“zero-reposi-tory” under your WebSphere sMash command-line installation directory, such as
c:\sMash\zero\zero-repository Under the zero-repository directory, you will have one or two
directories named “stable” and “experimental,” depending on which version of the WebSphere
sMash CLI you installed The “stable” and “experimental” branches are module groups Module
groups are collections of version-compatible modules “stable” contains modules that were
downloaded from a stable, fully tested remote repository, whereas “experimental” contains
mod-ules that were downloaded from the most recently published remote repository
Remote repositories come in two flavors: Zero repositories and Maven repositories Zero
repositories are Ivy-formatted repositories Maven repositories are structured and packaged
according to the Apache Maven specifications Many Apache projects, such as Apache
Com-mons, Xerces, and Xalan, are packaged and published in Maven repositories WebSphere sMash
can locate modules in both kinds of repositories
Remote Zero repositories look like local repositories, except that they are
HTTP-accessi-ble The preconfigured remote repositories are all published on www.projectzero.org The list of
remote Zero repositories at the time of this printing is shown in Table 4.3
Note that the URL for the experimental module group will change as newer versions of
sMash are released