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
