-
Notifications
You must be signed in to change notification settings - Fork 0
The Server side AMD Config file
The server-side AMD configuration is a JavaScript object that closely mirrors the client-side AMD configuration as detailed on the RequreJS web site and defines the paths and packages that relate AMD module identifiers to JavaScript and other resources, however, instead of specifying web resources, the server-side AMD config specifies URIs to resources on the server. The config file itself is specified as a resource URI. If the URI is not absolute (i.e. protocol specified), then the it is assumed to reside in the OSGi bundle that contains the plugin.xml defining the servlet. Server-side resources are specified using Universal Resource Identifiers (URIs) as specified by the java.net.URI class. The Aggregator provides support for URIs using the standard file protocol for files that reside on the server's file system, and the non-standard, Aggregator defined, namedbundleresource protocol for resources residing in OSGi bundles.
The URI to the server-side AMD config file is specified using the config servlet init-param in the <servlet> element defining the servlet.
The namedbundleresource protocol allows resources to be specified using the bundle symbolic name that the resource is contained in. A namedbundleresource URI looks similar to the following:
namedbundleresource://com.ibm.jaggr.sample.dojo/WebContent/dojo-release-1.8.0-src/dojo
which specifies the resource path dojo within the OSGi bundle with the symbolic name com.ibm.jaggr.sampled.dojo. URIs specified using the namedbundleresource protocol are not universal because multiple resources residing in different bundles using the same symbolic name may exist, and which resource the URI resolves to depends on the behavior of the OSGi class loader as it relates to resolving bundles. This ambiguity violates the rules governing URIs. It is, never the less, convenient to be able to specify resources that reside in named bundles using the URI syntax, so the Aggregator supports the use of the namedbundleresource protocol for URIs specified within the server-side AMD config file. The ambiguity around which bundle to use is dealt with by ensuring that the class loader of the application's bundle (the bundle containing the plugin.xml defining the servlet) is always used to load the bundle whose name is specified in the host part of the URI.
The Aggregator may be extended using the com.ibm.jaggr.service.resourcefactory extension point to support additional URI protocols, providing the ability to extend support to include resources residing within jar files, databases, etc. The default file and namedbundleresource protocols are supported using classes that implement this extension.
Strings of the form ${property-name} may appear anywhere within the config JavaScript and will be replaced with the value of the named property. The value is obtained by calling BundleContext.getPropery() using the BundleContext of the contributing bundle, or if the named property is not defined there, then by calling any registered OSGi services that support the com.ibm.jaggr.service.IVariableResolver interface. Variable property substitution is performed before script evaluation. If a value cannot be found for a named property, then the string is left un-modified.
When the server-side config javascript is being evaluated, the following JavaScript variables are defined and in scope, and may be referenced by JavaScript expressions in your config:
- initParams
- An object of the name-value pairs defined in the servlet-init-params
- options
- An object of the name-value pairs defined in the Aggregator options
- headers
- An object of the name-value pairs specified in the bundle manifest for the contributing bundle (i.e. the bundle that instantiated the servlet)
- console
- An object containing logging methods such as error, warn, info and log. These methods can be used to write messages to the server logs from javascript code in the config
The baseUrl, paths and location properties specify resource URIs which may be either a string value, or a two element array of strings specifying primary and override URIs. The idea behind override URIs is to facilitate product customization by supporting a location on the file system where customized resources may be placed. Resources that exist in the override locations will be used instead of the corresponding resources in the location specified by the primary URI. In this scenario, the primary URI typically specifies an OSGi bundle, using the namedbundleresource URI scheme, while the override URI specifies a customization area on the server's file system.
<table align="left" border="1" cellpadding="1" cellspacing="1" style="width: 99%; margin-bottom: 1em;">
<thead>
<tr>
<th scope="col" style="width: 100px;">
Property Name</th>
<th scope="col">
Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>baseUrl</strong></td>
<td>
<p>
The base URI to use for all relative URIs specified in this config. If <strong>baseUrl</strong> is not absolute, then it is assumed to be relative to the root of the bundle defining the servlet. Note that the property name specifies Url, with a lower-case L, instead of URI with an upper-case i, to maintain symmetry with the client-side config. This property may specify a single URI or primary and override URIs as described in <strong>Override URIs.</strong></p>
<p>
Files and folders located under the folder specified by <strong>baseUrl</strong> are not scanned when the Aggregator builds the module dependency map used for <a href="Require-list-expansion">require list expansion</a> unless the <strong>depsIncludeBaseUrl</strong> property is specified with a value of true.</p>
</td>
</tr>
<tr>
<td>
<strong>paths</strong></td>
<td>
Path mappings for module names to resource URIs. The path URIs are assumed to be relative to baseUrl, unless the URI starts with a "/" or specfies a protocol. Path entries may specify a single URI or primary and override URIs as described in [Override URIs](#overrride). If a relative override is specified, then it is relative to the override URI of the baseUrl property if there is one, else it is relative to the primary URI of the base property.</td>
</tr>
<tr>
<td>
<strong>packages</strong></td>
<td>
Defines the packages for the application. A package can be assocated with a module name/prefix. The package config can specify the following properties for a specific package:
<ul>
<li>
<strong>name</strong>: The name of the package (used for the module name/prefix mapping)</li>
<li>
<strong>location</strong>: The location URI on the server. Locations are relative to the baseUrl configuration value, unless they contain a protocol or start with a front slash (/). Location entries may specify a single URI or primary and override URIs as described in <a href="#override">Override URIs</a>. If a relative override is specified, then it is relative to the override URI of the baseUrl property if there is one, else it is relative to the primary URI of the base property.</li>
<li>
<strong>main</strong>: The module id that should be used when someone does a require for the package. The default value is "./main", so only specify it if it differs from the default. Note that unlike <strong>location</strong>, which specifies the URI to a resource on the server, <strong>main</strong> specifies a module id that is mapped to a server resource using the defined <strong>paths</strong> and <strong>packages</strong>. It may specify a relative module id, in which case it is combined with the package name, or a non-relative module id, in which case it is used as specified.</li>
</ul>
</td>
</tr>
<tr>
<td>
<strong>aliases</strong></td>
<td>
Specifies an array of vector pairs with alias mappings. Each array entry is a two element array with the first element specifying the string to replace, and the second element specify the replacement. Two forms of alias mappings are supported. The first form is a simple string substitution mapping with the first entry specifying the string to replace and the second specifying the string to replace it with. For example:
aliases: [ ["text", "dojo/text"] ]
The second form allows for regular expression pattern mapping and the specification of the replacement as a string or as a function, For replacement functions, the has() function may be called to query the feature set specified in the request. Note that unlike the has() function on the client, this has() function returns either a boolean value, representing the value of the feature on the client after cooercing the value to a boolean type, or undefined if the feature was not specified in the request.
aliases: [ [/^(.*)\/foo\/(.*)$/, "$1/bar/$2"] [/^(.*)\/backend\/(.*)$/, function($0,$1,$2){return $1+(has("foo")?"/foo/":(has("bar")?"/bar/":"/backend/"))+$2;}] ]
Server-side aliases are provided in support of client-side aliases, which are supported by some AMD loaders including the Dojo loader. In general, server-side and client-side aliases should produce the same mappings. Because client-side aliases are resolved on the client before modules are requested, server-side aliases are not used to find requested modules. Instead, they are used in require list expansion, in order to correctly identify dependent modules so that their dependencies may be expanded within the require list of another module. An important significance of this detail is that if the mappings produced by an alias resolver are conditional upon the has.js feature set provided in the request, then the conditioned feature tests must be defined on the client for the request containing the require call that gets expanded to include the aliased module. This can occur well before the request for the aliased module itself. For this reason, server-side alias resolvers should always be implemented in such a way that alias resolution fails (and the module path is not changed) if the tests for the conditioned feature(s) are not yet defined. This will cause the aliased resource's dependencies to not be expanded in the require list (because it won't be found on the server) instead of potentially expanding the dependencies for the wrong module.
Regular expressions specified in alias mappings are evaluated using Java regular expression classes for performance reasons, so you need to be aware of the subtle differences between java and javascript regular expressions.
In addition to the JavaScript variables defined in Scoped variables above, the following variables are defined and in scope and may be referenced by your alias resolver function:
- has - function to test if a specified feature is defined in the feature set provided with the request
- <user-defined> - Any variables that you defined within your server-side config JavaScript and placed in global scope.
Specifies a URI to a resource containing arbitrary text that is included at the beginning of every Aggregator response. The notice text should be in the form of a JavaScript block comment. The Aggregator does not do any processing on the notice text.
If the URI is relative, it is assumed to be relative to the location of the config file.
Aggregator extensions may support additional properties. For example, the CSS module builder supports config properties for controlling in-lining of image references and imported CSS.{ /* * Paths are relative the WebContent folder of the bundle containing this config. */ baseUrl: ['WebContent', '${MYAPP_CUSTOMIZATIONS}'], packages: [ { name: 'dojo', location: ['namedbundleresource://org.dojo-1.7.res/WebContent/dojo', 'dojo'], lib: '.' }, { name: 'dijit', location: ['namedbundleresource://org.dojo-1.7.res/WebContent/dijit', 'dijit'], lib: '.' }, { name: 'dojox', location: ['namedbundleresource://org.dojo-1.7.res/WebContent/dojox', 'dojox'], lib: '.' } ], paths: { "css": "js/css" // uses override path derived from baseUrl (i.e. ${MYAPP_CUSTOMIZATIONS}/js/css) }, expires: 3153600, cacheBust: headers["Bundle-Version"] }
The following example shows how you can define a JavaScript function that can later be called from within an alias resolver function:
(function() { /* Define transform function in global scope */ function transform(a, b, c) { a+(has("foo")?"/foo/":(has("bar")?"/bar/":c))+b }; return { baseUrl: '...', packages: [...], aliases: [ [/^(.*)\/backend\/(.*)$/, function($0,$1,$2){return transform($1, $2, '/backend/');}], ], }; })();