ptg This page intentionally left blank Download from www.wowebook.com ptg 63 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>. C H A P T E R 4 Configuration Files Explained Download from www.wowebook.com ptg Figure 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. 64 Chapter 4 Configuration Files Explained 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 Download from www.wowebook.com ptg Application Configuration 65 or 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" Download from www.wowebook.com ptg 66 Chapter 4 Configuration Files Explained Yo u can t he n r ef er en ce this els ewh er e b y u si ng th e syn ta x ${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 nested resources, such as /resources/users/1234/bookmarks/2002, you need to configure a bonding file. Download from www.wowebook.com ptg Application Configuration 67 Table 4.1 Handler/Bonding Files File Description /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" } } Download from www.wowebook.com ptg 68 Chapter 4 Configuration Files Explained Table 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. Download from www.wowebook.com ptg Dependency Management with Ivy 69 “/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> Download from www.wowebook.com ptg 70 Chapter 4 Configuration Files Explained <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 revision 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 lower-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 Download from www.wowebook.com ptg Dependency Management with Ivy 71 upper-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. Download from www.wowebook.com . export ZERO_OPTS) and # update proxy values # ZERO_OPTS="$ZERO_OPTS -Dhttp.proxyHost=myProxyHost -Dhttp.proxyPort=myProxyPort -Dhttps.proxyHost=myProxyHost -Dhttps.proxyPort=myProxyPort" #. proxy settings. rem set ZERO_OPTS=%ZERO_OPTS% -Dhttp.proxyHost=myProxyHost -Dhttp.proxyPort=myProxyPort -Dhttps.proxyHost=myProxyHost -Dhttps.proxyPort=myProxyPort For Windows, uncomment by. perfectly. IBM WebSphere sMash Development Process IBM WebSphere sMash has been developed using a community-driven commercial development process. This means that most of the development efforts