You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/04/19 16:05:17 UTC

svn commit: r935580 [1/2] - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/ main/java/org/apache/tapestry5/internal/ main/java/org/apache/tapestry5/internal/services/ main/java/org/apache/tapestry5/internal/services/ajax...

Author: hlship
Date: Mon Apr 19 14:05:16 2010
New Revision: 935580

URL: http://svn.apache.org/viewvc?rev=935580&view=rev
Log:
Mid-way through the conversion from virtual assets to JavaScript stack assets: JavaScript aggregation not yet re-implemented, many tests fail, but basic functionality is working

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavascriptStack.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructor.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructorImpl.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackSourceImpl.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavascriptStack.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavascriptStackSource.java   (with props)
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/VirtualAssetStreamer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/VirtualAssetStreamerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/VirtualAssetRequestHandler.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/RenderSupport.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientInfrastructureImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderSupportImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavascriptSupportImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientInfrastructure.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavascriptSupport.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RenderSupportImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/RenderSupport.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/RenderSupport.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/RenderSupport.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/RenderSupport.java Mon Apr 19 14:05:16 2010
@@ -116,7 +116,7 @@ public interface RenderSupport
      * @param stylesheetURL
      *            URL string of stylesheet
      * @param media
-     *            media value fo the stylesheet, or null to not specify a specific media type
+     *            media value for the stylesheet, or null to not specify a specific media type
      */
     void addStylesheetLink(String stylesheetURL, String media);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java Mon Apr 19 14:05:16 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,15 +14,19 @@
 
 package org.apache.tapestry5;
 
+import org.apache.tapestry5.internal.services.AssetDispatcher;
+import org.apache.tapestry5.services.assets.AssetPathConstructor;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
+
 /**
  * Defines the names of symbols used to configure Tapestry.
- *
+ * 
  * @see org.apache.tapestry5.ioc.services.SymbolSource
  */
 public class SymbolConstants
 {
     /**
-     * Indicates whether Tapestry is running in production mode or developer mode.  The primary difference is how
+     * Indicates whether Tapestry is running in production mode or developer mode. The primary difference is how
      * exceptions are reported.
      */
     public static final String PRODUCTION_MODE = "tapestry.production-mode";
@@ -34,7 +38,7 @@ public class SymbolConstants
 
     /**
      * If set to "true", then action requests will render a page markup response immediately, rather than sending a
-     * redirect to render the response.  "Action request" is an outdated term for "component event request" (i.e., most
+     * redirect to render the response. "Action request" is an outdated term for "component event request" (i.e., most
      * links and all form submissions).
      */
     public static final String SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS = "tapestry.suppress-redirect-from-action-requests";
@@ -78,7 +82,7 @@ public class SymbolConstants
     public static final String APPLICATION_CATALOG = "tapestry.app-catalog";
 
     /**
-     * The  charset used when rendering page markup; the charset is also used as the request encoding when handling
+     * The charset used when rendering page markup; the charset is also used as the request encoding when handling
      * incoming requests. The default is "UTF-8".
      */
     public static final String CHARSET = "tapestry.charset";
@@ -91,16 +95,17 @@ public class SymbolConstants
     public static final String FORM_CLIENT_LOGIC_ENABLED = "tapestry.form-client-logic-enabled";
 
     /**
-     * Name of page used to report exceptions; the page must implement {@link org.apache.tapestry5.services.ExceptionReporter}.
+     * Name of page used to report exceptions; the page must implement
+     * {@link org.apache.tapestry5.services.ExceptionReporter}.
      * This is used by the default exception report handler service.
      */
     public static final String EXCEPTION_REPORT_PAGE = "tapestry.exception-report-page";
 
     /**
      * If true, then links for external JavaScript libraries are placed at the top of the document (just inside the
-     * <body> element).  If false, the default, then the libraries are placed at the bottom of the document.
+     * <body> element). If false, the default, then the libraries are placed at the bottom of the document.
      * Per-page initialization always goes at the bottom.
-     *
+     * 
      * @deprecated since 5.1.0.1; scripts are now always at the top (see TAP5-544)
      */
     public static final String SCRIPTS_AT_TOP = "tapestry.script-at-top";
@@ -108,35 +113,37 @@ public class SymbolConstants
     /**
      * Identifies the default persistence strategy for all pages that do not provide an override (using this value as
      * {@link org.apache.tapestry5.annotations.Meta key}).
-     *
+     * 
      * @since 5.1.0.0
      */
     public static final String PERSISTENCE_STRATEGY = "tapestry.persistence-strategy";
 
-
     /**
      * Minimum output stream size, in bytes, before output is compressed using GZIP. Shorter streams are not compressed.
      * Tapestry buffers this amount and switches to a GZIP output stream as needed. The default is "100".
-     *
+     * 
      * @see #GZIP_COMPRESSION_ENABLED
      * @since 5.1.0.0
      */
     public static final String MIN_GZIP_SIZE = "tapestry.min-gzip-size";
 
     /**
-     * Version number integrated into URLs for context assets. This should be changed for each release, otherwise
+     * Version number integrated into URLs for assets. This should be changed for each release, otherwise
      * out-of-date files may be used from the client's local cache (due to far-future expired headers). The default
-     * value is semi-random and different for each execution, which will adversely affect client caching, but is reasonable
+     * value is semi-random and different for each execution, which will adversely affect client caching, but is
+     * reasonable
      * for development.
-     *
+     * 
      * @since 5.1.0.0
+     * @see AssetDispatcher
+     * @see AssetPathConstructor
      */
     public static final String APPLICATION_VERSION = "tapestry.application-version";
 
     /**
      * Used to omit the normal Tapestry framework generator meta tag. The meta tag is rendered by default, but clients
      * who do not wish to advertise their use of Tapestry may set this symbol to "true".
-     *
+     * 
      * @since 5.1.0.0
      */
     public static final String OMIT_GENERATOR_META = "tapestry.omit-generator-meta";
@@ -145,7 +152,7 @@ public class SymbolConstants
      * If "true" (the default) then GZip compression is enabled for dynamic requests and for static assets. If you are
      * using a server that handles GZip compression for you, or you don't want to ue the extra processing power
      * necessary to GZIP requests, then override this to "false".
-     *
+     * 
      * @see #MIN_GZIP_SIZE
      * @since 5.1.0.0
      */
@@ -153,9 +160,9 @@ public class SymbolConstants
 
     /**
      * If "true" (which itself defaults to production mode), then the {@link org.apache.tapestry5.annotations.Secure}
-     * annotation will be honored.  If "false" (i.e., development mode), then the annotation and related HTTP/HTTPS
+     * annotation will be honored. If "false" (i.e., development mode), then the annotation and related HTTP/HTTPS
      * logic is ignored.
-     *
+     * 
      * @since 5.1.0.1
      */
     public static final String SECURE_ENABLED = "tapestry.secure-enabled";
@@ -163,131 +170,126 @@ public class SymbolConstants
     /**
      * If "true" (the default), then the {@link org.apache.tapestry5.services.PersistentLocale} will be encoded into the
      * {@link org.apache.tapestry5.Link} path by the {@link org.apache.tapestry5.services.ComponentEventLinkEncoder}
-     * service. If overriden to "false" this does not occur, but you should provide a {@link
-     * org.apache.tapestry5.services.LinkCreationListener} (registered with the {@link
-     * org.apache.tapestry5.services.LinkCreationHub}) in order to add the locale as a query parameter (or provide some
-     * alternate means of persisting the locale between requests).
-     *
+     * service. If overridden to "false" this does not occur, but you should provide a
+     * {@link org.apache.tapestry5.services.LinkCreationListener} (registered with the
+     * {@link org.apache.tapestry5.services.LinkCreationHub}) in order to add the locale as a query parameter (or
+     * provide some alternate means of persisting the locale between requests).
+     * 
      * @since 5.1.0.1
      */
     public static final String ENCODE_LOCALE_INTO_PATH = "tapestry.encode-locale-into-path";
 
     /**
-     * If "true" then JavaScript files will be combined into a single virtual JavaScript file. Defaults to "true" is
-     * production mode.
-     *
+     * If "true" then Javascript files in a {@link JavascriptStack} will be combined into a single virtual JavaScript
+     * file. Defaults to "true" in production mode.
+     * 
      * @since 5.1.0.2
      */
     public static final String COMBINE_SCRIPTS = "tapestry.combine-scripts";
 
     /**
      * If "true" then Blackbird JavaScript console is enabled.
-     *
-     * @since 5.2.0.0
+     * 
+     * @since 5.2.0
      */
     public static final String BLACKBIRD_ENABLED = "tapestry.blackbird-enabled";
 
     /**
-     * The default time interval that cookies created by Tapestry will be kept in the client web browser. The default is "7 d" (that is, seven days).
-     *
-     * @since 5.2.0.0
+     * The default time interval that cookies created by Tapestry will be kept in the client web browser. The default is
+     * "7 d" (that is, seven days).
+     * 
+     * @since 5.2.0
      */
     public static final String COOKIE_MAX_AGE = "tapestry.default-cookie-max-age";
 
     /**
      * The logical name of the start page, the page that is rendered for the root URL.
-     *
-     * @since 5.2.0.0
+     * 
+     * @since 5.2.0
      */
     public static final String START_PAGE_NAME = "tapestry.start-page-name";
-    
 
     /**
-     * The default stylesheet automatically injected into every rendered HTML page. 
-     *
-     * @since 5.2.0.0
+     * The default stylesheet automatically injected into every rendered HTML page.
+     * 
+     * @since 5.2.0
      */
     public static final String DEFAULT_STYLESHEET = "tapestry.default-stylesheet";
-    
 
     /**
-     * The number of pages in the page pool (for a given page name / locale combination) before which Tapestry will start to wait for existing pages to be made available. 
-     * Under this limit of pages, Tapestry will simply create a new page instance if no existing instance is readily available. 
-     * Once the soft limit is reached, Tapestry will wait a short period of time (the soft wait interval) to see if an existing page 
-     * instance is made available. It will then create a new page instance (unless the hard limit has been reached). 
-     * The default is 5 page instances. Remember that page pooling is done separately for each page (and localization of the page). 
-     *
-     * @since 5.2.0.0
+     * The number of pages in the page pool (for a given page name / locale combination) before which Tapestry will
+     * start to wait for existing pages to be made available.
+     * Under this limit of pages, Tapestry will simply create a new page instance if no existing instance is readily
+     * available.
+     * Once the soft limit is reached, Tapestry will wait a short period of time (the soft wait interval) to see if an
+     * existing page
+     * instance is made available. It will then create a new page instance (unless the hard limit has been reached).
+     * The default is 5 page instances. Remember that page pooling is done separately for each page (and localization of
+     * the page).
+     * 
+     * @since 5.2.0
      */
     public static final String PAGE_POOL_SOFT_LIMIT = "tapestry.page-pool.soft-limit";
-    
 
     /**
-     * The absolute maximum number of page instances (for a particular page name / locale combination) that Tapestry will create at any time. 
-     * If this number is reached, then requests will fail because a page instance is not available ... this can happen as part of a denial of service attack. 
-     * For this value to have any meaning, it should be lower than the number of threads that the servlet container is configured to use when processing requests. 
-     * The default is 20 page instances. 
-     *
-     * @since 5.2.0.0
+     * The absolute maximum number of page instances (for a particular page name / locale combination) that Tapestry
+     * will create at any time.
+     * If this number is reached, then requests will fail because a page instance is not available ... this can happen
+     * as part of a denial of service attack.
+     * For this value to have any meaning, it should be lower than the number of threads that the servlet container is
+     * configured to use when processing requests.
+     * The default is 20 page instances.
+     * 
+     * @since 5.2.0
      */
     public static final String PAGE_POOL_HARD_LIMIT = "tapestry.page-pool.hard-limit";
-    
 
     /**
-     * The time interval that Tapestry will wait for a page instance to become available before deciding whether to create an entirely new page instance. 
+     * The time interval that Tapestry will wait for a page instance to become available before deciding whether to
+     * create an entirely new page instance.
      * The default is "10 ms".
-     *
-     * @since 5.2.0.0
+     * 
+     * @since 5.2.0
      */
     public static final String PAGE_POOL_SOFT_WAIT = "tapestry.page-pool.soft-wait";
-    
 
     /**
-     * The time interval that an instantiated page instance may be cached before being removed. As pages are returned to the pool, they are time stamped. 
-     * Periodically (as per the file check interval), the pool is scanned for page instances that have not been used recently; those that are outside the 
-     * active window are discarded. This is used to free up unnecessary page instances after a request surge. The default is "10 m" (10 minutes).
-     *
-     * @since 5.2.0.0
+     * The time interval that an instantiated page instance may be cached before being removed. As pages are returned to
+     * the pool, they are time stamped.
+     * Periodically (as per the file check interval), the pool is scanned for page instances that have not been used
+     * recently; those that are outside the
+     * active window are discarded. This is used to free up unnecessary page instances after a request surge. The
+     * default is "10 m" (10 minutes).
+     * 
+     * @since 5.2.0
      */
-    public static final String PAGE_POOL_ACTIVE_WINDOW  = "tapestry.page-pool.active-window";
-    
+    public static final String PAGE_POOL_ACTIVE_WINDOW = "tapestry.page-pool.active-window";
 
     /**
-     * The path to the embedded copy of script.aculo.us packaged with Tapestry.
-     *
-     * @since 5.2.0.0
+     * The Asset path to the embedded copy of script.aculo.us packaged with Tapestry.
+     * 
+     * @since 5.2.0
      */
-    public static final String SCRIPTACULOUS  = "tapestry.scriptaculous";
-    
+    public static final String SCRIPTACULOUS = "tapestry.scriptaculous";
 
     /**
-     * The path to the embedded datepicker.
-     *
-     * @since 5.2.0.0
+     * The Asset path to the embedded datepicker.
+     * 
+     * @since 5.2.0
      */
-    public static final String DATEPICKER  = "tapestry.datepicker";
-    
+    public static final String DATEPICKER = "tapestry.datepicker";
 
     /**
-     * The path to the embedded copy of blackbird packaged with Tapestry.
-     *
-     * @since 5.2.0.0
+     * The Asset path to the embedded copy of blackbird packaged with Tapestry.
+     * 
+     * @since 5.2.0
      */
-    public static final String BLACKBIRD  = "tapestry.blackbird";
+    public static final String BLACKBIRD = "tapestry.blackbird";
 
     /**
-     * Whether assets in the web application's context directory are available by default.
-     * If true (the default), tapestry will provide conributions to the appropriate services (RegexAuthorizer) to allow access
-     * to .js, .jpg, .jpeg, .png, .gif, and .css assets that reside within the application context.
-     * If false, no such contributions will be made, and access to those resources will be restricted
-     * without explicit user contributions.
-     */
-    public static final String CONTEXT_ASSETS_AVAILABLE ="tapestry.context-assets-available";
-    
-    /**
-     * The default javascript (tapestry.js) automatically injected into every rendered HTML page. 
-     *
-     * @since 5.2.0.0
+     * The default javascript (tapestry.js) automatically injected into every rendered HTML page.
+     * 
+     * @since 5.2.0
      */
     public static final String DEFAULT_JAVASCRIPT = "tapestry.default-javascript";
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java Mon Apr 19 14:05:16 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,6 +16,7 @@ package org.apache.tapestry5.internal;
 
 import org.apache.tapestry5.internal.structure.PageResetListener;
 import org.apache.tapestry5.ioc.util.TimeInterval;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
 
 public final class InternalConstants
 {
@@ -32,8 +33,7 @@ public final class InternalConstants
     public static final String DISABLE_DEFAULT_MODULES_PARAM = "tapestry.disable-default-modules";
 
     /**
-     * The extension used for Tapestry component template files, <em>T</em>apestry <em>M</em>arkup
-     * <em>L</em>anguage.
+     * The extension used for Tapestry component template files, <em>T</em>apestry <em>M</em>arkup <em>L</em>anguage.
      * Template files are well-formed XML files.
      */
     public static final String TEMPLATE_EXTENSION = "tml";
@@ -62,8 +62,8 @@ public final class InternalConstants
      * Name of query parameter that is placed on "loopback" links (page render links for the same
      * page). This mostly includes the redirects sent after a component event request. Page render
      * requests
-     * that do <em>not</em> have the LOOPBACK query parameter will trigger a
-     * {@linkplain PageResetListener reset notification} after the initialization event; the
+     * that do <em>not</em> have the LOOPBACK query parameter will trigger a {@linkplain PageResetListener reset
+     * notification} after the initialization event; the
      * LOOPBACK
      * prevents this reset notification.
      * 
@@ -93,18 +93,15 @@ public final class InternalConstants
     /**
      * Request attribute that stores a {@link org.apache.tapestry5.internal.structure.Page} instance
      * that will be
-     * rendered as the
-     * {@linkplain org.apache.tapestry5.SymbolConstants#SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS
+     * rendered as the {@linkplain org.apache.tapestry5.SymbolConstants#SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS
      * immediate
      * mode response}.
      */
     public static final String IMMEDIATE_RESPONSE_PAGE_ATTRIBUTE = "tapestry.immediate-response-page";
 
     /**
-     * Request attribute that forces
-     * {@link org.apache.tapestry5.internal.services.RequestPathOptimizer} to use not
-     * optimize URLs (this is necessitated by
-     * {@link org.apache.tapestry5.services.PageDocumentGenerator}). Any non-null
+     * Request attribute that forces {@link org.apache.tapestry5.internal.services.RequestPathOptimizer} to use not
+     * optimize URLs (this is necessitated by {@link org.apache.tapestry5.services.PageDocumentGenerator}). Any non-null
      * value will force the URLs to be non-optimized.
      */
     public static final String GENERATING_RENDERED_PAGE = "tapestry.generating-rendered-page";
@@ -149,6 +146,13 @@ public final class InternalConstants
      */
     public static final String INHERIT_BINDING_PREFIX = "inherit:";
     public static final long TEN_YEARS = new TimeInterval("10y").milliseconds();
-        
+
     public static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Name of the core {@link JavascriptStack}.
+     * 
+     * @since 5.2.0
+     */
+    public static final String CORE_STACK_NAME = "core";
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientInfrastructureImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientInfrastructureImpl.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientInfrastructureImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientInfrastructureImpl.java Mon Apr 19 14:05:16 2010
@@ -1,10 +1,10 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +14,10 @@
 
 package org.apache.tapestry5.internal.services;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
 import org.apache.tapestry5.Asset;
 import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.annotations.Symbol;
@@ -23,13 +27,9 @@ import org.apache.tapestry5.ioc.services
 import org.apache.tapestry5.services.AssetSource;
 import org.apache.tapestry5.services.ClientInfrastructure;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
 /**
  * The default Javascript Stack consists of Prototype, Scriptaculous & the Tapestry-specific library.
- *
+ * 
  * @since 5.1.0.2
  */
 public class ClientInfrastructureImpl implements ClientInfrastructure
@@ -41,34 +41,33 @@ public class ClientInfrastructureImpl im
     private final ThreadLocale threadLocale;
 
     private final List<Asset> javascriptStack, stylesheetStack;
-    
+
     private final Asset consoleJavascript, consoleStylesheet;
-    
+
     private final boolean isBlackbirdEnabled;
 
     private static final String[] CORE_JAVASCRIPT = new String[]
-            {
-                    // Core scripts added to any page that uses scripting
+    {
+    // Core scripts added to any page that uses scripting
 
-                    "${tapestry.scriptaculous}/prototype.js",
-                    "${tapestry.scriptaculous}/scriptaculous.js",
-                    "${tapestry.scriptaculous}/effects.js",
-
-                    // Uses functions defined by the prior three
-
-                    "${tapestry.default-javascript}",
-            };
-
-    private static final String[] CORE_STYLESHEET = new String[]
-            {
-                    "${tapestry.default-stylesheet}",
-            };
-
-    public ClientInfrastructureImpl(SymbolSource symbolSource, 
-                                    AssetSource assetSource,
-                                    ThreadLocale threadLocale,
-                                    @Symbol(SymbolConstants.BLACKBIRD_ENABLED)
-                                    boolean isBlackbirdEnabled)
+            "${tapestry.scriptaculous}/prototype.js",
+
+            "${tapestry.scriptaculous}/scriptaculous.js",
+
+            "${tapestry.scriptaculous}/effects.js",
+
+            // Uses functions defined by the prior three
+
+            "${tapestry.default-javascript}", };
+
+    // Because of changes to the logic of how stylesheets get incorporated, the default stylesheet
+    // was removed, the logic for it is now in TapestryModule.contributeMarkupRenderer().
+
+    private static final String[] CORE_STYLESHEET = new String[0];
+
+    public ClientInfrastructureImpl(SymbolSource symbolSource, AssetSource assetSource, ThreadLocale threadLocale,
+            @Symbol(SymbolConstants.BLACKBIRD_ENABLED)
+            boolean isBlackbirdEnabled)
     {
         this.symbolSource = symbolSource;
         this.assetSource = assetSource;
@@ -77,9 +76,11 @@ public class ClientInfrastructureImpl im
 
         javascriptStack = convertToAssets(CORE_JAVASCRIPT);
         stylesheetStack = convertToAssets(CORE_STYLESHEET);
-        
-        consoleJavascript = expand("${tapestry.blackbird}/blackbird.js", "org/apache/tapestry5/tapestry-console.js", null);
-        consoleStylesheet = expand("${tapestry.blackbird}/blackbird.css", "org/apache/tapestry5/tapestry-console.css", null);
+
+        consoleJavascript = expand("${tapestry.blackbird}/blackbird.js", "org/apache/tapestry5/tapestry-console.js",
+                null);
+        consoleStylesheet = expand("${tapestry.blackbird}/blackbird.css", "org/apache/tapestry5/tapestry-console.css",
+                null);
     }
 
     private List<Asset> convertToAssets(String[] paths)
@@ -100,18 +101,18 @@ public class ClientInfrastructureImpl im
 
         return assetSource.getAsset(null, expanded, locale);
     }
-    
+
     private Asset expand(String blackbirdPath, String consolePath, Locale locale)
     {
-        String path = isBlackbirdEnabled? blackbirdPath: consolePath;
+        String path = isBlackbirdEnabled ? blackbirdPath : consolePath;
 
         return expand(path, locale);
     }
 
     public List<Asset> getJavascriptStack()
     {
-        Asset messages = assetSource.getAsset(null, "org/apache/tapestry5/tapestry-messages.js",
-                                              threadLocale.getLocale());
+        Asset messages = assetSource.getAsset(null, "org/apache/tapestry5/tapestry-messages.js", threadLocale
+                .getLocale());
 
         return createStack(javascriptStack, messages, consoleJavascript);
     }
@@ -120,11 +121,11 @@ public class ClientInfrastructureImpl im
     {
         return createStack(stylesheetStack, consoleStylesheet);
     }
-    
+
     public List<Asset> createStack(List<Asset> stack, Asset... assets)
     {
         List<Asset> result = CollectionFactory.newList(stack);
-        
+
         for (Asset next : assets)
         {
             result.add(next);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java Mon Apr 19 14:05:16 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,24 +21,27 @@ package org.apache.tapestry5.internal.se
 public interface DocumentLinker
 {
     /**
-     * Adds a link to load a script. Scripts will be loaded only once.  The &lt;script&gt; elements will be added at the
-     * top or bottom of the &lt;body&gt; element (the location is configurable).
+     * Adds a link to load a JavaScript library. . The &lt;script&gt; elements will be added inside
+     * the document's &lt;head&gt;.
      */
     void addScriptLink(String scriptURL);
 
     /**
-     * Adds a link to load a CSS stylesheet. Stylesheets are loaded only once.
-     *
-     * @param styleURL URL of stylesheet to load
-     * @param media    media value (or null to omit the media attribute)
+     * Adds a link to load a CSS stylesheet.
+     * 
+     * @param styleURL
+     *            URL of stylesheet to load
+     * @param media
+     *            media value (or null to omit the media attribute)
      */
     void addStylesheetLink(String styleURL, String media);
 
     /**
      * Adds JavaScript code. The code is collected into a single block that is injected just before the close body tag
      * of the page.
-     *
-     * @param script statement to add to the block (a newline will be appended as well)
+     * 
+     * @param script
+     *            statement to add to the block (a newline will be appended as well)
      */
     void addScript(String script);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java Mon Apr 19 14:05:16 2010
@@ -14,19 +14,14 @@
 
 package org.apache.tapestry5.internal.services;
 
+import java.util.List;
+
 import org.apache.tapestry5.dom.Document;
 import org.apache.tapestry5.dom.Element;
 import org.apache.tapestry5.dom.Node;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.services.ClientDataEncoder;
-import org.apache.tapestry5.services.ClientDataSink;
-import org.apache.tapestry5.services.assets.AssetPathConstructor;
-
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.util.List;
-import java.util.Set;
+import org.apache.tapestry5.ioc.internal.util.Func;
+import org.apache.tapestry5.ioc.internal.util.Operation;
 
 public class DocumentLinkerImpl implements DocumentLinker
 {
@@ -34,84 +29,33 @@ public class DocumentLinkerImpl implemen
 
     private final StringBuilder scriptBlock = new StringBuilder();
 
-    private final Set<String> stylesheets = CollectionFactory.newSet();
-
     private final List<IncludedStylesheet> includedStylesheets = CollectionFactory.newList();
 
-    private final boolean developmentMode;
-
     private final boolean omitGeneratorMetaTag;
 
     private final String tapestryBanner;
 
-    private final ClientDataEncoder clientDataEncoder;
-
-    private boolean combineScripts;
-
-    /**
-     * Full asset path prefix, including the request context path.
-     */
-    private final String fullAssetPrefix;
-
-    private final int contextPathLength;
-
-    private final AssetPathConstructor assetPathConstructor;
-
     /**
-     * @param productionMode
-     *            via symbol configuration
      * @param omitGeneratorMetaTag
      *            via symbol configuration
      * @param tapestryVersion
      *            version of Tapestry framework (for meta tag)
-     * @param combineScripts
-     *            if true, individual JavaScript assets will be combined into a single virtual asset
-     * @param contextPath
-     *            {@link org.apache.tapestry5.services.Request#getContextPath()}
-     * @param clientDataEncoder
-     *            used to encode data for the combined virtual asset
-     * @param assetPathConstructor
-     *            TODO
      */
-    public DocumentLinkerImpl(boolean productionMode, boolean omitGeneratorMetaTag, String tapestryVersion,
-            boolean combineScripts, String contextPath, ClientDataEncoder clientDataEncoder,
-            AssetPathConstructor assetPathConstructor)
-    {
-        this.combineScripts = combineScripts;
-        this.clientDataEncoder = clientDataEncoder;
-        this.assetPathConstructor = assetPathConstructor;
-
-        developmentMode = !productionMode;
+    public DocumentLinkerImpl(boolean omitGeneratorMetaTag, String tapestryVersion)
+    {
         this.omitGeneratorMetaTag = omitGeneratorMetaTag;
 
         tapestryBanner = String.format("Apache Tapestry Framework (version %s)", tapestryVersion);
-
-        fullAssetPrefix = contextPath + RequestConstants.ASSET_PATH_PREFIX;
-
-        contextPathLength = contextPath.length();
     }
 
     public void addStylesheetLink(String styleURL, String media)
     {
-        if (stylesheets.contains(styleURL))
-            return;
-
         includedStylesheets.add(new IncludedStylesheet(styleURL, media));
-
-        stylesheets.add(styleURL);
     }
 
     public void addScriptLink(String scriptURL)
     {
-        if (scripts.contains(scriptURL))
-            return;
-
         scripts.add(scriptURL);
-
-        // If a script with an external URL is added, we can't combine the scripts after all.
-
-        if (combineScripts && !scriptURL.startsWith(fullAssetPrefix))
-            combineScripts = false;
     }
 
     public void addScript(String script)
@@ -134,7 +78,6 @@ public class DocumentLinkerImpl implemen
         if (root == null)
             return;
 
-        if (!stylesheets.isEmpty())
             addStylesheetsToHead(root, includedStylesheets);
 
         // only add the generator meta only to html documents
@@ -193,17 +136,12 @@ public class DocumentLinkerImpl implemen
      */
     protected void addDynamicScriptBlock(Element body)
     {
-        boolean blockNeeded = (developmentMode && !scripts.isEmpty()) || scriptBlock.length() > 0;
-
-        if (blockNeeded)
-        {
-            Element e = body.element("script", "type", "text/javascript");
+        if (scriptBlock.length() == 0)
+            return;
 
-            if (developmentMode)
-                e.raw("Tapestry.DEBUG_ENABLED = true;\n");
+        Element e = body.element("script", "type", "text/javascript");
 
-            e.raw(scriptBlock.toString());
-        }
+        e.raw(scriptBlock.toString());
     }
 
     /**
@@ -218,17 +156,15 @@ public class DocumentLinkerImpl implemen
     {
         Element existing = findExistingElement(container, "script");
 
-        Element scriptContainer = container.element("script-container");
+        final Element scriptContainer = container.element("script-container");
 
-        if (combineScripts)
-        {
-            addCombinedScriptLink(scriptContainer, scripts);
-        }
-        else
+        Func.each(scripts, new Operation<String>()
         {
-            for (String scriptURL : scripts)
+            public void op(String scriptURL)
+            {
                 scriptContainer.element("script", "type", "text/javascript", "src", scriptURL);
-        }
+            }
+        });
 
         if (existing != null)
             scriptContainer.moveBefore(existing);
@@ -236,37 +172,6 @@ public class DocumentLinkerImpl implemen
         scriptContainer.pop();
     }
 
-    private void addCombinedScriptLink(Element container, List<String> scripts)
-    {
-        try
-        {
-            ClientDataSink dataSink = clientDataEncoder.createSink();
-
-            ObjectOutputStream stream = dataSink.getObjectOutputStream();
-
-            stream.writeInt(scripts.size());
-
-            for (String scriptURL : scripts)
-            {
-                // Each scriptURL will be prefixed with the context path, which isn't needed to build the combined
-                // virtual
-                // asset (in fact, it gets in the way).
-
-                stream.writeUTF(scriptURL.substring(contextPathLength));
-            }
-
-            String virtualURL = assetPathConstructor.constructAssetPath(RequestConstants.VIRTUAL_FOLDER, dataSink
-                    .getEncodedClientData()
-                    + ".js");
-
-            container.element("script", "type", "text/javascript", "src", virtualURL);
-        }
-        catch (IOException ex)
-        {
-            throw new RuntimeException(ex);
-        }
-    }
-
     /**
      * Locates the head element under the root ("html") element, creating it if necessary, and adds the stylesheets to
      * it.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java Mon Apr 19 14:05:16 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,6 +18,7 @@ import javax.servlet.http.Cookie;
 
 import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.pageload.PageLoaderImpl;
+import org.apache.tapestry5.internal.services.javascript.JavascriptStackPathConstructor;
 import org.apache.tapestry5.internal.structure.ComponentPageElementResourcesSource;
 import org.apache.tapestry5.internal.structure.ComponentPageElementResourcesSourceImpl;
 import org.apache.tapestry5.ioc.ObjectLocator;
@@ -33,19 +34,7 @@ import org.apache.tapestry5.ioc.services
 import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
 import org.apache.tapestry5.ioc.services.PerthreadManager;
 import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
-import org.apache.tapestry5.services.AssetFactory;
-import org.apache.tapestry5.services.ComponentClassResolver;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.ComponentMessages;
-import org.apache.tapestry5.services.ComponentTemplates;
-import org.apache.tapestry5.services.ContextProvider;
-import org.apache.tapestry5.services.Core;
-import org.apache.tapestry5.services.InvalidationEventHub;
-import org.apache.tapestry5.services.LocalizationSetter;
-import org.apache.tapestry5.services.RequestGlobals;
-import org.apache.tapestry5.services.ResponseCompressionAnalyzer;
-import org.apache.tapestry5.services.UpdateListenerHub;
+import org.apache.tapestry5.services.*;
 import org.slf4j.Logger;
 
 /**
@@ -61,18 +50,16 @@ public class InternalModule
 
     private final InvalidationEventHub classesInvalidationEventHub;
 
-    public InternalModule(UpdateListenerHub updateListenerHub,
-                          RequestGlobals requestGlobals,
+    public InternalModule(UpdateListenerHub updateListenerHub, RequestGlobals requestGlobals,
 
-                          @ComponentClasses
-                          InvalidationEventHub classesInvalidationEventHub)
+    @ComponentClasses
+    InvalidationEventHub classesInvalidationEventHub)
     {
         this.updateListenerHub = updateListenerHub;
         this.requestGlobals = requestGlobals;
         this.classesInvalidationEventHub = classesInvalidationEventHub;
     }
 
-
     /**
      * Bind all the private/internal services of Tapestry.
      */
@@ -98,13 +85,7 @@ public class InternalModule
         binder.bind(ResponseCompressionAnalyzer.class, ResponseCompressionAnalyzerImpl.class);
         binder.bind(ComponentModelSource.class);
         binder.bind(AssetResourceLocator.class);
-    }
-
-    public static VirtualAssetStreamer buildVirtualAssetStreamer(@Autobuild VirtualAssetStreamerImpl service, ResourceCache cache)
-    {
-        cache.addInvalidationListener(service);
-
-        return service;
+        binder.bind(JavascriptStackPathConstructor.class);
     }
 
     /**
@@ -112,50 +93,52 @@ public class InternalModule
      */
     public static ActionRenderResponseGenerator buildActionRenderResponseGenerator(
 
-            @Symbol(SymbolConstants.SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS)
-            boolean immediateMode,
+    @Symbol(SymbolConstants.SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS)
+    boolean immediateMode,
 
-            ObjectLocator locator)
+    ObjectLocator locator)
     {
-        if (immediateMode) return locator.autobuild(ImmediateActionRenderResponseGenerator.class);
+        if (immediateMode)
+            return locator.autobuild(ImmediateActionRenderResponseGenerator.class);
 
         return locator.autobuild(ActionRenderResponseGeneratorImpl.class);
     }
 
-
     @Scope(ScopeConstants.PERTHREAD)
-    public static RequestPageCache buildRequestPageCache(@Autobuild RequestPageCacheImpl service,
-                                                         PerthreadManager perthreadManager)
+    public static RequestPageCache buildRequestPageCache(@Autobuild
+    RequestPageCacheImpl service, PerthreadManager perthreadManager)
     {
         perthreadManager.addThreadCleanupListener(service);
 
         return service;
     }
 
-    public static PageTemplateLocator buildPageTemplateLocator(@ContextProvider AssetFactory contextAssetFactory,
+    public static PageTemplateLocator buildPageTemplateLocator(@ContextProvider
+    AssetFactory contextAssetFactory,
 
-                                                               ComponentClassResolver componentClassResolver)
+    ComponentClassResolver componentClassResolver)
     {
         return new PageTemplateLocatorImpl(contextAssetFactory.getRootResource(), componentClassResolver);
     }
 
-
-    public ComponentMessagesSource buildComponentMessagesSource(@Autobuild ComponentMessagesSourceImpl service)
+    public ComponentMessagesSource buildComponentMessagesSource(@Autobuild
+    ComponentMessagesSourceImpl service)
     {
         updateListenerHub.addUpdateListener(service);
 
         return service;
     }
 
-    public ComponentInstantiatorSource buildComponentInstantiatorSource(@Builtin ClassFactory classFactory,
+    public ComponentInstantiatorSource buildComponentInstantiatorSource(@Builtin
+    ClassFactory classFactory,
 
-                                                                        ComponentClassTransformer transformer,
+    ComponentClassTransformer transformer,
 
-                                                                        Logger logger,
+    Logger logger,
 
-                                                                        InternalRequestGlobals internalRequestGlobals,
+    InternalRequestGlobals internalRequestGlobals,
 
-                                                                        ClasspathURLConverter classpathURLConverter)
+    ClasspathURLConverter classpathURLConverter)
     {
         ComponentInstantiatorSourceImpl source = new ComponentInstantiatorSourceImpl(logger, classFactory
                 .getClassLoader(), transformer, internalRequestGlobals, classpathURLConverter);
@@ -165,21 +148,23 @@ public class InternalModule
         return source;
     }
 
-    public static ComponentClassTransformer buildComponentClassTransformer(
-            @Autobuild ComponentClassTransformerImpl transformer, @ComponentClasses InvalidationEventHub hub)
+    public static ComponentClassTransformer buildComponentClassTransformer(@Autobuild
+    ComponentClassTransformerImpl transformer, @ComponentClasses
+    InvalidationEventHub hub)
     {
         hub.addInvalidationListener(transformer);
 
         return transformer;
     }
 
-    public PageLoader buildPageLoader(@Autobuild PageLoaderImpl service,
+    public PageLoader buildPageLoader(@Autobuild
+    PageLoaderImpl service,
 
-                                      @ComponentTemplates
-                                      InvalidationEventHub templatesHub,
+    @ComponentTemplates
+    InvalidationEventHub templatesHub,
 
-                                      @ComponentMessages
-                                      InvalidationEventHub messagesHub)
+    @ComponentMessages
+    InvalidationEventHub messagesHub)
     {
         // TODO: We could combine these three using chain-of-command.
 
@@ -190,14 +175,14 @@ public class InternalModule
         return service;
     }
 
+    public PagePool buildPagePool(@Autobuild
+    PagePoolImpl service,
 
-    public PagePool buildPagePool(@Autobuild PagePoolImpl service,
-
-                                  @ComponentTemplates
-                                  InvalidationEventHub templatesHub,
+    @ComponentTemplates
+    InvalidationEventHub templatesHub,
 
-                                  @ComponentMessages
-                                  InvalidationEventHub messagesHub)
+    @ComponentMessages
+    InvalidationEventHub messagesHub)
     {
         // This covers invalidations due to changes to classes
 
@@ -218,7 +203,8 @@ public class InternalModule
         return service;
     }
 
-    public ComponentClassCache buildComponentClassCache(@Autobuild ComponentClassCacheImpl service)
+    public ComponentClassCache buildComponentClassCache(@Autobuild
+    ComponentClassCacheImpl service)
     {
         classesInvalidationEventHub.addInvalidationListener(service);
 
@@ -237,7 +223,6 @@ public class InternalModule
         };
     }
 
-
     public CookieSink buildCookieSink()
     {
         return new CookieSink()
@@ -250,17 +235,16 @@ public class InternalModule
         };
     }
 
-    public ResourceCache buildResourceCache(@Autobuild ResourceCacheImpl service)
+    public ResourceCache buildResourceCache(@Autobuild
+    ResourceCacheImpl service)
     {
         updateListenerHub.addUpdateListener(service);
 
         return service;
     }
 
-
-    public ComponentTemplateSource buildComponentTemplateSource(TemplateParser parser,
-                                                                PageTemplateLocator locator,
-                                                                ClasspathURLConverter classpathURLConverter)
+    public ComponentTemplateSource buildComponentTemplateSource(TemplateParser parser, PageTemplateLocator locator,
+            ClasspathURLConverter classpathURLConverter)
     {
         ComponentTemplateSourceImpl service = new ComponentTemplateSourceImpl(parser, locator, classpathURLConverter);
 
@@ -271,13 +255,13 @@ public class InternalModule
 
     @Marker(ComponentLayer.class)
     public static CtClassSource buildCtClassSource(PropertyShadowBuilder builder,
-                                                   ComponentInstantiatorSource componentInstantiatorSource)
+            ComponentInstantiatorSource componentInstantiatorSource)
     {
         return builder.build(componentInstantiatorSource, "classSource", CtClassSource.class);
     }
 
-    public PageActivationContextCollector buildPageActivationContextCollector(
-            @Autobuild PageActivationContextCollectorImpl service)
+    public PageActivationContextCollector buildPageActivationContextCollector(@Autobuild
+    PageActivationContextCollectorImpl service)
     {
         classesInvalidationEventHub.addInvalidationListener(service);
 
@@ -287,7 +271,8 @@ public class InternalModule
     /**
      * @since 5.1.0.0
      */
-    public StringInterner buildStringInterner(@Autobuild StringInternerImpl service)
+    public StringInterner buildStringInterner(@Autobuild
+    StringInternerImpl service)
     {
         classesInvalidationEventHub.addInvalidationListener(service);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java Mon Apr 19 14:05:16 2010
@@ -14,9 +14,6 @@
 
 package org.apache.tapestry5.internal.services;
 
-import java.util.Set;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
 
@@ -28,23 +25,13 @@ public class PartialMarkupDocumentLinker
 
     private final JSONArray stylesheets = new JSONArray();
 
-    private final Set<String> uniquer = CollectionFactory.newSet();
-
     public void addScriptLink(String scriptURL)
     {
-        if (uniquer.contains(scriptURL))
-            return;
-
         scripts.put(scriptURL);
-
-        uniquer.add(scriptURL);
     }
 
     public void addStylesheetLink(String styleURL, String media)
     {
-        if (uniquer.contains(styleURL))
-            return;
-
         JSONObject object = new JSONObject();
         object.put("href", styleURL);
 
@@ -52,8 +39,6 @@ public class PartialMarkupDocumentLinker
             object.put("media", media);
 
         stylesheets.put(object);
-
-        uniquer.add(styleURL);
     }
 
     public void addScript(String script)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderSupportImpl.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderSupportImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderSupportImpl.java Mon Apr 19 14:05:16 2010
@@ -27,8 +27,6 @@ import org.apache.tapestry5.services.jav
 
 public class RenderSupportImpl implements RenderSupport
 {
-    private final DocumentLinker linker;
-
     private final SymbolSource symbolSource;
 
     private final AssetSource assetSource;
@@ -40,10 +38,8 @@ public class RenderSupportImpl implement
     private final JavascriptSupport javascriptSupport;
 
     /**
-     * @param linker
-     *            Used to assemble JavaScript includes and snippets
      * @param symbolSource
-     *            Used to example symbols (in {@linkplain #addClasspathScriptLink(String...)}
+     *            Used to expand symbols (in {@linkplain #addClasspathScriptLink(String...)}
      * @param assetSource
      *            Used to convert classpath scripts to {@link org.apache.tapestry5.Asset}s
      * @param javascriptSupport
@@ -51,10 +47,8 @@ public class RenderSupportImpl implement
      * @param ClientInfrastructure
      *            Identifies which JavaScript libraries and stylesheets are needed in a full page render
      */
-    public RenderSupportImpl(DocumentLinker linker, SymbolSource symbolSource, AssetSource assetSource,
-            JavascriptSupport javascriptSupport)
+    public RenderSupportImpl(SymbolSource symbolSource, AssetSource assetSource, JavascriptSupport javascriptSupport)
     {
-        this.linker = linker;
         this.symbolSource = symbolSource;
         this.assetSource = assetSource;
         this.javascriptSupport = javascriptSupport;
@@ -173,13 +167,11 @@ public class RenderSupportImpl implement
 
     public void addStylesheetLink(Asset stylesheet, String media)
     {
-        Defense.notNull(stylesheet, "stylesheet");
-
-        linker.addStylesheetLink(stylesheet.toClientURL(), media);
+        javascriptSupport.importStylesheet(stylesheet, media);
     }
 
     public void addStylesheetLink(String stylesheetURL, String media)
     {
-        linker.addStylesheetLink(stylesheetURL, media);
+        javascriptSupport.importStylesheet(stylesheetURL, media);
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java Mon Apr 19 14:05:16 2010
@@ -16,6 +16,7 @@ package org.apache.tapestry5.internal.se
 
 import org.apache.tapestry5.corelib.components.Form;
 import org.apache.tapestry5.corelib.components.FormInjector;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
 
 /**
  * Constants used when processing requests from the client web browser.
@@ -45,6 +46,15 @@ public final class RequestConstants
     public static final String VIRTUAL_FOLDER = "virtual";
 
     /**
+     * Folder for combined {@link JavascriptStack} JavaScript files. The path consists of the locale (as a folder) and
+     * the name
+     * of the stack (suffixed with ".js").
+     * 
+     * @since 5.2.0
+     */
+    public static final String STACK_FOLDER = "stack";
+
+    /**
      * Name of parameter, in an Ajax update, that identifies the client-side id of the {@link Form} being extended. Used
      * with {@link Zone}, {@link FormInjector} and other similar components that may be contained within a form.
      * 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavascriptSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavascriptSupportImpl.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavascriptSupportImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavascriptSupportImpl.java Mon Apr 19 14:05:16 2010
@@ -14,63 +14,132 @@
 
 package org.apache.tapestry5.internal.services.ajax;
 
+import java.util.List;
 import java.util.Map;
 
 import org.apache.tapestry5.Asset;
 import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.services.DocumentLinker;
+import org.apache.tapestry5.internal.services.javascript.JavascriptStackPathConstructor;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.Defense;
+import org.apache.tapestry5.ioc.internal.util.Func;
 import org.apache.tapestry5.ioc.internal.util.IdAllocator;
+import org.apache.tapestry5.ioc.internal.util.Operation;
+import org.apache.tapestry5.ioc.services.Coercion;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
-import org.apache.tapestry5.services.ClientInfrastructure;
 import org.apache.tapestry5.services.javascript.InitializationPriority;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
+import org.apache.tapestry5.services.javascript.JavascriptStackSource;
 import org.apache.tapestry5.services.javascript.JavascriptSupport;
 
 public class JavascriptSupportImpl implements JavascriptSupport
 {
+    private class Stylesheet
+    {
+        final String path;
+
+        final String media;
+
+        public Stylesheet(String path, String media)
+        {
+            this.path = path;
+            this.media = media;
+        }
+    }
+
     private final IdAllocator idAllocator;
 
     private final DocumentLinker linker;
 
-    private final ClientInfrastructure clientInfrastructure;
-
     private final boolean partialMode;
 
-    private boolean stackAssetsAdded;;
+    // Using a Map as a case-insensitive set of stack names.
+
+    private final Map<String, Boolean> addedStacks = CollectionFactory.newCaseInsensitiveMap();
+
+    private final List<String> stackLibraries = CollectionFactory.newList();
+
+    private final List<String> otherLibraries = CollectionFactory.newList();
+
+    private final List<String> stackStylesheets = CollectionFactory.newList();
+
+    private final List<Stylesheet> otherStylesheets = CollectionFactory.newList();
 
     private final Map<InitializationPriority, StringBuilder> scripts = CollectionFactory.newMap();
 
     private final Map<InitializationPriority, JSONObject> inits = CollectionFactory.newMap();
 
-    public JavascriptSupportImpl(DocumentLinker linker, ClientInfrastructure clientInfrastructure)
+    private final JavascriptStackSource javascriptStackSource;
+
+    private final JavascriptStackPathConstructor stackPathConstructor;
+
+    private static final Coercion<Asset, String> toPath = new Coercion<Asset, String>()
+    {
+        public String coerce(Asset input)
+        {
+            return input.toClientURL();
+        }
+    };
+
+    public JavascriptSupportImpl(DocumentLinker linker, JavascriptStackSource javascriptStackSource,
+            JavascriptStackPathConstructor stackPathConstructor)
     {
-        this(linker, clientInfrastructure, new IdAllocator(), false);
+        this(linker, javascriptStackSource, stackPathConstructor, new IdAllocator(), false);
     }
 
-    public JavascriptSupportImpl(DocumentLinker linker, ClientInfrastructure clientInfrastructure,
-            IdAllocator idAllocator, boolean partialMode)
+    public JavascriptSupportImpl(DocumentLinker linker, JavascriptStackSource javascriptStackSource,
+            JavascriptStackPathConstructor stackPathConstructor, IdAllocator idAllocator, boolean partialMode)
     {
         this.linker = linker;
-        this.clientInfrastructure = clientInfrastructure;
         this.idAllocator = idAllocator;
+        this.javascriptStackSource = javascriptStackSource;
         this.partialMode = partialMode;
+        this.stackPathConstructor = stackPathConstructor;
 
         // In partial mode, assume that the infrastructure stack is already present
         // (from the original page render).
-        stackAssetsAdded = partialMode;
+
+        if (partialMode)
+            addedStacks.put(InternalConstants.CORE_STACK_NAME, true);
     }
 
     public void commit()
     {
+        Func.each(stackStylesheets, new Operation<String>()
+        {
+            public void op(String value)
+            {
+                linker.addStylesheetLink(value, null);
+            }
+        });
+
+        Func.each(otherStylesheets, new Operation<Stylesheet>()
+        {
+            public void op(Stylesheet value)
+            {
+                linker.addStylesheetLink(value.path, value.media);
+            }
+        });
+
+        Operation<String> linkLibrary = new Operation<String>()
+        {
+            public void op(String value)
+            {
+                linker.addScriptLink(value);
+            }
+        };
+
+        Func.each(stackLibraries, linkLibrary);
+        Func.each(otherLibraries, linkLibrary);
+
         convertInitsToScriptBlocks();
 
         if (scripts.isEmpty())
             return;
 
-        addStack();
-
         String masterBlock = assembleMasterScriptBlock();
 
         linker.addScript(masterBlock);
@@ -168,9 +237,18 @@ public class JavascriptSupportImpl imple
 
     public void addScript(InitializationPriority priority, String format, Object... arguments)
     {
+        addCoreStackIfNeeded();
+
         Defense.notNull(priority, "priority");
         Defense.notBlank(format, "format");
 
+        String newScript = arguments.length == 0 ? format : String.format(format, arguments);
+
+        appendScript(priority, newScript);
+    }
+
+    private void appendScript(InitializationPriority priority, String newScript)
+    {
         StringBuilder script = scripts.get(priority);
 
         if (script == null)
@@ -179,11 +257,7 @@ public class JavascriptSupportImpl imple
             scripts.put(priority, script);
         }
 
-        if (arguments.length == 0)
-            script.append(format);
-        else
-            script.append(String.format(format, arguments));
-
+        script.append(newScript);
         script.append("\n");
     }
 
@@ -206,21 +280,57 @@ public class JavascriptSupportImpl imple
     {
         Defense.notNull(asset, "asset");
 
-        addStack();
+        addCoreStackIfNeeded();
+
+        String path = asset.toClientURL();
+
+        if (otherLibraries.contains(path))
+            return;
 
-        linker.addScriptLink(asset.toClientURL());
+        otherLibraries.add(path);
     }
 
-    private void addStack()
+    private void addCoreStackIfNeeded()
     {
-        if (!stackAssetsAdded)
-        {
-            for (Asset script : clientInfrastructure.getJavascriptStack())
-            {
-                linker.addScriptLink(script.toClientURL());
-            }
+        addAssetsFromStack(InternalConstants.CORE_STACK_NAME);
+    }
 
-            stackAssetsAdded = true;
-        }
+    private void addAssetsFromStack(String stackName)
+    {
+        if (addedStacks.containsKey(stackName))
+            return;
+
+        JavascriptStack stack = javascriptStackSource.getStack(stackName);
+
+        stackLibraries.addAll(stackPathConstructor.constructPathsForJavascriptStack(stackName));
+
+        List<String> stylesheetPaths = Func.map(stack.getStylesheets(), toPath);
+
+        stackStylesheets.addAll(stylesheetPaths);
+
+        String initialization = stack.getInitialization();
+
+        if (initialization != null)
+            appendScript(InitializationPriority.IMMEDIATE, initialization);
+
+        addedStacks.put(stackName, true);
     }
+
+    public void importStylesheet(Asset stylesheet, String media)
+    {
+        Defense.notNull(stylesheet, "stylesheet");
+
+        importStylesheet(stylesheet.toClientURL(), media);
+    }
+
+    public void importStylesheet(String stylesheetURL, String media)
+    {
+        Defense.notBlank(stylesheetURL, "stylesheetURL");
+
+        if (otherStylesheets.contains(stylesheetURL))
+            return;
+
+        otherStylesheets.add(new Stylesheet(stylesheetURL, media));
+    }
+
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavascriptStack.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavascriptStack.java?rev=935580&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavascriptStack.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavascriptStack.java Mon Apr 19 14:05:16 2010
@@ -0,0 +1,60 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services.javascript;
+
+import java.util.List;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.services.ClientInfrastructure;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
+
+/**
+ * JavascriptStack based on the information retrieved from {@link ClientInfrastructure}.
+ * 
+ * @since 5.2.0
+ */
+public class CoreJavascriptStack implements JavascriptStack
+{
+    private final ClientInfrastructure clientInfrastructure;
+
+    private final boolean productionMode;
+
+    public CoreJavascriptStack(ClientInfrastructure clientInfrastructure,
+
+    @Symbol(SymbolConstants.PRODUCTION_MODE)
+    boolean productionMode)
+    {
+        this.clientInfrastructure = clientInfrastructure;
+        this.productionMode = productionMode;
+    }
+
+    public String getInitialization()
+    {
+        return productionMode ? null : "Tapestry.DEBUG_ENABLED = true;";
+    }
+
+    public List<Asset> getJavascriptLibraries()
+    {
+        return clientInfrastructure.getJavascriptStack();
+    }
+
+    public List<Asset> getStylesheets()
+    {
+        return clientInfrastructure.getStylesheetStack();
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavascriptStack.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructor.java?rev=935580&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructor.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructor.java Mon Apr 19 14:05:16 2010
@@ -0,0 +1,44 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services.javascript;
+
+import java.util.List;
+
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
+import org.apache.tapestry5.services.javascript.JavascriptStackSource;
+import org.apache.tapestry5.services.javascript.JavascriptSupport;
+
+/**
+ * Used to generate a list of asset URL paths for the JavaScript libraries
+ * of a JavaScript stack. This encapsulates much of the logic of {@linkplain SymbolConstants#COMBINE_SCRIPTS script
+ * aggregation}.
+ * 
+ * @since 5.2.0
+ * @see JavascriptStack
+ * @see JavascriptStackSource
+ * @see JavascriptSupport
+ */
+public interface JavascriptStackPathConstructor
+{
+    /**
+     * Given a stack, by name, return a list of URL paths for the individual libraqries in the stack.
+     * If scripts are combined, this will be a single (combined) URL.
+     * 
+     * @param stackName
+     *            name of {@link JavascriptStack}
+     */
+    List<String> constructPathsForJavascriptStack(String stackName);
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructorImpl.java?rev=935580&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructorImpl.java Mon Apr 19 14:05:16 2010
@@ -0,0 +1,87 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services.javascript;
+
+import java.util.List;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.internal.services.RequestConstants;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.Func;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.ThreadLocale;
+import org.apache.tapestry5.services.assets.AssetPathConstructor;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
+import org.apache.tapestry5.services.javascript.JavascriptStackSource;
+
+public class JavascriptStackPathConstructorImpl implements JavascriptStackPathConstructor
+{
+    private final ThreadLocale threadLocale;
+
+    private final AssetPathConstructor assetPathConstructor;
+
+    private final JavascriptStackSource javascriptStackSource;
+
+    private final boolean combineScripts;
+
+    private final Coercion<Asset, String> toPath = new Coercion<Asset, String>()
+    {
+        public String coerce(Asset input)
+        {
+            return input.toClientURL();
+        }
+    };
+
+    public JavascriptStackPathConstructorImpl(ThreadLocale threadLocale, AssetPathConstructor assetPathConstructor,
+            JavascriptStackSource javascriptStackSource,
+
+            @Symbol(SymbolConstants.COMBINE_SCRIPTS)
+            boolean combineScripts)
+    {
+        this.threadLocale = threadLocale;
+        this.assetPathConstructor = assetPathConstructor;
+        this.javascriptStackSource = javascriptStackSource;
+        this.combineScripts = combineScripts;
+    }
+
+    public List<String> constructPathsForJavascriptStack(String stackName)
+    {
+        JavascriptStack stack = javascriptStackSource.getStack(stackName);
+
+        List<Asset> assets = stack.getJavascriptLibraries();
+
+        if (assets.size() > 1 && combineScripts)
+            return combinedStackURL(stackName);
+
+        return toPaths(assets);
+    }
+
+    private List<String> toPaths(List<Asset> assets)
+    {
+        return Func.map(assets, toPath);
+    }
+
+    private List<String> combinedStackURL(String stackName)
+    {
+        String path = String.format("%s/%s.js", threadLocale.getLocale().toString(), stackName);
+
+        String stackURL = assetPathConstructor.constructAssetPath(RequestConstants.STACK_FOLDER, path);
+
+        return CollectionFactory.newList(stackURL);
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackPathConstructorImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackSourceImpl.java?rev=935580&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackSourceImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackSourceImpl.java Mon Apr 19 14:05:16 2010
@@ -0,0 +1,44 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services.javascript;
+
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
+import org.apache.tapestry5.services.javascript.JavascriptStackSource;
+
+public class JavascriptStackSourceImpl implements JavascriptStackSource
+{
+    private final Map<String, JavascriptStack> configuration;
+
+    public JavascriptStackSourceImpl(Map<String, JavascriptStack> configuration)
+    {
+        this.configuration = configuration;
+    }
+
+    public JavascriptStack getStack(String name)
+    {
+        JavascriptStack stack = configuration.get(name);
+
+        if (stack == null)
+            throw new UnknownValueException(String.format("No JavascriptStack with name '%s'.", name),
+                    new AvailableValues("JavaScript stacks", configuration));
+
+        return stack;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavascriptStackSourceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientInfrastructure.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientInfrastructure.java?rev=935580&r1=935579&r2=935580&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientInfrastructure.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientInfrastructure.java Mon Apr 19 14:05:16 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.services;
 
 import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.services.javascript.JavascriptStack;
 
 import java.util.List;
 
@@ -23,7 +24,7 @@ import java.util.List;
  * are added to any page that {@linkplain org.apache.tapestry5.RenderSupport#addScript(String, Object[]) adds JavaScript
  * to the page}. The CSS stylesheet files are added to any page with a root &lt;html&gt; element.
  * <p/>
- * Tapestry's default JavaScript stack includes Prototype, Scriptaculous, and a Tapestry-specific library.  Note that
+ * Tapestry's default JavaScript stack includes Prototype, Scriptaculous, and a Tapestry-specific library. Note that
  * these individual library files will {@linkplain org.apache.tapestry5.SymbolConstants#COMBINE_SCRIPTS be combined into
  * a single virtual resource} (from the client's point of view).
  * <p/>
@@ -32,7 +33,10 @@ import java.util.List;
  * <p/>
  * Overriding the default ClientInfrastructure service gives an application complete freedom to replace any part of
  * Tapestry's default client-side resources.
- *
+ * <p>
+ * 
+ * @deprecated ClientInfrastructure now exists to define the "core" {@link JavascriptStack}. It may be removed
+ *             in the future.
  * @since 5.1.0.2
  */
 public interface ClientInfrastructure
@@ -41,7 +45,7 @@ public interface ClientInfrastructure
      * Returns the (localized) assets for the scripts to be included as core JavaScript stack. The assets for the stack
      * will be added before any other JavaScript libraries included in the render of the page. Adding a library or any
      * initialization JavaScript triggers the inclusion of the JavaScript stack.
-     *
+     * 
      * @return list of assets
      */
     List<Asset> getJavascriptStack();
@@ -50,7 +54,7 @@ public interface ClientInfrastructure
      * Returns the (localized) assets for CSS stylesheet files to be included on any page. These are ordered before any
      * stylesheets specifically included (to allow default rules to be easily overridden). The default core stack
      * includes the Tapestry default stylesheet, and an additional stylesheet for the Blackbird JavaScript console.
-     *
+     * 
      * @return list of assets
      */
     List<Asset> getStylesheetStack();