You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2007/03/11 20:11:04 UTC

svn commit: r516990 [2/2] - in /tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry: internal/services/InternalModule.java services/TapestryModule.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=516990&r1=516989&r2=516990
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Sun Mar 11 12:11:03 2007
@@ -199,232 +199,141 @@
 @SubModule(InternalModule.class)
 public final class TapestryModule
 {
-    private final ChainBuilder _chainBuilder;
-
-    private final PipelineBuilder _pipelineBuilder;
-
-    private final RequestGlobals _requestGlobals;
-
-    private final ApplicationGlobals _applicationGlobals;
-
-    private final PropertyShadowBuilder _shadowBuilder;
-
-    private final RequestPageCache _requestPageCache;
-
-    private final PageResponseRenderer _pageResponseRenderer;
-
-    private final Request _request;
-
-    private final Environment _environment;
-
-    private final StrategyBuilder _strategyBuilder;
-
-    // Primarily used as a InvalidationEventHub for service implementations
-    // that should clear their cache when the underlying component class loader
-    // is discarded.
-
-    private final ComponentInstantiatorSource _componentInstantiatorSource;
-
-    private final LinkFactory _linkFactory;
-
-    private final PropertyAccess _propertyAccess;
-
-    private final PropertyConduitSource _propertyConduitSource;
-
-    private final ClassFactory _componentClassFactory;
-
-    // Yes, you can inject services defined by this module into this module. The service proxy is
-    // created without instantiating the module itself. We're careful about making as many
-    // service builder and contributor methods static as possible to avoid recursive build
-    // exceptions.
-
-    public TapestryModule(@InjectService("PipelineBuilder")
-    PipelineBuilder pipelineBuilder,
-
-    @InjectService("PropertyShadowBuilder")
-    PropertyShadowBuilder shadowBuilder,
-
-    @Inject("infrastructure:RequestGlobals")
-    RequestGlobals requestGlobals,
+    public static MarkupWriterFactory build(@InjectService("ComponentInvocationMap")
+    final ComponentInvocationMap componentInvocationMap)
+    {
+        // Temporary ...
+        return new MarkupWriterFactory()
+        {
+            public MarkupWriter newMarkupWriter()
+            {
+                return new MarkupWriterImpl(new DefaultMarkupModel(), componentInvocationMap);
+            }
+        };
+    }
 
-    @Inject("infrastructure:ApplicationGlobals")
-    ApplicationGlobals applicationGlobals,
+    public static ClasspathAssetAliasManager build(@InjectService("ContextPathSource")
+    ContextPathSource contextPathSource, Map<String, String> configuration)
+    {
+        return new ClasspathAssetAliasManagerImpl(contextPathSource, configuration);
+    }
 
-    @InjectService("ChainBuilder")
-    ChainBuilder chainBuilder,
+    public static PersistentLocale build(@InjectService("Cookies")
+    Cookies cookies)
+    {
+        return new PersistentLocaleImpl(cookies);
+    }
 
-    @InjectService("RequestPageCache")
-    RequestPageCache requestPageCache,
+    public static Infrastructure build(Log log,
 
-    @InjectService("PageResponseRenderer")
-    PageResponseRenderer pageResponseRenderer,
+    @InjectService("InfrastructureOverrides")
+    InfrastructureManager overridesManager,
 
-    @Inject("infrastructure:Request")
-    Request request,
+    Collection<InfrastructureContribution> configuration)
+    {
+        InfrastructureManager manager = new InfrastructureManagerImpl(log, configuration);
 
-    @Inject("infrastructure:Environment")
-    Environment environment,
+        return new InfrastructureImpl(manager, overridesManager);
+    }
 
-    @InjectService("StrategyBuilder")
-    StrategyBuilder strategyBuilder,
+    public static ApplicationStateManager build(
+            Map<Class, ApplicationStateContribution> configuration,
+            @Inject("infrastructure:ApplicationStatePersistenceStrategySource")
+            ApplicationStatePersistenceStrategySource source)
+    {
+        return new ApplicationStateManagerImpl(configuration, source);
+    }
 
-    @InjectService("ComponentInstantiatorSource")
-    ComponentInstantiatorSource componentInstantiatorSource,
+    public static ApplicationStatePersistenceStrategySource build(
+            Map<String, ApplicationStatePersistenceStrategy> configuration)
+    {
+        return new ApplicationStatePersistenceStrategySourceImpl(configuration);
+    }
 
-    @InjectService("LinkFactory")
-    LinkFactory linkFactory,
+    public static BindingSource build(Map<String, BindingFactory> configuration)
+    {
+        return new BindingSourceImpl(configuration);
+    }
 
-    @Inject("infrastructure:PropertyConduitSource")
-    PropertyConduitSource propertyConduitSource,
+    public static TranslatorSource build(Map<String, Translator> configuration)
+    {
+        return new TranslatorSourceImpl(configuration);
+    }
 
-    @Inject("infrastructure:PropertyAccess")
-    PropertyAccess propertyAccess,
+    /** A public service since extensions may provide new persistent strategies. */
+    public static PersistentFieldManager build(@Inject("infrastructure:MetaDataLocator")
+    MetaDataLocator locator,
 
-    @InjectService("ComponentClassFactory")
-    ClassFactory componentClassFactory)
+    Map<String, PersistentFieldStrategy> configuration)
     {
-        _pipelineBuilder = pipelineBuilder;
-        _shadowBuilder = shadowBuilder;
-        _requestGlobals = requestGlobals;
-        _applicationGlobals = applicationGlobals;
-        _chainBuilder = chainBuilder;
-        _requestPageCache = requestPageCache;
-        _pageResponseRenderer = pageResponseRenderer;
-        _request = request;
-        _environment = environment;
-        _strategyBuilder = strategyBuilder;
-        _componentInstantiatorSource = componentInstantiatorSource;
-        _linkFactory = linkFactory;
-        _propertyAccess = propertyAccess;
-        _propertyConduitSource = propertyConduitSource;
-        _componentClassFactory = componentClassFactory;
+        return new PersistentFieldManagerImpl(locator, configuration);
     }
 
-    /**
-     * Invoked from
-     * {@link #contributeInfrastructure(Configuration, ServiceLocator, Request, Response, TypeCoercer)}
-     * to contribute services from the tapestry module where the unqualified class name of the
-     * service interface matches the unqualified service id. This unqualified name is used as the
-     * infrastructure alias.
-     */
-    @SuppressWarnings("unchecked")
-    private static void add(Configuration<InfrastructureContribution> configuration,
-            ServiceLocator locator, Class... serviceInterfaces)
-    {
-        for (Class serviceInterface : serviceInterfaces)
-        {
-            String serviceId = TapestryInternalUtils.lastTerm(serviceInterface.getName());
+    public static FieldValidatorSource build(@Inject("infrastructure:ValidationMessagesSource")
+    ValidationMessagesSource messagesSource,
 
-            Object service = locator.getService(serviceId, serviceInterface);
+    @Inject("infrastructure:TypeCoercer")
+    TypeCoercer typeCoercer,
 
-            InfrastructureContribution contribution = new InfrastructureContribution(serviceId,
-                    service);
+    @Inject("service:PageRenderSupport")
+    PageRenderSupport pageRenderSupport,
 
-            configuration.add(contribution);
-        }
+    Map<String, Validator> configuration)
+    {
+        return new FieldValidatorSourceImpl(messagesSource, typeCoercer, pageRenderSupport,
+                configuration);
     }
 
+    // Primarily used as a InvalidationEventHub for service implementations
+    // that should clear their cache when the underlying component class loader
+    // is discarded.
+
     public static ApplicationGlobals buildApplicationGlobals()
     {
         return new ApplicationGlobalsImpl();
     }
 
-    public Context buildContext(@InjectService("ApplicationGlobals")
-    ApplicationGlobals globals)
+    public static AssetSource buildAssetSource(Map<String, AssetFactory> configuration)
     {
-        return _shadowBuilder.build(globals, "context", Context.class);
+        return new AssetSourceImpl(configuration);
     }
 
-    public ServletApplicationInitializer buildServletApplicationInitializer(Log log,
-            List<ServletApplicationInitializerFilter> configuration,
-            @InjectService("ApplicationInitializer")
-            final ApplicationInitializer initializer)
-    {
-        ServletApplicationInitializer terminator = new ServletApplicationInitializer()
-        {
-            public void initializeApplication(ServletContext context)
-            {
-                _applicationGlobals.store(context);
-
-                // And now, down the (Web) ApplicationInitializer pipeline ...
+    public static Cookies buildCookies(@InjectService("ContextPathSource")
+    ContextPathSource contextPathSource,
 
-                initializer.initializeApplication(new ContextImpl(context));
-            }
-        };
+    @InjectService("CookieSource")
+    CookieSource cookieSource,
 
-        return _pipelineBuilder.build(
-                log,
-                ServletApplicationInitializer.class,
-                ServletApplicationInitializerFilter.class,
-                configuration,
-                terminator);
-    }
+    @InjectService("CookieSink")
+    CookieSink cookieSink,
 
-    /** Initializes the application. */
-    public ApplicationInitializer buildApplicationInitializer(Log log,
-            List<ApplicationInitializerFilter> configuration)
+    @Inject("${tapestry.default-cookie-max-age}")
+    int defaultMaxAge)
     {
-        ApplicationInitializer terminator = new ApplicationInitializer()
-        {
-            public void initializeApplication(Context context)
-            {
-                _applicationGlobals.store(context);
-            }
-        };
-
-        return _pipelineBuilder.build(
-                log,
-                ApplicationInitializer.class,
-                ApplicationInitializerFilter.class,
-                configuration,
-                terminator);
+        return new CookiesImpl(contextPathSource, cookieSource, cookieSink, defaultMaxAge);
     }
 
-    /**
-     * Allows the exact steps in the component class transformation process to be defined.
-     */
-    public ComponentClassTransformWorker buildComponentClassTransformWorker(
-            List<ComponentClassTransformWorker> configuration)
+    @Lifecycle("perthread")
+    public static Environment buildEnvironment()
     {
-        return _chainBuilder.build(ComponentClassTransformWorker.class, configuration);
+        return new EnvironmentImpl();
     }
 
-    public HttpServletRequestHandler buildHttpServletRequestHandler(Log log,
-            List<HttpServletRequestFilter> configuration,
+    public static FieldValidatorDefaultSource buildFieldValidatorDefaultSource(
+            @Inject("infrastructure:ValidationConstraintGenerator")
+            ValidationConstraintGenerator validationConstraintGenerator,
 
-            @InjectService("RequestHandler")
-            final RequestHandler handler)
+            @Inject("infrastructure:FieldValidatorSource")
+            FieldValidatorSource fieldValidatorSource)
     {
-        HttpServletRequestHandler terminator = new HttpServletRequestHandler()
-        {
-            public boolean service(HttpServletRequest request, HttpServletResponse response)
-                    throws IOException
-            {
-                _requestGlobals.store(request, response);
-
-                return handler.service(new RequestImpl(request), new ResponseImpl(response));
-            }
-        };
-
-        return _pipelineBuilder.build(
-                log,
-                HttpServletRequestHandler.class,
-                HttpServletRequestFilter.class,
-                configuration,
-                terminator);
+        return new FieldValidatorDefaultSourceImpl(validationConstraintGenerator,
+                fieldValidatorSource);
     }
 
-    public static Infrastructure buildInfrastructure(Log log,
-
-    @InjectService("InfrastructureOverrides")
-    InfrastructureManager overridesManager,
-
-    Collection<InfrastructureContribution> configuration)
-    {
-        InfrastructureManager manager = new InfrastructureManagerImpl(log, configuration);
-
-        return new InfrastructureImpl(manager, overridesManager);
-    }
+    // Yes, you can inject services defined by this module into this module. The service proxy is
+    // created without instantiating the module itself. We're careful about making as many
+    // service builder and contributor methods static as possible to avoid recursive build
+    // exceptions.
 
     /**
      * A companion service to {@link #buildInfrastructure(Log, Collection)} whose configuration
@@ -436,118 +345,268 @@
         return new InfrastructureManagerImpl(log, configuration);
     }
 
-    public static MarkupWriterFactory buildMarkupWriterFactory(
-            @InjectService("ComponentInvocationMap")
-            final ComponentInvocationMap componentInvocationMap)
+    @Lifecycle("perthread")
+    public static RequestGlobals buildRequestGlobals()
     {
-        // Temporary ...
-        return new MarkupWriterFactory()
-        {
-            public MarkupWriter newMarkupWriter()
-            {
-                return new MarkupWriterImpl(new DefaultMarkupModel(), componentInvocationMap);
-            }
-        };
+        return new RequestGlobalsImpl();
     }
 
-    /**
-     * Ordered contributions to the MasterDispatcher service allow different URL matching strategies
-     * to occur.
-     */
-    public Dispatcher buildMasterDispatcher(List<Dispatcher> configuration)
+    public static ResourceDigestGenerator buildResourceDigestGenerator()
     {
-        return _chainBuilder.build(Dispatcher.class, configuration);
+        return new ResourceDigestGeneratorImpl();
     }
 
-    @Lifecycle("perthread")
-    public static RequestGlobals buildRequestGlobals()
+    public static ValidationConstraintGenerator buildValidationConstraintGenerator(
+            List<ValidationConstraintGenerator> configuration)
     {
-        return new RequestGlobalsImpl();
+        return new ValidationConstraintGeneratorImpl(configuration);
     }
 
     /**
-     * Builds a shadow of the RequestGlobals.request property. Note again that the shadow can be an
-     * ordinary singleton, even though RequestGlobals is perthread.
+     * Contributes the factory for serveral built-in binding prefixes ("literal", prop", "block",
+     * "component" "message", "validate", "translate").
      */
-    public Request buildRequest()
+    public static void contributeBindingSource(
+            MappedConfiguration<String, BindingFactory> configuration,
+
+            @InjectService("PropBindingFactory")
+            BindingFactory propBindingFactory,
+
+            @Inject("infrastructure:FieldValidatorSource")
+            FieldValidatorSource fieldValidatorSource,
+
+            @Inject("infrastructure:TranslatorSource")
+            TranslatorSource translatorSource)
     {
-        return _shadowBuilder.build(_requestGlobals, "request", Request.class);
+        configuration.add(TapestryConstants.LITERAL_BINDING_PREFIX, new LiteralBindingFactory());
+        configuration.add(TapestryConstants.PROP_BINDING_PREFIX, propBindingFactory);
+        configuration.add("component", new ComponentBindingFactory());
+        configuration.add("message", new MessageBindingFactory());
+        configuration.add("validate", new ValidateBindingFactory(fieldValidatorSource));
+        configuration.add("translate", new TranslateBindingFactory(translatorSource));
+        configuration.add("block", new BlockBindingFactory());
     }
 
-    /**
-     * Builds a shadow of the RequestGlobals.response property. Note again that the shadow can be an
-     * ordinary singleton, even though RequestGlobals is perthread.
-     */
-    public Response buildResponse()
+    public static void contributeClasspathAssetAliasManager(
+            MappedConfiguration<String, String> configuration,
+
+            @Inject("${tapestry.scriptaculous.path}")
+            String scriptaculousPath)
     {
-        return _shadowBuilder.build(_requestGlobals, "response", Response.class);
+        configuration.add("tapestry/", "org/apache/tapestry/");
+
+        configuration.add("scriptaculous/", scriptaculousPath + "/");
     }
 
-    public RequestHandler buildRequestHandler(Log log, List<RequestFilter> configuration,
-            @InjectService("MasterDispatcher")
-            final Dispatcher masterDispatcher)
+    public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
     {
-        RequestHandler terminator = new RequestHandler()
-        {
-            public boolean service(Request request, Response response) throws IOException
-            {
-                _requestGlobals.store(request, response);
+        configuration.add(new LibraryMapping("core", "org.apache.tapestry.corelib"));
+    }
 
-                return masterDispatcher.dispatch(request, response);
-            }
-        };
+    /**
+     * Adds a number of standard component class transform workers:
+     * <ul>
+     * <li>Retain -- allows fields to retain their values between requests</li>
+     * <li>Persist -- allows fields to store their their value persistently between requests</li>
+     * <li>Parameter -- identifies parameters based on the
+     * {@link org.apache.tapestry.annotations.Parameter} annotation</li>
+     * <li>Component -- identifies embedded components based on the
+     * {@link org.apache.tapestry.annotations.Component} annotation</li>
+     * <li>Mixin -- adds a mixin as part of a component's implementation</li>
+     * <li>Environment -- allows fields to contain values extracted from the {@link Environment}
+     * service</li>
+     * <li>InjectNamed -- used with the {@link Inject} annotation, when a value is supplied</li>
+     * <li>InjectAnnonymous -- used with the {@link Inject} annotation, when no value is supplied</li>
+     * <li>InjectPage -- adds code to allow access to other pages via the {@link InjectPage} field
+     * annotation</li>
+     * <li>InjectBlock -- allows a block from the template to be injected into a field</li>
+     * <li>SupportsInformalParameters -- checks for the annotation</li>
+     * <li>Meta -- checks for meta data and adds it to the component model
+     * <li>ApplicationState -- converts fields that reference application state objects
+     * <li>UnclaimedField -- identifies unclaimed fields and resets them to null/0/false at the end
+     * of the request</li>
+     * <li>RenderCommand -- ensures all components also implement {@link RenderCommand}</li>
+     * <li>SetupRender, BeginRender, etc. -- correspond to component render phases and annotations</li>
+     * </ul>
+     */
+    public static void contributeComponentClassTransformWorker(
+            OrderedConfiguration<ComponentClassTransformWorker> configuration,
 
-        return _pipelineBuilder.build(
-                log,
-                RequestHandler.class,
-                RequestFilter.class,
+            ServiceLocator locator,
+
+            @InjectService("MasterObjectProvider")
+            ObjectProvider objectProvider,
+
+            @InjectService("InjectionProvider")
+            InjectionProvider injectionProvider,
+
+            @Inject("infrastructure:Environment")
+            Environment environment,
+
+            @Inject("infrastructure:ComponentClassResolver")
+            ComponentClassResolver resolver,
+
+            @InjectService("RequestPageCache")
+            RequestPageCache requestPageCache,
+
+            @Inject("infrastructure:AssetSource")
+            AssetSource assetSource,
+
+            @InjectService("SymbolSource")
+            SymbolSource symbolSource,
+
+            @Inject("infrastructure:BindingSource")
+            BindingSource bindingsource,
+
+            @Inject("infrastructure:ApplicationStateManager")
+            ApplicationStateManager applicationStateManager)
+    {
+        // TODO: Proper scheduling of all of this. Since a given field or method should
+        // only have a single annotation, the order doesn't matter so much, as long as
+        // UnclaimedField is last.
+
+        configuration.add("Meta", new MetaWorker());
+        configuration.add("ApplicationState", new ApplicationStateWorker(applicationStateManager));
+        configuration.add("InjectNamed", new InjectNamedWorker(objectProvider, locator));
+        configuration.add(
+                "InjectAnonymous",
+                new InjectAnonymousWorker(locator, injectionProvider),
+                "after:InjectNamed");
+        configuration.add(
+                "InjectAsset",
+                new InjectAssetWorker(assetSource, symbolSource),
+                "before:InjectNamed");
+        configuration.add("InjectBlock", new InjectBlockWorker(), "before:InjectNamed");
+
+        configuration.add("MixinAfter", new MixinAfterWorker());
+        configuration.add("Component", new ComponentWorker(resolver));
+        configuration.add("Environment", new EnvironmentalWorker(environment));
+        configuration.add("Mixin", new MixinWorker(resolver));
+        configuration.add("OnEvent", new OnEventWorker());
+        configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
+        configuration.add("InjectPage", new InjectPageWorker(requestPageCache));
+        configuration.add("InjectComponent", new InjectComponentWorker());
+        configuration.add("RenderCommand", new RenderCommandWorker());
+
+        // Default values for parameters are often some form of injection, so make sure
+        // that Parameter fields are processed after injections.
+
+        configuration.add("Parameter", new ParameterWorker(bindingsource), "after:Inject*");
+
+        // Workers for the component rendering state machine methods; this is in typical
+        // execution order.
+
+        add(configuration, TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class, false);
+        add(configuration, TransformConstants.BEGIN_RENDER_SIGNATURE, BeginRender.class, false);
+        add(
                 configuration,
-                terminator);
+                TransformConstants.BEFORE_RENDER_TEMPLATE_SIGNATURE,
+                BeforeRenderTemplate.class,
+                false);
+        add(
+                configuration,
+                TransformConstants.BEFORE_RENDER_BODY_SIGNATURE,
+                BeforeRenderBody.class,
+                false);
+
+        // These phases operate in reverse order.
+
+        add(
+                configuration,
+                TransformConstants.AFTER_RENDER_BODY_SIGNATURE,
+                AfterRenderBody.class,
+                true);
+        add(
+                configuration,
+                TransformConstants.AFTER_RENDER_TEMPLATE_SIGNATURE,
+                AfterRenderTemplate.class,
+                true);
+        add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class, true);
+        add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class, true);
+
+        // Ideally, these should be ordered pretty late in the process to make sure there are no
+        // side effects
+        // with other workers that do work inside the page lifecycle methods.
+
+        add(
+                configuration,
+                PageLoaded.class,
+                TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+                "pageLoaded");
+        add(
+                configuration,
+                PageAttached.class,
+                TransformConstants.CONTAINING_PAGE_DID_ATTACH_SIGNATURE,
+                "pageAttached");
+        add(
+                configuration,
+                PageDetached.class,
+                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
+                "pageDetached");
+
+        configuration.add("Retain", new RetainWorker());
+        configuration.add("Persist", new PersistWorker());
+        configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*.*");
     }
 
     /**
-     * Contributes filter "StaticFilesFilter" that identifies requests for static resources and
-     * terminates the pipeline by returning false. Generally, most filters should be ordered after
-     * this filter.
+     * Adds the {@link #buildDefaultDataTypeAnalyzer(Map) DefaultDatatTypeAnalyzer} to the
+     * configuration, ordered explicitly last.
      */
-    public static void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration,
-            @InjectService("Context")
-            Context context,
-
-            @Inject("infrastructure:RequestExceptionHandler")
-            final RequestExceptionHandler exceptionHandler)
+    public static void contributeDataTypeAnalyzer(
+            OrderedConfiguration<DataTypeAnalyzer> configuration,
+            @InjectService("DefaultDataTypeAnalyzer")
+            DataTypeAnalyzer defaultDataTypeAnalyzer)
     {
-        RequestFilter staticFilesFilter = new StaticFilesFilter(context);
+        configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
+    }
 
-        configuration.add("StaticFiles", staticFilesFilter);
+    /**
+     * Maps property types to data type names
+     * <ul>
+     * <li>String --&gt; text
+     * <li>Number --&gt; text
+     * <li>Enum --&gt; enum
+     * <li>Boolean --&gt; checkbox
+     * </ul>
+     */
+    public static void contributeDefaultDataTypeAnalyzer(
+            MappedConfiguration<Class, String> configuration)
+    {
+        // This is a special case contributed to avoid exceptions when a property type can't be
+        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
 
-        RequestFilter errorFilter = new RequestFilter()
-        {
-            public boolean service(Request request, Response response, RequestHandler handler)
-                    throws IOException
-            {
-                try
-                {
-                    return handler.service(request, response);
-                }
-                catch (IOException ex)
-                {
-                    // Pass it through.
-                    throw ex;
-                }
-                catch (Throwable ex)
-                {
-                    exceptionHandler.handleRequestException(ex);
+        configuration.add(Object.class, "");
 
-                    // We assume a reponse has been sent and there's no need to handle the request
-                    // further.
+        configuration.add(String.class, "text");
 
-                    return true;
-                }
-            }
-        };
+        // This may change; as currently implemented, "text" refers more to the edit component
+        // (TextField) than to
+        // the "flavor" of data.
 
-        configuration.add("ErrorFilter", errorFilter);
+        configuration.add(Number.class, "text");
+        configuration.add(Enum.class, "enum");
+        configuration.add(Boolean.class, "checkbox");
+    }
+
+    /**
+     * Contributes the basic set of validators:
+     * <ul>
+     * <li>required</li>
+     * <li>minlength</li>
+     * <li>maxlength</li>
+     * <li>min</li>
+     * <li>max</li>
+     * </ul>
+     */
+    public static void contributeFieldValidatorSource(
+            MappedConfiguration<String, Validator> configuration)
+    {
+        configuration.add("required", new Required());
+        configuration.add("minlength", new MinLength());
+        configuration.add("maxlength", new MaxLength());
+        configuration.add("min", new Min());
+        configuration.add("max", new Max());
     }
 
     /**
@@ -603,6 +662,22 @@
     }
 
     /**
+     * Contributes the elemental providers:
+     * <ul>
+     * <li>ComponentResources -- give component access to its resources</li>
+     * <li>CommonResources -- access to properties of resources (log, messages, etc.)</li>
+     * <li>Default -- looks for a unique IoC service that matches the field type</li>
+     * </ul>
+     */
+    public static void contributeInjectionProvider(
+            OrderedConfiguration<InjectionProvider> configuration)
+    {
+        configuration.add("ComponentResources", new ComponentResourcesInjectionProvider());
+        configuration.add("CommonResources", new CommonResourcesInjectionProvider());
+        configuration.add("Default", new DefaultInjectionProvider(), "after:*.*");
+    }
+
+    /**
      * Contributes the {@link ObjectProvider} provided by {@link Infrastructure#getObjectProvider()}
      * mapped to the provider prefix "infrastructure".
      */
@@ -633,296 +708,200 @@
         configuration.add("infrastructure", wrapper);
     }
 
-    public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
-            @Inject("infrastructure:ClasspathAssetAliasManager")
-            ClasspathAssetAliasManager aliasManager,
-
-            @InjectService("ResourceCache")
-            ResourceCache resourceCache,
-
-            @InjectService("ResourceStreamer")
-            ResourceStreamer streamer,
-
-            @InjectService("PageLinkHandler")
-            PageLinkHandler pageLinkHandler,
-
-            @InjectService("ActionLinkHandler")
-            ActionLinkHandler actionLinkHandler,
-
-            @InjectService("ComponentClassResolver")
-            ComponentClassResolver componentClassResolver,
-
-            @Inject("${tapestry.start-page-name}")
-            String startPageName)
-    {
-        // Looks for the root path and renders the start page
-
-        configuration.add("RootPath", new RootPathDispatcher(componentClassResolver,
-                pageLinkHandler, _pageResponseRenderer, startPageName), "before:Asset");
-
-        // This goes first because an asset to be streamed may have an file extension, such as
-        // ".html", that will confuse the later dispatchers.
-
-        configuration.add(
-                "Asset",
-                new AssetDispatcher(streamer, aliasManager, resourceCache),
-                "before:PageRender");
-
-        configuration.add("PageRender", new PageRenderDispatcher(componentClassResolver,
-                pageLinkHandler, _pageResponseRenderer));
-
-        configuration.add(
-                "ComponentAction",
-                new ComponentActionDispatcher(actionLinkHandler),
-                "after:PageRender");
-    }
-
-    public ComponentClassResolver buildComponentClassResolver(
-            Collection<LibraryMapping> configuration)
-    {
-        ComponentClassResolverImpl service = new ComponentClassResolverImpl(
-                _componentInstantiatorSource, new ComponentClassLocatorImpl(), configuration);
-
-        // Allow the resolver to clean its cache when the source is invalidated
-
-        _componentInstantiatorSource.addInvalidationListener(service);
-
-        return service;
-    }
-
-    public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
-    {
-        configuration.add(new LibraryMapping("core", "org.apache.tapestry.corelib"));
-    }
-
-    public static BindingSource buildBindingSource(Map<String, BindingFactory> configuration)
-    {
-        return new BindingSourceImpl(configuration);
-    }
-
     /**
-     * Contributes the factory for serveral built-in binding prefixes ("literal", prop", "block",
-     * "component" "message", "validate", "translate").
+     * Contributes filter "StaticFilesFilter" that identifies requests for static resources and
+     * terminates the pipeline by returning false. Generally, most filters should be ordered after
+     * this filter.
      */
-    public static void contributeBindingSource(
-            MappedConfiguration<String, BindingFactory> configuration,
+    public static void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration,
+            @InjectService("Context")
+            Context context,
 
-            @InjectService("PropBindingFactory")
-            BindingFactory propBindingFactory,
+            @Inject("infrastructure:RequestExceptionHandler")
+            final RequestExceptionHandler exceptionHandler)
+    {
+        RequestFilter staticFilesFilter = new StaticFilesFilter(context);
 
-            @Inject("infrastructure:FieldValidatorSource")
-            FieldValidatorSource fieldValidatorSource,
+        configuration.add("StaticFiles", staticFilesFilter);
 
-            @Inject("infrastructure:TranslatorSource")
-            TranslatorSource translatorSource)
-    {
-        configuration.add(TapestryConstants.LITERAL_BINDING_PREFIX, new LiteralBindingFactory());
-        configuration.add(TapestryConstants.PROP_BINDING_PREFIX, propBindingFactory);
-        configuration.add("component", new ComponentBindingFactory());
-        configuration.add("message", new MessageBindingFactory());
-        configuration.add("validate", new ValidateBindingFactory(fieldValidatorSource));
-        configuration.add("translate", new TranslateBindingFactory(translatorSource));
-        configuration.add("block", new BlockBindingFactory());
-    }
+        RequestFilter errorFilter = new RequestFilter()
+        {
+            public boolean service(Request request, Response response, RequestHandler handler)
+                    throws IOException
+            {
+                try
+                {
+                    return handler.service(request, response);
+                }
+                catch (IOException ex)
+                {
+                    // Pass it through.
+                    throw ex;
+                }
+                catch (Throwable ex)
+                {
+                    exceptionHandler.handleRequestException(ex);
 
-    /**
-     * Returns a {@link ClassFactory} that can be used to create extra classes around component
-     * classes. This ClassFactory will be cleared whenever an underlying component class is
-     * discovered to have changed. Use of this class factory implies that your code will become
-     * aware of this (if necessary) to discard any cached object (alas, this currently involves
-     * dipping into the internals side to register for the correct notifications). Failure to
-     * properly clean up can result in really nasty PermGen space memory leaks.
-     */
-    public ClassFactory buildComponentClassFactory()
-    {
-        return _shadowBuilder.build(
-                _componentInstantiatorSource,
-                "classFactory",
-                ClassFactory.class);
-    }
+                    // We assume a reponse has been sent and there's no need to handle the request
+                    // further.
 
-    /**
-     * A chain of command for providing values for {@link org.apache.tapestry.annotations.Inject}-ed
-     * fields in component classes. The service's configuration can be extended to allow for
-     * different automatic injections (based on some combination of field type and field name).
-     */
+                    return true;
+                }
+            }
+        };
 
-    public InjectionProvider buildInjectionProvider(List<InjectionProvider> configuration)
-    {
-        return _chainBuilder.build(InjectionProvider.class, configuration);
+        configuration.add("ErrorFilter", errorFilter);
     }
 
     /**
-     * Contributes the elemental providers:
+     * Contributes the basic set of default translators:
      * <ul>
-     * <li>ComponentResources -- give component access to its resources</li>
-     * <li>CommonResources -- access to properties of resources (log, messages, etc.)</li>
-     * <li>Default -- looks for a unique IoC service that matches the field type</li>
-     * </ul>
+     * <li>Integer</li>
+     * <li>String</li>
+     * <li>Long</li>
+     * <li>Double</li>
+     * </li>
      */
-    public static void contributeInjectionProvider(
-            OrderedConfiguration<InjectionProvider> configuration)
+    public static void contributeTranslatorDefaultSource(
+            MappedConfiguration<Class, Translator> configuration)
     {
-        configuration.add("ComponentResources", new ComponentResourcesInjectionProvider());
-        configuration.add("CommonResources", new CommonResourcesInjectionProvider());
-        configuration.add("Default", new DefaultInjectionProvider(), "after:*.*");
+        configuration.add(Integer.class, new IntegerTranslator());
+        configuration.add(String.class, new StringTranslator());
+        configuration.add(Long.class, new LongTranslator());
+        configuration.add(Double.class, new DoubleTranslator());
     }
 
     /**
-     * Adds a number of standard component class transform workers:
+     * Contributes the basic set of named translators:
      * <ul>
-     * <li>Retain -- allows fields to retain their values between requests</li>
-     * <li>Persist -- allows fields to store their their value persistently between requests</li>
-     * <li>Parameter -- identifies parameters based on the
-     * {@link org.apache.tapestry.annotations.Parameter} annotation</li>
-     * <li>Component -- identifies embedded components based on the
-     * {@link org.apache.tapestry.annotations.Component} annotation</li>
-     * <li>Mixin -- adds a mixin as part of a component's implementation</li>
-     * <li>Environment -- allows fields to contain values extracted from the {@link Environment}
-     * service</li>
-     * <li>InjectNamed -- used with the {@link Inject} annotation, when a value is supplied</li>
-     * <li>InjectAnnonymous -- used with the {@link Inject} annotation, when no value is supplied</li>
-     * <li>InjectPage -- adds code to allow access to other pages via the {@link InjectPage} field
-     * annotation</li>
-     * <li>InjectBlock -- allows a block from the template to be injected into a field</li>
-     * <li>SupportsInformalParameters -- checks for the annotation</li>
-     * <li>Meta -- checks for meta data and adds it to the component model
-     * <li>ApplicationState -- converts fields that reference application state objects
-     * <li>UnclaimedField -- identifies unclaimed fields and resets them to null/0/false at the end
-     * of the request</li>
-     * <li>RenderCommand -- ensures all components also implement {@link RenderCommand}</li>
-     * <li>SetupRender, BeginRender, etc. -- correspond to component render phases and annotations</li>
+     * <li>integer</li>
+     * <li>string</li>
+     * <li>long</li>
+     * <li>double</li>
      * </ul>
      */
-    public static void contributeComponentClassTransformWorker(
-            OrderedConfiguration<ComponentClassTransformWorker> configuration,
-
-            ServiceLocator locator,
-
-            @InjectService("MasterObjectProvider")
-            ObjectProvider objectProvider,
-
-            @InjectService("InjectionProvider")
-            InjectionProvider injectionProvider,
-
-            @Inject("infrastructure:Environment")
-            Environment environment,
-
-            @Inject("infrastructure:ComponentClassResolver")
-            ComponentClassResolver resolver,
-
-            @InjectService("RequestPageCache")
-            RequestPageCache requestPageCache,
-
-            @Inject("infrastructure:AssetSource")
-            AssetSource assetSource,
-
-            @InjectService("SymbolSource")
-            SymbolSource symbolSource,
+    public static void contributeTranslatorSource(
+            MappedConfiguration<String, Translator> configuration)
+    {
+        // Fortunately, the translators are tiny, so we don't have to worry about the slight
+        // duplication between this and TranslatorDefaultSource, though it is a pain to keep the two
+        // organized (perhaps they should be joined together into a single service, where we
+        // identify a name and a match type).
 
-            @Inject("infrastructure:BindingSource")
-            BindingSource bindingsource,
+        configuration.add("integer", new IntegerTranslator());
+        configuration.add("string", new StringTranslator());
+        configuration.add("long", new LongTranslator());
+        configuration.add("double", new DoubleTranslator());
+    }
 
-            @Inject("infrastructure:ApplicationStateManager")
-            ApplicationStateManager applicationStateManager)
+    /**
+     * Adds coercions:
+     * <ul>
+     * <li>String to {@link SelectModel}
+     * <li>Map to {@link SelectModel}
+     * <li>List to {@link GridDataSource}
+     * <li>null to {@link GridDataSource}
+     * <li>String to {@link GridPagerPosition}
+     * <li>List to {@link SelectModel}
+     * </ul>
+     */
+    public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
     {
-        // TODO: Proper scheduling of all of this. Since a given field or method should
-        // only have a single annotation, the order doesn't matter so much, as long as
-        // UnclaimedField is last.
-
-        configuration.add("Meta", new MetaWorker());
-        configuration.add("ApplicationState", new ApplicationStateWorker(applicationStateManager));
-        configuration.add("InjectNamed", new InjectNamedWorker(objectProvider, locator));
-        configuration.add(
-                "InjectAnonymous",
-                new InjectAnonymousWorker(locator, injectionProvider),
-                "after:InjectNamed");
-        configuration.add(
-                "InjectAsset",
-                new InjectAssetWorker(assetSource, symbolSource),
-                "before:InjectNamed");
-        configuration.add("InjectBlock", new InjectBlockWorker(), "before:InjectNamed");
+        add(configuration, String.class, SelectModel.class, new Coercion<String, SelectModel>()
+        {
+            public SelectModel coerce(String input)
+            {
+                return TapestryInternalUtils.toSelectModel(input);
+            }
+        });
 
-        configuration.add("MixinAfter", new MixinAfterWorker());
-        configuration.add("Component", new ComponentWorker(resolver));
-        configuration.add("Environment", new EnvironmentalWorker(environment));
-        configuration.add("Mixin", new MixinWorker(resolver));
-        configuration.add("OnEvent", new OnEventWorker());
-        configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
-        configuration.add("InjectPage", new InjectPageWorker(requestPageCache));
-        configuration.add("InjectComponent", new InjectComponentWorker());
-        configuration.add("RenderCommand", new RenderCommandWorker());
+        add(configuration, Map.class, SelectModel.class, new Coercion<Map, SelectModel>()
+        {
+            @SuppressWarnings("unchecked")
+            public SelectModel coerce(Map input)
+            {
+                return TapestryInternalUtils.toSelectModel(input);
+            }
+        });
 
-        // Default values for parameters are often some form of injection, so make sure
-        // that Parameter fields are processed after injections.
+        add(configuration, List.class, GridDataSource.class, new Coercion<List, GridDataSource>()
+        {
+            public GridDataSource coerce(List input)
+            {
+                return new ListGridDataSource(input);
+            }
+        });
 
-        configuration.add("Parameter", new ParameterWorker(bindingsource), "after:Inject*");
+        add(configuration, void.class, GridDataSource.class, new Coercion<Void, GridDataSource>()
+        {
+            private final GridDataSource _source = new NullDataSource();
 
-        // Workers for the component rendering state machine methods; this is in typical
-        // execution order.
+            public GridDataSource coerce(Void input)
+            {
+                return _source;
+            }
+        });
 
-        add(configuration, TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class, false);
-        add(configuration, TransformConstants.BEGIN_RENDER_SIGNATURE, BeginRender.class, false);
-        add(
-                configuration,
-                TransformConstants.BEFORE_RENDER_TEMPLATE_SIGNATURE,
-                BeforeRenderTemplate.class,
-                false);
         add(
                 configuration,
-                TransformConstants.BEFORE_RENDER_BODY_SIGNATURE,
-                BeforeRenderBody.class,
-                false);
-
-        // These phases operate in reverse order.
+                String.class,
+                GridPagerPosition.class,
+                new StringToEnumCoercion<GridPagerPosition>(GridPagerPosition.class));
 
-        add(
-                configuration,
-                TransformConstants.AFTER_RENDER_BODY_SIGNATURE,
-                AfterRenderBody.class,
-                true);
-        add(
-                configuration,
-                TransformConstants.AFTER_RENDER_TEMPLATE_SIGNATURE,
-                AfterRenderTemplate.class,
-                true);
-        add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class, true);
-        add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class, true);
+        add(configuration, List.class, SelectModel.class, new Coercion<List, SelectModel>()
+        {
+            @SuppressWarnings("unchecked")
+            public SelectModel coerce(List input)
+            {
+                return TapestryInternalUtils.toSelectModel(input);
+            }
+        });
+    }
 
-        // Ideally, these should be ordered pretty late in the process to make sure there are no
-        // side effects
-        // with other workers that do work inside the page lifecycle methods.
+    /**
+     * Adds built-in constraint generators:
+     * <ul>
+     * <li>PrimtiveField -- primitive fields are always required
+     * <li>ValidateAnnotation -- adds constraints from a {@link Validate} annotation
+     * </ul>
+     */
+    public static void contributeValidationConstraintGenerator(
+            OrderedConfiguration<ValidationConstraintGenerator> configuration)
+    {
+        configuration.add("PrimitiveField", new PrimitiveFieldConstraintGenerator());
+        configuration.add("ValidateAnnotation", new ValidateAnnotationConstraintGenerator());
+    }
 
-        add(
-                configuration,
-                PageLoaded.class,
-                TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
-                "pageLoaded");
-        add(
-                configuration,
-                PageAttached.class,
-                TransformConstants.CONTAINING_PAGE_DID_ATTACH_SIGNATURE,
-                "pageAttached");
-        add(
-                configuration,
-                PageDetached.class,
-                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
-                "pageDetached");
+    private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
+            Class<T> targetType, Coercion<S, T> coercion)
+    {
+        CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion);
 
-        configuration.add("Retain", new RetainWorker());
-        configuration.add("Persist", new PersistWorker());
-        configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*.*");
+        configuration.add(tuple);
     }
 
-    private static void add(OrderedConfiguration<ComponentClassTransformWorker> configuration,
-            MethodSignature signature, Class<? extends Annotation> annotationClass, boolean reverse)
+    /**
+     * Invoked from
+     * {@link #contributeInfrastructure(Configuration, ServiceLocator, Request, Response, TypeCoercer)}
+     * to contribute services from the tapestry module where the unqualified class name of the
+     * service interface matches the unqualified service id. This unqualified name is used as the
+     * infrastructure alias.
+     */
+    @SuppressWarnings("unchecked")
+    private static void add(Configuration<InfrastructureContribution> configuration,
+            ServiceLocator locator, Class... serviceInterfaces)
     {
-        // make the name match the annotation class name.
+        for (Class serviceInterface : serviceInterfaces)
+        {
+            String serviceId = TapestryInternalUtils.lastTerm(serviceInterface.getName());
 
-        String name = TapestryInternalUtils.lastTerm(annotationClass.getName());
+            Object service = locator.getService(serviceId, serviceInterface);
 
-        configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass,
-                reverse));
+            InfrastructureContribution contribution = new InfrastructureContribution(serviceId,
+                    service);
+
+            configuration.add(contribution);
+        }
     }
 
     private static void add(OrderedConfiguration<ComponentClassTransformWorker> configuration,
@@ -937,148 +916,132 @@
         configuration.add(name, worker);
     }
 
-    @Lifecycle("perthread")
-    public static Environment buildEnvironment()
+    private static void add(OrderedConfiguration<ComponentClassTransformWorker> configuration,
+            MethodSignature signature, Class<? extends Annotation> annotationClass, boolean reverse)
     {
-        return new EnvironmentImpl();
+        // make the name match the annotation class name.
+
+        String name = TapestryInternalUtils.lastTerm(annotationClass.getName());
+
+        configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass,
+                reverse));
     }
 
-    /**
-     * Controls setup and cleanup of the environment during page rendering (the generation of a
-     * markup stream response for the client web browser).
-     */
-    public PageRenderInitializer buildPageRenderInitializer(
-            final List<PageRenderCommand> configuration)
-    {
-        return new PageRenderInitializer()
-        {
-            public void setup(MarkupWriter writer)
-            {
-                _environment.clear();
+    private final ChainBuilder _chainBuilder;
 
-                _environment.push(MarkupWriter.class, writer);
-                _environment.push(Document.class, writer.getDocument());
+    private final PipelineBuilder _pipelineBuilder;
 
-                for (PageRenderCommand command : configuration)
-                    command.setup(_environment);
-            }
+    private final RequestGlobals _requestGlobals;
 
-            public void cleanup(MarkupWriter writer)
-            {
-                Iterator<PageRenderCommand> i = InternalUtils.reverseIterator(configuration);
+    private final ApplicationGlobals _applicationGlobals;
 
-                while (i.hasNext())
-                    i.next().cleanup(_environment);
+    private final PropertyShadowBuilder _shadowBuilder;
 
-                _environment.clear();
-            }
-        };
-    }
+    private final RequestPageCache _requestPageCache;
 
-    public void contributePageRenderInitializer(
-            OrderedConfiguration<PageRenderCommand> configuration,
+    private final PageResponseRenderer _pageResponseRenderer;
 
-            @InjectService("ThreadLocale")
-            ThreadLocale threadLocale,
+    private final Request _request;
 
-            @Inject("infrastructure:AssetSource")
-            AssetSource assetSource,
+    private final Environment _environment;
 
-            @Inject("infrastructure:ValidationMessagesSource")
-            ValidationMessagesSource validationMessagesSource,
+    private final StrategyBuilder _strategyBuilder;
 
-            @Inject("service:SymbolSource")
-            final SymbolSource symbolSource,
+    private final ComponentInstantiatorSource _componentInstantiatorSource;
+
+    private final LinkFactory _linkFactory;
+
+    private final PropertyAccess _propertyAccess;
+
+    private final PropertyConduitSource _propertyConduitSource;
+
+    private final ClassFactory _componentClassFactory;
+
+    public TapestryModule(@InjectService("PipelineBuilder")
+    PipelineBuilder pipelineBuilder,
+
+    @InjectService("PropertyShadowBuilder")
+    PropertyShadowBuilder shadowBuilder,
 
-            @Inject("service:ClasspathAssetFactory")
-            final AssetFactory classpathAssetFactory)
-    {
-        configuration.add("PageRenderSupport", new PageRenderCommand()
-        {
-            public void setup(Environment environment)
-            {
-                DocumentScriptBuilder builder = new DocumentScriptBuilderImpl();
+    @Inject("infrastructure:RequestGlobals")
+    RequestGlobals requestGlobals,
 
-                environment.push(DocumentScriptBuilder.class, builder);
-                environment.push(PageRenderSupport.class, new PageRenderSupportImpl(builder,
-                        symbolSource, classpathAssetFactory));
-            }
+    @Inject("infrastructure:ApplicationGlobals")
+    ApplicationGlobals applicationGlobals,
 
-            public void cleanup(Environment environment)
-            {
-                environment.pop(PageRenderSupport.class);
+    @InjectService("ChainBuilder")
+    ChainBuilder chainBuilder,
 
-                Document document = environment.peek(Document.class);
+    @InjectService("RequestPageCache")
+    RequestPageCache requestPageCache,
 
-                DocumentScriptBuilder builder = environment.pop(DocumentScriptBuilder.class);
+    @InjectService("PageResponseRenderer")
+    PageResponseRenderer pageResponseRenderer,
 
-                builder.updateDocument(document);
-            }
-        });
+    @Inject("infrastructure:Request")
+    Request request,
 
-        configuration.add("Heartbeat", new PageRenderCommand()
-        {
-            public void setup(Environment environment)
-            {
-                HeartbeatImpl heartbeat = new HeartbeatImpl();
+    @Inject("infrastructure:Environment")
+    Environment environment,
 
-                heartbeat.begin();
+    @InjectService("StrategyBuilder")
+    StrategyBuilder strategyBuilder,
 
-                environment.push(Heartbeat.class, heartbeat);
-            }
+    @InjectService("ComponentInstantiatorSource")
+    ComponentInstantiatorSource componentInstantiatorSource,
 
-            public void cleanup(Environment environment)
-            {
-                environment.pop(Heartbeat.class).end();
-            }
-        });
+    @InjectService("LinkFactory")
+    LinkFactory linkFactory,
 
-        configuration.add("InjectStandardStylesheet", new InjectStandardStylesheetCommand(
-                threadLocale, assetSource));
+    @Inject("infrastructure:PropertyConduitSource")
+    PropertyConduitSource propertyConduitSource,
 
-        Asset iconAsset = assetSource.getClasspathAsset(
-                "org/apache/tapestry/field-error-marker.png",
-                Locale.ENGLISH);
+    @Inject("infrastructure:PropertyAccess")
+    PropertyAccess propertyAccess,
 
-        configuration.add("DefaultValidationDelegate", new DefaultValidationDelegateCommand(
-                threadLocale, validationMessagesSource, iconAsset));
+    @InjectService("ComponentClassFactory")
+    ClassFactory componentClassFactory)
+    {
+        _pipelineBuilder = pipelineBuilder;
+        _shadowBuilder = shadowBuilder;
+        _requestGlobals = requestGlobals;
+        _applicationGlobals = applicationGlobals;
+        _chainBuilder = chainBuilder;
+        _requestPageCache = requestPageCache;
+        _pageResponseRenderer = pageResponseRenderer;
+        _request = request;
+        _environment = environment;
+        _strategyBuilder = strategyBuilder;
+        _componentInstantiatorSource = componentInstantiatorSource;
+        _linkFactory = linkFactory;
+        _propertyAccess = propertyAccess;
+        _propertyConduitSource = propertyConduitSource;
+        _componentClassFactory = componentClassFactory;
     }
 
-    /** A public service since extensions may provide new persistent strategies. */
-    public static PersistentFieldManager buildPersistentFieldManager(
-            @Inject("infrastructure:MetaDataLocator")
-            MetaDataLocator locator,
-
-            Map<String, PersistentFieldStrategy> configuration)
+    public Context build(@InjectService("ApplicationGlobals")
+    ApplicationGlobals globals)
     {
-        return new PersistentFieldManagerImpl(locator, configuration);
+        return _shadowBuilder.build(globals, "context", Context.class);
     }
 
     /**
-     * Contributes the "session" strategy.
+     * A service for building proxies that shadow a value stored in the {@link Environment}.
      */
-    public void contributePersistentFieldManager(
-            MappedConfiguration<String, PersistentFieldStrategy> configuration,
-
-            @InjectService("SessionHolder")
-            SessionHolder sessionHolder)
+    public EnvironmentalShadowBuilder build(@Inject("service:ClassFactory")
+    ClassFactory classFactory)
     {
-        configuration.add("session", new SessionPersistentFieldStrategy(sessionHolder));
-        configuration.add("flash", new FlashPersistentFieldStrategy(sessionHolder));
+        return new EnvironmentalShadowBuilderImpl(classFactory, _environment);
     }
 
-    public ComponentSource buildComponentSource(@InjectService("RequestPageCache")
-    RequestPageCache pageCache)
+    public ComponentClassResolver build(Collection<LibraryMapping> configuration)
     {
-        return new ComponentSourceImpl(pageCache);
-    }
+        ComponentClassResolverImpl service = new ComponentClassResolverImpl(
+                _componentInstantiatorSource, new ComponentClassLocatorImpl(), configuration);
 
-    public ComponentMessagesSource buildComponentMessagesSource(@InjectService("UpdateListenerHub")
-    UpdateListenerHub updateListenerHub)
-    {
-        ComponentMessagesSourceImpl service = new ComponentMessagesSourceImpl();
+        // Allow the resolver to clean its cache when the source is invalidated
 
-        updateListenerHub.addUpdateListener(service);
+        _componentInstantiatorSource.addInvalidationListener(service);
 
         return service;
     }
@@ -1088,7 +1051,7 @@
      * paths to message bundles (resource paths within the classpath); the default contribution is
      * "org/apache/tapestry/internal/ValidationMessages".
      */
-    public ValidationMessagesSource buildValidationMessagesSource(Collection<String> configuration,
+    public ValidationMessagesSource build(Collection<String> configuration,
             @InjectService("UpdateListenerHub")
             UpdateListenerHub updateListenerHub,
 
@@ -1103,214 +1066,173 @@
         return service;
     }
 
-    public void contributeValidationMessagesSource(Configuration<String> configuration)
-    {
-        configuration.add("org/apache/tapestry/internal/ValidationMessages");
-    }
-
-    public static AssetSource buildAssetSource(Map<String, AssetFactory> configuration)
-    {
-        return new AssetSourceImpl(configuration);
-    }
-
-    public void contributeAssetSource(MappedConfiguration<String, AssetFactory> configuration,
-            @InjectService("ContextAssetFactory")
-            AssetFactory contextAssetFactory,
-
-            @InjectService("ClasspathAssetFactory")
-            AssetFactory classpathAssetFactory)
-    {
-        configuration.add("context", contextAssetFactory);
-        configuration.add("classpath", classpathAssetFactory);
-    }
-
-    public static ResourceDigestGenerator buildResourceDigestGenerator()
-    {
-        return new ResourceDigestGeneratorImpl();
-    }
-
-    public static ClasspathAssetAliasManager buildClasspathAssetAliasManager(
-            @InjectService("ContextPathSource")
-            ContextPathSource contextPathSource, Map<String, String> configuration)
-    {
-        return new ClasspathAssetAliasManagerImpl(contextPathSource, configuration);
-    }
-
-    public static void contributeClasspathAssetAliasManager(
-            MappedConfiguration<String, String> configuration,
+    public MetaDataLocator build(@Inject("infrastructure:ComponentClassResolver")
+    ComponentClassResolver componentClassResolver,
 
-            @Inject("${tapestry.scriptaculous.path}")
-            String scriptaculousPath)
+    Map<String, String> configuration)
     {
-        configuration.add("tapestry/", "org/apache/tapestry/");
-
-        configuration.add("scriptaculous/", scriptaculousPath + "/");
-    }
-
-    public static FieldValidatorSource buildFieldValidatorSource(
-            @Inject("infrastructure:ValidationMessagesSource")
-            ValidationMessagesSource messagesSource,
-
-            @Inject("infrastructure:TypeCoercer")
-            TypeCoercer typeCoercer,
+        MetaDataLocatorImpl service = new MetaDataLocatorImpl(componentClassResolver, configuration);
 
-            @Inject("service:PageRenderSupport")
-            PageRenderSupport pageRenderSupport,
+        _componentInstantiatorSource.addInvalidationListener(service);
 
-            Map<String, Validator> configuration)
-    {
-        return new FieldValidatorSourceImpl(messagesSource, typeCoercer, pageRenderSupport,
-                configuration);
+        return service;
     }
 
     /**
-     * Contributes the basic set of validators:
-     * <ul>
-     * <li>required</li>
-     * <li>minlength</li>
-     * <li>maxlength</li>
-     * <li>min</li>
-     * <li>max</li>
-     * </ul>
+     * Builds a proxy to the current PageRenderSupport inside this thread's {@link Environment}.
      */
-    public static void contributeFieldValidatorSource(
-            MappedConfiguration<String, Validator> configuration)
+    public PageRenderSupport build(@Inject("service:EnvironmentalShadowBuilder")
+    EnvironmentalShadowBuilder builder)
     {
-        configuration.add("required", new Required());
-        configuration.add("minlength", new MinLength());
-        configuration.add("maxlength", new MaxLength());
-        configuration.add("min", new Min());
-        configuration.add("max", new Max());
+        return builder.build(PageRenderSupport.class);
     }
 
-    public static TranslatorSource buildTranslatorSource(Map<String, Translator> configuration)
+    /**
+     * Allows the exact steps in the component class transformation process to be defined.
+     */
+    public ComponentClassTransformWorker build(List<ComponentClassTransformWorker> configuration)
     {
-        return new TranslatorSourceImpl(configuration);
+        return _chainBuilder.build(ComponentClassTransformWorker.class, configuration);
     }
 
-    public TranslatorDefaultSource buildTranslatorDefaultSource(Map<Class, Translator> configuration)
+    public DataTypeAnalyzer build(List<DataTypeAnalyzer> configuration)
     {
-        TranslatorDefaultSourceImpl service = new TranslatorDefaultSourceImpl(configuration);
-
-        _componentInstantiatorSource.addInvalidationListener(service);
-
-        return service;
+        return _chainBuilder.build(DataTypeAnalyzer.class, configuration);
     }
 
     /**
-     * Contributes the basic set of named translators:
-     * <ul>
-     * <li>integer</li>
-     * <li>string</li>
-     * <li>long</li>
-     * <li>double</li>
-     * </ul>
+     * A chain of command for providing values for {@link org.apache.tapestry.annotations.Inject}-ed
+     * fields in component classes. The service's configuration can be extended to allow for
+     * different automatic injections (based on some combination of field type and field name).
      */
-    public static void contributeTranslatorSource(
-            MappedConfiguration<String, Translator> configuration)
-    {
-        // Fortunately, the translators are tiny, so we don't have to worry about the slight
-        // duplication between this and TranslatorDefaultSource, though it is a pain to keep the two
-        // organized (perhaps they should be joined together into a single service, where we
-        // identify a name and a match type).
-
-        configuration.add("integer", new IntegerTranslator());
-        configuration.add("string", new StringTranslator());
-        configuration.add("long", new LongTranslator());
-        configuration.add("double", new DoubleTranslator());
-    }
 
-    /**
-     * Contributes the basic set of default translators:
-     * <ul>
-     * <li>Integer</li>
-     * <li>String</li>
-     * <li>Long</li>
-     * <li>Double</li>
-     * </li>
-     */
-    public static void contributeTranslatorDefaultSource(
-            MappedConfiguration<Class, Translator> configuration)
+    public InjectionProvider build(List<InjectionProvider> configuration)
     {
-        configuration.add(Integer.class, new IntegerTranslator());
-        configuration.add(String.class, new StringTranslator());
-        configuration.add(Long.class, new LongTranslator());
-        configuration.add(Double.class, new DoubleTranslator());
+        return _chainBuilder.build(InjectionProvider.class, configuration);
     }
 
     /**
-     * Adds coercions:
-     * <ul>
-     * <li>String to {@link SelectModel}
-     * <li>Map to {@link SelectModel}
-     * <li>List to {@link GridDataSource}
-     * <li>null to {@link GridDataSource}
-     * <li>String to {@link GridPagerPosition}
-     * <li>List to {@link SelectModel}
-     * </ul>
+     * Controls setup and cleanup of the environment during page rendering (the generation of a
+     * markup stream response for the client web browser).
      */
-    public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
+    public PageRenderInitializer build(final List<PageRenderCommand> configuration)
     {
-        add(configuration, String.class, SelectModel.class, new Coercion<String, SelectModel>()
+        return new PageRenderInitializer()
         {
-            public SelectModel coerce(String input)
+            public void cleanup(MarkupWriter writer)
             {
-                return TapestryInternalUtils.toSelectModel(input);
+                Iterator<PageRenderCommand> i = InternalUtils.reverseIterator(configuration);
+
+                while (i.hasNext())
+                    i.next().cleanup(_environment);
+
+                _environment.clear();
             }
-        });
 
-        add(configuration, Map.class, SelectModel.class, new Coercion<Map, SelectModel>()
-        {
-            @SuppressWarnings("unchecked")
-            public SelectModel coerce(Map input)
+            public void setup(MarkupWriter writer)
             {
-                return TapestryInternalUtils.toSelectModel(input);
+                _environment.clear();
+
+                _environment.push(MarkupWriter.class, writer);
+                _environment.push(Document.class, writer.getDocument());
+
+                for (PageRenderCommand command : configuration)
+                    command.setup(_environment);
             }
-        });
+        };
+    }
 
-        add(configuration, List.class, GridDataSource.class, new Coercion<List, GridDataSource>()
+    /** Initializes the application. */
+    public ApplicationInitializer build(Log log, List<ApplicationInitializerFilter> configuration)
+    {
+        ApplicationInitializer terminator = new ApplicationInitializer()
         {
-            public GridDataSource coerce(List input)
+            public void initializeApplication(Context context)
             {
-                return new ListGridDataSource(input);
+                _applicationGlobals.store(context);
             }
-        });
+        };
 
-        add(configuration, void.class, GridDataSource.class, new Coercion<Void, GridDataSource>()
-        {
-            private final GridDataSource _source = new NullDataSource();
+        return _pipelineBuilder.build(
+                log,
+                ApplicationInitializer.class,
+                ApplicationInitializerFilter.class,
+                configuration,
+                terminator);
+    }
 
-            public GridDataSource coerce(Void input)
+    public HttpServletRequestHandler build(Log log, List<HttpServletRequestFilter> configuration,
+
+    @InjectService("RequestHandler")
+    final RequestHandler handler)
+    {
+        HttpServletRequestHandler terminator = new HttpServletRequestHandler()
+        {
+            public boolean service(HttpServletRequest request, HttpServletResponse response)
+                    throws IOException
             {
-                return _source;
+                _requestGlobals.store(request, response);
+
+                return handler.service(new RequestImpl(request), new ResponseImpl(response));
             }
-        });
+        };
 
-        add(
+        return _pipelineBuilder.build(
+                log,
+                HttpServletRequestHandler.class,
+                HttpServletRequestFilter.class,
                 configuration,
-                String.class,
-                GridPagerPosition.class,
-                new StringToEnumCoercion<GridPagerPosition>(GridPagerPosition.class));
+                terminator);
+    }
 
-        add(configuration, List.class, SelectModel.class, new Coercion<List, SelectModel>()
+    public RequestHandler build(Log log, List<RequestFilter> configuration,
+            @InjectService("MasterDispatcher")
+            final Dispatcher masterDispatcher)
+    {
+        RequestHandler terminator = new RequestHandler()
         {
-            @SuppressWarnings("unchecked")
-            public SelectModel coerce(List input)
+            public boolean service(Request request, Response response) throws IOException
             {
-                return TapestryInternalUtils.toSelectModel(input);
+                _requestGlobals.store(request, response);
+
+                return masterDispatcher.dispatch(request, response);
             }
-        });
+        };
+
+        return _pipelineBuilder.build(
+                log,
+                RequestHandler.class,
+                RequestFilter.class,
+                configuration,
+                terminator);
     }
 
-    private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
-            Class<T> targetType, Coercion<S, T> coercion)
+    public ServletApplicationInitializer build(Log log,
+            List<ServletApplicationInitializerFilter> configuration,
+            @InjectService("ApplicationInitializer")
+            final ApplicationInitializer initializer)
     {
-        CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion);
+        ServletApplicationInitializer terminator = new ServletApplicationInitializer()
+        {
+            public void initializeApplication(ServletContext context)
+            {
+                _applicationGlobals.store(context);
 
-        configuration.add(tuple);
+                // And now, down the (Web) ApplicationInitializer pipeline ...
+
+                initializer.initializeApplication(new ContextImpl(context));
+            }
+        };
+
+        return _pipelineBuilder.build(
+                log,
+                ServletApplicationInitializer.class,
+                ServletApplicationInitializerFilter.class,
+                configuration,
+                terminator);
     }
 
-    public ComponentEventResultProcessor buildComponentEventResultProcessor(
+    public ComponentEventResultProcessor build(
             Map<Class, ComponentEventResultProcessor> configuration)
     {
         // A slight hack!
@@ -1326,109 +1248,49 @@
     }
 
     /**
-     * Contributes handlers for the following types:
-     * <dl>
-     * <dt>Object</dt>
-     * <dd>Failure case, added to provide a more useful exception message</dd>
-     * <dt>ActionResponseGenerator</dt>
-     * <dd>Returns the ActionResponseGenerator; this sometimes occurs when a component generates
-     * events whose return values are converted to ActionResponseGenerators (this handles that
-     * bubble up case).</dd>
-     * <dt>Link</dt>
-     * <dd>Wraps the Link to send a redirect</dd>
-     * <dt>String</dt>
-     * <dd>The name of the page to render the response (after a redirect)</dd>
-     * </dl>
+     * The default data type analyzer is the final analyzer consulted and identifies the type
+     * entirely pased on the property type, working against its own configuration (mapping property
+     * type class to data type).
      */
-    public void contributeComponentEventResultProcessor(
-            @InjectService("ComponentInstanceResultProcessor")
-            ComponentEventResultProcessor componentInstanceProcessor,
-
-            MappedConfiguration<Class, ComponentEventResultProcessor> configuration)
+    public DataTypeAnalyzer buildDefaultDataTypeAnalyzer(Map<Class, String> configuration)
     {
-        configuration.add(
-                ActionResponseGenerator.class,
-                new ComponentEventResultProcessor<ActionResponseGenerator>()
-                {
-                    public ActionResponseGenerator processComponentEvent(
-                            ActionResponseGenerator value, Component component,
-                            String methodDescripion)
-                    {
-                        return value;
-                    }
-                });
-
-        configuration.add(Link.class, new ComponentEventResultProcessor<Link>()
-        {
-
-            public ActionResponseGenerator processComponentEvent(Link value, Component component,
-                    String methodDescripion)
-            {
-                return new LinkActionResponseGenerator(value);
-            }
-        });
-
-        configuration.add(String.class, new StringResultProcessor(_requestPageCache, _linkFactory));
-
-        configuration.add(Component.class, componentInstanceProcessor);
+        DefaultDataTypeAnalyzer service = new DefaultDataTypeAnalyzer(configuration);
 
-        configuration.add(StreamResponse.class, new StreamResponseResultProcessor());
-    }
+        _componentInstantiatorSource.addInvalidationListener(service);
 
-    public ComponentEventResultProcessor buildComponentInstanceResultProcessor(Log log)
-    {
-        return new ComponentInstanceResultProcessor(_requestPageCache, _linkFactory, log);
+        return service;
     }
 
-    public static PersistentLocale buildPersistentLocale(@InjectService("Cookies")
-    Cookies cookies)
+    public TranslatorDefaultSource build(Map<Class, Translator> configuration)
     {
-        return new PersistentLocaleImpl(cookies);
-    }
-
-    public static Cookies buildCookies(@InjectService("ContextPathSource")
-    ContextPathSource contextPathSource,
-
-    @InjectService("CookieSource")
-    CookieSource cookieSource,
+        TranslatorDefaultSourceImpl service = new TranslatorDefaultSourceImpl(configuration);
 
-    @InjectService("CookieSink")
-    CookieSink cookieSink,
+        _componentInstantiatorSource.addInvalidationListener(service);
 
-    @Inject("${tapestry.default-cookie-max-age}")
-    int defaultMaxAge)
-    {
-        return new CookiesImpl(contextPathSource, cookieSource, cookieSink, defaultMaxAge);
+        return service;
     }
 
-    public static ApplicationStatePersistenceStrategySource buildApplicationStatePersistenceStrategySource(
-            Map<String, ApplicationStatePersistenceStrategy> configuration)
+    public ComponentSource build(@InjectService("RequestPageCache")
+    RequestPageCache pageCache)
     {
-        return new ApplicationStatePersistenceStrategySourceImpl(configuration);
+        return new ComponentSourceImpl(pageCache);
     }
 
-    /** Contributes the default "session" strategy. */
-    public void contributeApplicationStatePersistenceStrategySource(
-            MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration)
+    public ObjectRenderer build(@InjectService("StrategyBuilder")
+    StrategyBuilder strategyBuilder, Map<Class, ObjectRenderer> configuration)
     {
-        configuration.add("session", new SessionApplicationStatePersistenceStrategy(_request));
-    }
+        StrategyRegistry<ObjectRenderer> registry = StrategyRegistry.newInstance(
+                ObjectRenderer.class,
+                configuration);
 
-    public static ApplicationStateManager buildApplicationStateManager(
-            Map<Class, ApplicationStateContribution> configuration,
-            @Inject("infrastructure:ApplicationStatePersistenceStrategySource")
-            ApplicationStatePersistenceStrategySource source)
-    {
-        return new ApplicationStateManagerImpl(configuration, source);
+        return _strategyBuilder.build(registry);
     }
 
     /**
      * The configuration of the model source is a mapping from type to string. The types are
      * property types and the values, the strings, represent different type of editors.
      */
-    public BeanModelSource buildBeanModelSource(
-
-    @Inject("infrastructure:TypeCoercer")
+    public BeanModelSource build(@Inject("infrastructure:TypeCoercer")
     TypeCoercer typeCoercer,
 
     @InjectService("DataTypeAnalyzer")
@@ -1438,94 +1300,51 @@
                 _componentClassFactory, analyzer);
     }
 
-    public DataTypeAnalyzer buildDataTypeAnalyzer(List<DataTypeAnalyzer> configuration)
-    {
-        return _chainBuilder.build(DataTypeAnalyzer.class, configuration);
-    }
-
-    /**
-     * Adds the {@link #buildDefaultDataTypeAnalyzer(Map) DefaultDatatTypeAnalyzer} to the
-     * configuration, ordered explicitly last.
-     */
-    public static void contributeDataTypeAnalyzer(
-            OrderedConfiguration<DataTypeAnalyzer> configuration,
-            @InjectService("DefaultDataTypeAnalyzer")
-            DataTypeAnalyzer defaultDataTypeAnalyzer)
-    {
-        configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
-    }
-
-    /**
-     * The default data type analyzer is the final analyzer consulted and identifies the type
-     * entirely pased on the property type, working against its own configuration (mapping property
-     * type class to data type).
-     */
-    public DataTypeAnalyzer buildDefaultDataTypeAnalyzer(Map<Class, String> configuration)
+    public ComponentMessagesSource build(@InjectService("UpdateListenerHub")
+    UpdateListenerHub updateListenerHub)
     {
-        DefaultDataTypeAnalyzer service = new DefaultDataTypeAnalyzer(configuration);
+        ComponentMessagesSourceImpl service = new ComponentMessagesSourceImpl();
 
-        _componentInstantiatorSource.addInvalidationListener(service);
+        updateListenerHub.addUpdateListener(service);
 
         return service;
     }
 
     /**
-     * Maps property types to data type names
-     * <ul>
-     * <li>String --&gt; text
-     * <li>Number --&gt; text
-     * <li>Enum --&gt; enum
-     * <li>Boolean --&gt; checkbox
-     * </ul>
+     * Returns a {@link ClassFactory} that can be used to create extra classes around component
+     * classes. This ClassFactory will be cleared whenever an underlying component class is
+     * discovered to have changed. Use of this class factory implies that your code will become
+     * aware of this (if necessary) to discard any cached object (alas, this currently involves
+     * dipping into the internals side to register for the correct notifications). Failure to
+     * properly clean up can result in really nasty PermGen space memory leaks.
      */
-    public static void contributeDefaultDataTypeAnalyzer(
-            MappedConfiguration<Class, String> configuration)
+    public ClassFactory buildComponentClassFactory()
     {
-        // This is a special case contributed to avoid exceptions when a property type can't be
-        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
-
-        configuration.add(Object.class, "");
-
-        configuration.add(String.class, "text");
-
-        // This may change; as currently implemented, "text" refers more to the edit component
-        // (TextField) than to
-        // the "flavor" of data.
+        return _shadowBuilder.build(
+                _componentInstantiatorSource,
+                "classFactory",
+                ClassFactory.class);
+    }
 
-        configuration.add(Number.class, "text");
-        configuration.add(Enum.class, "enum");
-        configuration.add(Boolean.class, "checkbox");
+    public ComponentEventResultProcessor buildComponentInstanceResultProcessor(Log log)
+    {
+        return new ComponentInstanceResultProcessor(_requestPageCache, _linkFactory, log);
     }
 
-    public static ValidationConstraintGenerator buildValidationConstraintGenerator(
-            List<ValidationConstraintGenerator> configuration)
+    public DefaultComponentParameterBindingSource buildDefaultComponentParameterBindingSource(
+            @Inject("infrastructure:BindingSource")
+            BindingSource bindingSource)
     {
-        return new ValidationConstraintGeneratorImpl(configuration);
+        return new DefaultComponentParameterBindingSourceImpl(_propertyAccess, bindingSource);
     }
 
     /**
-     * Adds built-in constraint generators:
-     * <ul>
-     * <li>PrimtiveField -- primitive fields are always required
-     * <li>ValidateAnnotation -- adds constraints from a {@link Validate} annotation
-     * </ul>
+     * Ordered contributions to the MasterDispatcher service allow different URL matching strategies
+     * to occur.
      */
-    public static void contributeValidationConstraintGenerator(
-            OrderedConfiguration<ValidationConstraintGenerator> configuration)
-    {
-        configuration.add("PrimitiveField", new PrimitiveFieldConstraintGenerator());
-        configuration.add("ValidateAnnotation", new ValidateAnnotationConstraintGenerator());
-    }
-
-    public static FieldValidatorDefaultSource buildFieldValidatorDefaultSource(
-            @Inject("infrastructure:ValidationConstraintGenerator")
-            ValidationConstraintGenerator validationConstraintGenerator,
-
-            @Inject("infrastructure:FieldValidatorSource")
-            FieldValidatorSource fieldValidatorSource)
+    public Dispatcher buildMasterDispatcher(List<Dispatcher> configuration)
     {
-        return new FieldValidatorDefaultSourceImpl(validationConstraintGenerator,
-                fieldValidatorSource);
+        return _chainBuilder.build(Dispatcher.class, configuration);
     }
 
     public PropertyConduitSource buildPropertyConduitSource()
@@ -1538,40 +1357,141 @@
         return service;
     }
 
-    public MetaDataLocator buildMetaDataLocator(@Inject("infrastructure:ComponentClassResolver")
-    ComponentClassResolver componentClassResolver,
+    /**
+     * Builds a shadow of the RequestGlobals.request property. Note again that the shadow can be an
+     * ordinary singleton, even though RequestGlobals is perthread.
+     */
+    public Request buildRequest()
+    {
+        return _shadowBuilder.build(_requestGlobals, "request", Request.class);
+    }
 
-    Map<String, String> configuration)
+    /**
+     * Builds a shadow of the RequestGlobals.response property. Note again that the shadow can be an
+     * ordinary singleton, even though RequestGlobals is perthread.
+     */
+    public Response buildResponse()
     {
-        MetaDataLocatorImpl service = new MetaDataLocatorImpl(componentClassResolver, configuration);
+        return _shadowBuilder.build(_requestGlobals, "response", Response.class);
+    }
 
-        _componentInstantiatorSource.addInvalidationListener(service);
+    /** Contributes the default "session" strategy. */
+    public void contributeApplicationStatePersistenceStrategySource(
+            MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration)
+    {
+        configuration.add("session", new SessionApplicationStatePersistenceStrategy(_request));
+    }
 
-        return service;
+    public void contributeAssetSource(MappedConfiguration<String, AssetFactory> configuration,
+            @InjectService("ContextAssetFactory")
+            AssetFactory contextAssetFactory,
+
+            @InjectService("ClasspathAssetFactory")
+            AssetFactory classpathAssetFactory)
+    {
+        configuration.add("context", contextAssetFactory);
+        configuration.add("classpath", classpathAssetFactory);
     }
 
-    public void contributeMetaDataLocator(MappedConfiguration<String, String> configuration)
+    /**
+     * Contributes handlers for the following types:
+     * <dl>
+     * <dt>Object</dt>
+     * <dd>Failure case, added to provide a more useful exception message</dd>
+     * <dt>ActionResponseGenerator</dt>
+     * <dd>Returns the ActionResponseGenerator; this sometimes occurs when a component generates
+     * events whose return values are converted to ActionResponseGenerators (this handles that
+     * bubble up case).</dd>
+     * <dt>Link</dt>
+     * <dd>Wraps the Link to send a redirect</dd>
+     * <dt>String</dt>
+     * <dd>The name of the page to render the response (after a redirect)</dd>
+     * </dl>
+     */
+    public void contributeComponentEventResultProcessor(
+            @InjectService("ComponentInstanceResultProcessor")
+            ComponentEventResultProcessor componentInstanceProcessor,
+
+            MappedConfiguration<Class, ComponentEventResultProcessor> configuration)
     {
         configuration.add(
-                PersistentFieldManagerImpl.META_KEY,
-                PersistentFieldManagerImpl.DEFAULT_STRATEGY);
+                ActionResponseGenerator.class,
+                new ComponentEventResultProcessor<ActionResponseGenerator>()
+                {
+                    public ActionResponseGenerator processComponentEvent(
+                            ActionResponseGenerator value, Component component,
+                            String methodDescripion)
+                    {
+                        return value;
+                    }
+                });
+
+        configuration.add(Link.class, new ComponentEventResultProcessor<Link>()
+        {
+
+            public ActionResponseGenerator processComponentEvent(Link value, Component component,
+                    String methodDescripion)
+            {
+                return new LinkActionResponseGenerator(value);
+            }
+        });
+
+        configuration.add(String.class, new StringResultProcessor(_requestPageCache, _linkFactory));
+
+        configuration.add(Component.class, componentInstanceProcessor);
+
+        configuration.add(StreamResponse.class, new StreamResponseResultProcessor());
     }
 
-    public DefaultComponentParameterBindingSource buildDefaultComponentParameterBindingSource(
-            @Inject("infrastructure:BindingSource")
-            BindingSource bindingSource)
+    public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
+            @Inject("infrastructure:ClasspathAssetAliasManager")
+            ClasspathAssetAliasManager aliasManager,
+
+            @InjectService("ResourceCache")
+            ResourceCache resourceCache,
+
+            @InjectService("ResourceStreamer")
+            ResourceStreamer streamer,
+
+            @InjectService("PageLinkHandler")
+            PageLinkHandler pageLinkHandler,
+
+            @InjectService("ActionLinkHandler")
+            ActionLinkHandler actionLinkHandler,
+
+            @InjectService("ComponentClassResolver")
+            ComponentClassResolver componentClassResolver,
+
+            @Inject("${tapestry.start-page-name}")
+            String startPageName)
     {
-        return new DefaultComponentParameterBindingSourceImpl(_propertyAccess, bindingSource);
+        // Looks for the root path and renders the start page
+
+        configuration.add("RootPath", new RootPathDispatcher(componentClassResolver,
+                pageLinkHandler, _pageResponseRenderer, startPageName), "before:Asset");
+
+        // This goes first because an asset to be streamed may have an file extension, such as
+        // ".html", that will confuse the later dispatchers.
+
+        configuration.add(
+                "Asset",
+                new AssetDispatcher(streamer, aliasManager, resourceCache),
+                "before:PageRender");
+
+        configuration.add("PageRender", new PageRenderDispatcher(componentClassResolver,
+                pageLinkHandler, _pageResponseRenderer));
+
+        configuration.add(
+                "ComponentAction",
+                new ComponentActionDispatcher(actionLinkHandler),
+                "after:PageRender");
     }
 
-    public ObjectRenderer buildObjectRenderer(@InjectService("StrategyBuilder")
-    StrategyBuilder strategyBuilder, Map<Class, ObjectRenderer> configuration)
+    public void contributeMetaDataLocator(MappedConfiguration<String, String> configuration)
     {
-        StrategyRegistry<ObjectRenderer> registry = StrategyRegistry.newInstance(
-                ObjectRenderer.class,
-                configuration);
-
-        return _strategyBuilder.build(registry);
+        configuration.add(
+                PersistentFieldManagerImpl.META_KEY,
+                PersistentFieldManagerImpl.DEFAULT_STRATEGY);
     }
 
     /**

[... 103 lines stripped ...]