Gang -

I am getting closer to finishing this work.  A new (feature-complete)
patch is available here:

https://issues.apache.org/jira/secure/attachment/12518405/trinidad-skin-pregen-take2.patch

Some more details on the new APIs…

The most interesting API is the uri structure for the skin
pregeneration service/internal view.  This is described in detail in
the class doc for
org.apache.myfaces.trinidadinternal.skin.pregen.SkinPregenerationService
[1], but important enough that I'll inline the doc here:

/**
 * InternalView implementation that provides skin pregeneration service.
 *
 * Skin pregeneration is enabled by specifying the following system
 * property:
 *
 *  -Dorg.apache.myfaces.trinidad.SKIN_PREGENERATION_SERVICE=on
 *
 * When enabled, a request to the "-pregenerate-skins" view id can be
 * used to force pregeneration for specific skins.  Each request must
 * specifiy a single "id" query parameter.  The value of this query parameter
 * must be an id of one of the skins registered with trinidad (eg. via
 * an "id" element in a trinidad-skins.xml file).
 *
 * For example, in an application that uses prefix mapping for the FacesServlet,
 * enabling the skin pregeneration service exposes the following uri:
 *
 *   - /context root/faces/-pregenerate-skins?id=minimal.desktop
 *
 * Which triggers pregeneration of style sheets for the minimal.desktop skin
 * when hit.
 *
 * By default, only style sheets for common variant values are generated.
 * In particular:
 *
 * - plaform: android | iphone | linux | macos | windows
 * - agent: ie | gecko | webkit
 * - locale: default (unmatched) locale
 * - reading direction: ltr
 * - accessibility: standard contrast, medium fonts
 *
 * The "variants" request parameter can be used to force generation of all
 * possible variants, eg:
 *
 *    - "/context root/faces/-pregenerate-skins?id=minimal.desktop?variants=all
 *
 * The following optional request parameters may also be used to
provide contextual
 * information about how the pregeneration should be performed:
 *
 * - containerType: servlet | portlet. (Defaults to "servlet".)
 * - requestType: nonsecure | secure.  (Defaults to "nonsecure".)
 * - styleClassType: compressed | uncompressed.  (Defaults to "compressed".)
 *
 * All of the contextual request parameters support multiple values.
For example,
 * the following request:
 *
 *  
/-pregenerate-skins?id=minimal.desktop&styleClassType=compressed&styleClassType=uncompressed
 *
 * Pregenerates both servlet and portlet style sheets for the common
variants of the the
 * minimal.desktop skin.
 *
 * By default, pregenerated style sheets are written into the web application's
 * style sheet cache directory (typically, tmpdir/adf/styles/cache).  However,
 * a target directory for the pregenerated output can be specified via the
 * following system property:
 *
 * 
-Dorg.apache.myfaces.trinidad.SKIN_PREGENERATION_SERVICE_TARGET_DIRECTORY=directory
path
 *
 *
 * Requests that result in successful skin pregeneration result in status 200
 * responses.  Failed requests (eg. for invalid skin ids) result in non-200
 * status codes.
 *
 * For security purposes, pregeneration must never be enabled in end
user facing,
 * production deployments - ie. skin pregeneration is CPU and I/O intensive, and
 * must not be exposed to arbitrary users.  To avoid the potential for abuse,
 * enabling skin pregeneration has the side effect of disabling the rest of the
 * application.  As such, applications that are enabled for skin pregeneration
 * can only be used for this single purpose.
 */

The other particularly interesting API is the new stable file name
structure for generated style sheets.

This is described in the class doc for StableNameUtils [2], and reproduced here:

/**
 * This class serves one purpose: it provides a replacement for
NameUtils.getContextName()
 * that produces "stable" file names.  This ensures that generated
style sheets will be
 * named in a consistent manner that is not dependent on the order in
which requests arrives.
 *
 * With NameUtils.getContextName(), a skin that contains the following
locale-specific
 * definition:
 *
 * @locale ja, cz, ko { ... }
 *
 * May share a generated .css file across Japanese, Chinese and Korean
end users.  The name
 * of this generated style sheet depends on which locale is specified
when the style sheet is
 * first generated.  For example, if the style sheet is generated in
response from a request
 * for a Korean-locale user, the file name will include the "ko"
locale token.  This file
 * will then be shared by Japanese, Chinese and Korean end users.
However, if the server is
 * subsequently bounced and the first post-bounce request is from a
Japanese end user, the file
 * will be re-generated with the "ja" token.
 *
 * As a result of this behavior, file names are not predictable across
runs.  The lack of
 * stable file names makes it difficult/impossible to support use
cases where we want to
 * share generated style sheets across applications - eg. by
pregenerating style sheets
 * and deploying them to some common server (or a CDN).
 *
 * StableNameUtils.getContextName() solves this problem by producing
names for generated
 * style sheet files that are not dependent on request ordering.
 *
 * The file names produced by StableNameUtils.getContextName() are
broken up into three
 * major sections:
 *
 * 1. The skin identifier.
 * 2. Variant identifiers (eg. agent, locale, etc...)
 * 3. Contextual identifiers (eg. portlet vs. servlet)
 *
 * These major sections are separated by double dashes ("--").
 *
 * Within each major section, minor subsections appear in a
predictable order, separated
 * by single dashs ("-").
 *
 * The skin identifier section (section #1) contains the following subsections:
 *
 *   <id>-<hash>
 *
 * Where:
 *
 * - id: the skin id.  Note that the skin id itself may include dash characters
 *     (eg. "simple-desktop").
 * - hash: a hash of the skin contents
 *
 * The variant identifiers section (section #2) contains the following
subsections:
 *
 *   <platform>-<agent>-<version>-<locale>-<direction>-<accessibility>
 *
 * Where:
 *
 * - platform: the platform name (eg. linux, windows, iphone)
 * - agent: the agent name (eg. ie, gecko, safari)
 * - version: the agent version (eg. 7, 1.9.2, 534)
 * - locale: the locale (eg. en, en_US, ja).
 * - direction: the reading direction (ltr|rtl)
 * - accessibility: accessibility profile preferences (hc|lf|hclf for
high contrast|
 *     large fonts|high contrast + large fonts).
 *
 * These fields all support two additional values:
 *
 * - Default: in the event that no @-rule variant is expicitly
matched, only default styles
 *    (ie. styles that apply to all requests) are included in the
generated style sheet.
 *   The token "d" is used to identify this case.  For example, if the
skin does not
 *   define any @locale rules, the locale portion of the file name will be "d".
 *
 * - Multiple: In some cases it is not possible to determine a unique value
 *   for a particular variant, because only @-rules that specify multiple values
 *   are matched.  The token "x" is used to identify such cases.  For
example, if the
 *   skin defines a single @locale rule matching the ja, cz, and ko
locales, the
 *   locale portion of the file name for generated style sheets
corresponding to these
 *   locales will be "x".
 *
 * The contextual identifiers section (section #3) contains the
following subsections:
 *
 * - container type: identifies whether the application is hosted
within a servlet or
 *     portlet (s|p).
 * - request type: identifies whether the style sheet is used for a
secure or non-secure
 *     request (s|n).
 * - style class type: identifies whether the style sheet is generated
with compressed or
 *     uncompressed style classes (c|u).
 *
 * In case where skins are pregenerated and shared across
applications, it may be necessary
 * to write regular expressions against the above format in order to
rewrite style sheet
 * uris to point to some other host.  When doing so, the following
recommendations should
 * be observed:
 *
 * - The identifier section contains a variable number of subsection
separators: skin
 *   ids may contain dashes.  As such, when writing regular
expressions that target items
 *   in the subsequent major sections, it is best to anchor these
regular expressions
 *   to the major section separators (double-dash).
 *
 * - In the future it is possible that new subsections may need to be
added to the
 *   variant or contextual identifier sections.  If the need for additional
 *   information arises, new subsections will be added at the end of
the appropriate
 *   major section.  As such, regular expressions should be written in
a way that they
 *   can tolerate new subsections later appearing at the end of each
major section.
 */

Stable names are enabled via the following context parameter:

 - org.apache.myfaces.trinidad.STYLE_SHEET_NAMING_STRATEGY: short | stable

Where "short" matches our existing behavior and is the default.

Note that when performing skin pregeneration, the naming strategy is
automatically forced to "stable", since pregenerating non-stable names
is not useful.

In addition to the above new APIs, I introduced several supporting
utility classes under org.apache.myfaces.trinidad.util:

- Args [3]: Utilities for method argument processing.  At the moment,
just one utility method for verifying that an argument is non-null.
- Enums [4]: Utilities for supporting enum implementations,
particularly for enums that use some String alias other than the
canonical enum constant name.
- FileUtils [5]: File processing utilities.  At the moment, just one
utility method for verifying that a String path corresponds to an
existing, writable directory.
- Range [6]: A non-lame (immutable, genericized) replacement for
org.apache.myfaces.trinidadinternal.util.Range.

Finally, I added some new methods and constants to
org.apache.myfaces.trinidad.context.Version [7], including:

- MIN_VERSION constant: lower bound on Versions.
- MAX_VERSION constant: upper bound on Versions.
- ALL_VERSIONS: a Range<Version> from MIN_VERSION to MAX_VERSION
- toMinimumVersion(): converts a wildcard version to the minimum
possible version (removing any wildcards in the process).
- toMaximumVersion(): converts a wildcard version to the maximum
possible version (removing wildcards).

Think that's it for new APIs.

Please let me know if you have any comments/questions!

Andy

[1] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java
[2] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/StableNameUtils.java
[3] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/Args.java
[4] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/Enums.java
[5] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/FileUtils.java
[6] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/Range.java
[7] 
http://svn.apache.org/repos/asf/myfaces/trinidad/branches/andys-skin-pregen/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/Version.java

Reply via email to