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 2010/01/05 19:39:33 UTC

svn commit: r896168 - in /tapestry/tapestry5/trunk: src/site/apt/guide/ tapestry-core/src/main/java/org/apache/tapestry5/ tapestry-core/src/main/java/org/apache/tapestry5/internal/ tapestry-core/src/test/app1/ tapestry-core/src/test/app1/WEB-INF/ tapes...

Author: hlship
Date: Tue Jan  5 18:39:32 2010
New Revision: 896168

URL: http://svn.apache.org/viewvc?rev=896168&view=rev
Log:
TAP5-966: TapestryFilter should be able add additional modules to the Registry to accomidate different testing (or other) execution configurations

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/TestOnlyServiceDemo.tml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TestOnlyServiceDemo.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnly.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnlyModule.java   (with props)
Modified:
    tapestry/tapestry5/trunk/src/site/apt/guide/conf.apt
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/web.xml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/RegistryBuilder.java

Modified: tapestry/tapestry5/trunk/src/site/apt/guide/conf.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/guide/conf.apt?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/guide/conf.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/guide/conf.apt Tue Jan  5 18:39:32 2010
@@ -13,9 +13,11 @@
   The majority of configuration occurs inside the servlet deployment descriptor,
   WEB-INF/web.xml.
   
-  Most of the configuration is boilerplate; the same for all applications.
+  Most of the configuration is boilerplate; the same for all applications. Your application
+  will configure a 
+  {{{../apidocs/org/apache/tapestry5/TapestryFilter}TapestryFilter}} (or a subclass in some cases). This filter intercepts all incoming requests and determines which ones will be handled by Tapestry, and how.
   
-  The application specific configuration is to identify the root application package.
+  The main application-specific configuration is to identify the root application package.
   Tapestry uses this package name to locate your page and component classes.
   
   Page classes must go in the pages sub-package, and components must go in the
@@ -49,6 +51,9 @@
   In this example, page classes will be stored in the <<<org.example.myapp.pages>>> package (or in sub-packages below).
   Likewise, component classes will be stored in the <<<org.example.myapp.components>>> package.
   
+
+  
+  
 * Tapestry Requests vs. Container Requests
 
   The Tapestry filter matches all the requests that apply to Tapestry, and passes the rest off to the
@@ -254,6 +259,24 @@
     is sent directly for the action request, no redirect in the middle. This option should be used with care,
     and only in cases where you are certain that the benefits outweigh the disadvantages.
 
+* Additional modules
+
+  In some cases, especially related to testing, you may want to fine tune which modules are
+  available at runtime.  For example,
+  you might use a symbol (defined in your AppModule) to identify the database URL to connect to,
+  and have a test-only module that overrides the symbol's value to point to a test database.
+  
+  Specifying additional modules is accomplished in two steps:
+  
+  First, change your launch configuration or startup script to specify the JVM system property
+  <<<tapestry.execution-mode>>>.  The value for this
+  property is a comma-separated list of modes; if not specified at
+  all, it defaults to the string "production".
+  
+  For each execution mode in the list, Tapestry will check for a \<context-param\> named 
+  <<<tapestry.>>><mode><<<-modules>>>.  The value is a comma-separated list
+  of fully qualified module class names.
+  
 
 Ignored Paths
 
@@ -283,4 +306,4 @@
 
   The regular expressions provided in the configuration are always compiled with case insensitivity enabled.
 
-  Also note that actual files in your web application (images, stylesheets, etc.) are always ignored by Tapestry.
+  Also note that actual files in your web application (images, stylesheets, etc.) are always ignored by Tapestry.  
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java Tue Jan  5 18:39:32 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 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.
@@ -30,15 +30,25 @@
 import java.io.IOException;
 
 /**
- * The TapestryFilter is responsible for intercepting all requests into the web application. It identifies the requests
- * that are relevant to Tapestry, and lets the servlet container handle the rest. It is also responsible for
+ * The TapestryFilter is responsible for intercepting all requests into the web application. It
+ * identifies the requests
+ * that are relevant to Tapestry, and lets the servlet container handle the rest. It is also
+ * responsible for
  * initializing Tapestry.
  * <p/>
+ * The application is primarily configured via context-level init parameters.
  * <p/>
- * The application is configured via context-level init parameters.
- * <p/>
- * <dl> <dt>  tapestry.app-package</dt> <dd> The application package (used to search for pages, components, etc.)</dd>
+ * <dl>
+ * <dt>tapestry.app-package</dt>
+ * <dd>The application package (used to search for pages, components, etc.)</dd>
  * </dl>
+ * <p>
+ * In addition, a JVM system property affects configuration: <code>tapestry.execution-mode</code>
+ * (with default value "production"). This property is a comma-separated list of execution modes.
+ * For each mode, an additional init parameter is checked for:
+ * <code>tapestry.<em>mode</em>-modules</code>; this is a comma-separated list of module class names
+ * to load. In this way, more precise control over the available modules can be obtained which is
+ * often needed during testing.
  */
 public class TapestryFilter implements Filter
 {
@@ -51,14 +61,18 @@
     private HttpServletRequestHandler handler;
 
     /**
-     * Key under which that Tapestry IoC {@link org.apache.tapestry5.ioc.Registry} is stored in the ServletContext. This
-     * allows other code, beyond Tapestry, to obtain the Registry and, from it, any Tapestry services. Such code should
-     * be careful about invoking {@link org.apache.tapestry5.ioc.Registry#cleanupThread()} appopriately.
+     * Key under which that Tapestry IoC {@link org.apache.tapestry5.ioc.Registry} is stored in the
+     * ServletContext. This
+     * allows other code, beyond Tapestry, to obtain the Registry and, from it, any Tapestry
+     * services. Such code should
+     * be careful about invoking {@link org.apache.tapestry5.ioc.Registry#cleanupThread()}
+     * appropriately.
      */
     public static final String REGISTRY_CONTEXT_NAME = "org.apache.tapestry5.application-registry";
 
     /**
-     * Initializes the filter using the {@link TapestryAppInitializer}. The application name is the capitalization of
+     * Initializes the filter using the {@link TapestryAppInitializer}. The application name is the
+     * capitalization of
      * the filter name (as specified in web.xml).
      */
     public final void init(FilterConfig filterConfig) throws ServletException
@@ -71,7 +85,10 @@
 
         SymbolProvider provider = new ServletContextSymbolProvider(context);
 
-        TapestryAppInitializer appInitializer = new TapestryAppInitializer(logger, provider, filterName, "servlet");
+        String executionMode = System.getProperty("tapestry.execution-mode", "production");
+
+        TapestryAppInitializer appInitializer = new TapestryAppInitializer(logger, provider,
+                filterName, "servlet", executionMode);
 
         appInitializer.addModules(provideExtraModuleDefs(context));
 
@@ -80,7 +97,7 @@
         context.setAttribute(REGISTRY_CONTEXT_NAME, registry);
 
         ServletApplicationInitializer ai = registry.getService("ServletApplicationInitializer",
-                                                               ServletApplicationInitializer.class);
+                ServletApplicationInitializer.class);
 
         ai.initializeApplication(filterConfig.getServletContext());
 
@@ -99,10 +116,12 @@
     }
 
     /**
-     * Invoked from {@link #init(FilterConfig)} after the Registry has been created, to allow any additional
+     * Invoked from {@link #init(FilterConfig)} after the Registry has been created, to allow any
+     * additional
      * initialization to occur. This implementation does nothing, and my be overriden in subclasses.
-     *
-     * @param registry from which services may be extracted
+     * 
+     * @param registry
+     *            from which services may be extracted
      * @throws ServletException
      */
     protected void init(Registry registry) throws ServletException
@@ -111,7 +130,8 @@
     }
 
     /**
-     * Overridden in subclasses to provide additional module definitions beyond those normally located. This
+     * Overridden in subclasses to provide additional module definitions beyond those normally
+     * located. This
      * implementation returns an empty array.
      */
     protected ModuleDef[] provideExtraModuleDefs(ServletContext context)
@@ -124,9 +144,11 @@
     {
         try
         {
-            boolean handled = handler.service((HttpServletRequest) request, (HttpServletResponse) response);
+            boolean handled = handler.service((HttpServletRequest) request,
+                    (HttpServletResponse) response);
 
-            if (!handled) chain.doFilter(request, response);
+            if (!handled)
+                chain.doFilter(request, response);
         }
         finally
         {
@@ -135,8 +157,10 @@
     }
 
     /**
-     * Shuts down and discards the registry.  Invokes {@link #destroy(org.apache.tapestry5.ioc.Registry)} to allow
-     * subclasses to peform any shutdown logic, then shuts down the registry, and removes it from the ServletContext.
+     * Shuts down and discards the registry. Invokes
+     * {@link #destroy(org.apache.tapestry5.ioc.Registry)} to allow
+     * subclasses to peform any shutdown logic, then shuts down the registry, and removes it from
+     * the ServletContext.
      */
     public final void destroy()
     {
@@ -152,9 +176,11 @@
     }
 
     /**
-     * Invoked from {@link #destroy()} to allow subclasses to add additional shutdown logic to the filter. The Registry
-     * will be shutdown after this call. This implementation does nothing, and may be overridden in subclasses.
-     *
+     * Invoked from {@link #destroy()} to allow subclasses to add additional shutdown logic to the
+     * filter. The Registry
+     * will be shutdown after this call. This implementation does nothing, and may be overridden in
+     * subclasses.
+     * 
      * @param registry
      */
     protected void destroy(Registry registry)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java Tue Jan  5 18:39:32 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 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.
@@ -29,13 +29,14 @@
 import java.util.List;
 
 /**
- * This class is used to build the {@link Registry}. The Registry contains {@link org.apache.tapestry5.ioc.services.TapestryIOCModule}
- * and {@link TapestryModule}, any modules identified by {@link #addModules(Class[])} )}, plus the application module.
+ * This class is used to build the {@link Registry}. The Registry contains
+ * {@link org.apache.tapestry5.ioc.services.TapestryIOCModule} and {@link TapestryModule}, any
+ * modules identified by {@link #addModules(Class[])} )}, plus the application module.
  * <p/>
  * The application module is optional.
  * <p/>
- * The application module is identified as <em>package</em>.services.<em>appName</em>Module, where <em>package</em> and
- * the <em>appName</em> are specified by the caller.
+ * The application module is identified as <em>package</em>.services.<em>appName</em>Module, where
+ * <em>package</em> and the <em>appName</em> are specified by the caller.
  */
 public class TapestryAppInitializer
 {
@@ -54,33 +55,78 @@
     private long registryCreatedTime;
     private Registry registry;
 
+    /**
+     * @param logger
+     *            logger for output confirmation
+     * @param appProvider
+     *            provides symbols for the application (normally, from the ServletContext init
+     *            parameters)
+     * @param appName
+     *            the name of the application (i.e., the name of the application servlet)
+     * @param aliasMode
+     *            the mode, used by the {@link org.apache.tapestry5.services.Alias} service,
+     *            normally "servlet"
+     */
     public TapestryAppInitializer(Logger logger, String appPackage, String appName, String aliasMode)
     {
-        this(logger, new SingleKeySymbolProvider(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM, appPackage), appName,
-             aliasMode);
+        this(logger, new SingleKeySymbolProvider(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM,
+                appPackage), appName, aliasMode, null);
+    }
+
+    /**
+     * @param logger
+     *            logger for output confirmation
+     * @param appProvider
+     *            provides symbols for the application (normally, from the ServletContext init
+     *            parameters)
+     * @param appName
+     *            the name of the application (i.e., the name of the application servlet)
+     * @param aliasMode
+     *            the mode, used by the {@link org.apache.tapestry5.services.Alias} service,
+     *            normally "servlet"
+     * @deprecated Use
+     *             {@link #TapestryAppInitializer(Logger, SymbolProvider, String, String, String)}
+     *             instead
+     */
+    public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName,
+            String aliasMode)
+    {
+        this(logger, appProvider, appName, aliasMode, null);
     }
 
     /**
-     * @param logger      logger for output confirmation
-     * @param appProvider provides symbols for the application (normally, from the ServletContext init parameters)
-     * @param appName     the name of the application (i.e., the name of the application servlet)
-     * @param aliasMode   the mode, used by the {@link org.apache.tapestry5.services.Alias} service, normally "servlet"
+     * @param logger
+     *            logger for output confirmation
+     * @param appProvider
+     *            provides symbols for the application (normally, from the ServletContext init
+     *            parameters)
+     * @param appName
+     *            the name of the application (i.e., the name of the application servlet)
+     * @param aliasMode
+     *            the mode, used by the {@link org.apache.tapestry5.services.Alias} service,
+     *            normally "servlet"
+     * @param executionModes
+     *            an optional, comma-seperated list of execution modes, each of which is used
+     *            to find a list of additional module classes to load (key
+     *            <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
+     *            context)
      */
-    public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName, String aliasMode)
+    public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName,
+            String aliasMode, String executionModes)
     {
         this.logger = logger;
         this.appProvider = appProvider;
 
-        String appPackage = appProvider.valueForSymbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
-
+        String appPackage = appProvider
+                .valueForSymbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
 
         this.appName = appName;
         this.aliasMode = aliasMode;
 
         startTime = System.currentTimeMillis();
 
-
-        if (!Boolean.parseBoolean(appProvider.valueForSymbol(InternalConstants.DISABLE_DEFAULT_MODULES_PARAM)))
+        if (!Boolean.parseBoolean(appProvider
+                .valueForSymbol(InternalConstants.DISABLE_DEFAULT_MODULES_PARAM)))
         {
             IOCUtilities.addDefaultModules(builder);
         }
@@ -89,12 +135,13 @@
 
         addModules(TapestryModule.class);
 
-        String className = appPackage + ".services." + InternalUtils.capitalize(this.appName) + "Module";
+        String className = appPackage + ".services." + InternalUtils.capitalize(this.appName)
+                + "Module";
 
         try
         {
             // This class is possibly loaded by a parent class loader of the application class
-            // loader. The context class loader should have the approprite view to the module class,
+            // loader. The context class loader should have the appropriate view to the module class,
             // if any.
 
             Class moduleClass = Thread.currentThread().getContextClassLoader().loadClass(className);
@@ -110,11 +157,22 @@
         // Add a synthetic module that contributes symbol sources.
 
         addSyntheticSymbolSourceModule(appPackage);
+
+        for (String mode : TapestryInternalUtils.splitAtCommas(executionModes))
+        {
+            String key = String.format("tapestry.%s-modules", mode);
+            String moduleList = appProvider.valueForSymbol(key);
+
+            for (String moduleClassName : TapestryInternalUtils.splitAtCommas(moduleList))
+            {
+                builder.add(moduleClassName);
+            }
+        }
     }
 
     /**
      * Adds additional modules.
-     *
+     * 
      * @param moduleDefs
      */
     public void addModules(ModuleDef... moduleDefs)
@@ -130,30 +188,23 @@
 
     private void addSyntheticSymbolSourceModule(String appPackage)
     {
-        ContributionDef appPathContribution =
-                new SyntheticSymbolSourceContributionDef("AppPath",
-                                                         new SingleKeySymbolProvider(
-                                                                 InternalSymbols.APP_PACKAGE_PATH,
-                                                                 appPackage.replace('.', '/')));
-
-        ContributionDef symbolSourceContribution =
-                new SyntheticSymbolSourceContributionDef("ServletContext",
-                                                         appProvider,
-                                                         "before:ApplicationDefaults");
-
-        ContributionDef aliasModeContribution =
-                new SyntheticSymbolSourceContributionDef("AliasMode",
-                                                         new SingleKeySymbolProvider(InternalSymbols.ALIAS_MODE,
-                                                                                     aliasMode),
-                                                         "before:ServletContext");
-
-        ContributionDef appNameContribution =
-                new SyntheticSymbolSourceContributionDef("AppName",
-                                                         new SingleKeySymbolProvider(InternalSymbols.APP_NAME, appName),
-                                                         "before:ServletContext");
+        ContributionDef appPathContribution = new SyntheticSymbolSourceContributionDef("AppPath",
+                new SingleKeySymbolProvider(InternalSymbols.APP_PACKAGE_PATH, appPackage.replace(
+                        '.', '/')));
+
+        ContributionDef symbolSourceContribution = new SyntheticSymbolSourceContributionDef(
+                "ServletContext", appProvider, "before:ApplicationDefaults");
+
+        ContributionDef aliasModeContribution = new SyntheticSymbolSourceContributionDef(
+                "AliasMode", new SingleKeySymbolProvider(InternalSymbols.ALIAS_MODE, aliasMode),
+                "before:ServletContext");
+
+        ContributionDef appNameContribution = new SyntheticSymbolSourceContributionDef("AppName",
+                new SingleKeySymbolProvider(InternalSymbols.APP_NAME, appName),
+                "before:ServletContext");
 
-        builder.add(new SyntheticModuleDef(symbolSourceContribution, aliasModeContribution, appNameContribution,
-                                           appPathContribution));
+        builder.add(new SyntheticModuleDef(symbolSourceContribution, aliasModeContribution,
+                appNameContribution, appPathContribution));
     }
 
     public Registry createRegistry()
@@ -174,17 +225,15 @@
         StringBuilder buffer = new StringBuilder("Startup status:\n\n");
         Formatter f = new Formatter(buffer);
 
-        f.format("Application '%s' (Tapestry version %s).\n\n" +
-                "Startup time: %,d ms to build IoC Registry, %,d ms overall.\n\n" +
-                "Startup services status:\n",
-                 appName,
-                 source.valueForSymbol(SymbolConstants.TAPESTRY_VERSION),
-                 registryCreatedTime - startTime, toFinish - startTime);
+        f.format("Application '%s' (Tapestry version %s).\n\n"
+                + "Startup time: %,d ms to build IoC Registry, %,d ms overall.\n\n"
+                + "Startup services status:\n", appName, source
+                .valueForSymbol(SymbolConstants.TAPESTRY_VERSION), registryCreatedTime - startTime,
+                toFinish - startTime);
 
         int unrealized = 0;
 
-        ServiceActivityScoreboard scoreboard = registry
-                .getService(ServiceActivityScoreboard.class);
+        ServiceActivityScoreboard scoreboard = registry.getService(ServiceActivityScoreboard.class);
 
         List<ServiceActivity> serviceActivity = scoreboard.getServiceActivity();
 
@@ -198,7 +247,8 @@
 
             longest = Math.max(longest, activity.getServiceId().length());
 
-            if (status == Status.DEFINED || status == Status.VIRTUAL) unrealized++;
+            if (status == Status.DEFINED || status == Status.VIRTUAL)
+                unrealized++;
         }
 
         String formatString = "%" + longest + "s: %s\n";
@@ -210,8 +260,8 @@
             f.format(formatString, activity.getServiceId(), activity.getStatus().name());
         }
 
-        f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized / serviceActivity.size(), unrealized,
-                 serviceActivity.size());
+        f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized
+                / serviceActivity.size(), unrealized, serviceActivity.size());
 
         logger.info(buffer.toString());
     }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/TestOnlyServiceDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/TestOnlyServiceDemo.tml?rev=896168&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/TestOnlyServiceDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/TestOnlyServiceDemo.tml Tue Jan  5 18:39:32 2010
@@ -0,0 +1,7 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+  <h1>Test only message</h1>
+
+  <span id="message">${service.message}</span>
+
+</html>  
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/web.xml?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/web.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/web.xml Tue Jan  5 18:39:32 2010
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- 
-   Copyright 2006 The Apache Software Foundation
+   Copyright 2006, 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.
@@ -24,6 +24,10 @@
         <param-name>tapestry.app-package</param-name>
         <param-value>org.apache.tapestry5.integration.app1</param-value>
     </context-param>
+    <context-param>
+      <param-name>tapestry.production-modules</param-name>
+      <param-value>org.apache.tapestry5.integration.app1.services.TestOnlyModule</param-value>
+    </context-param>
     <filter>
         <filter-name>app</filter-name>
         <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java Tue Jan  5 18:39:32 2010
@@ -1,4 +1,4 @@
-// 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.
@@ -1437,4 +1437,14 @@
                 "container",
                 "Exception rendering description for object of type org.apache.tapestry5.integration.app1.data.NullToString: (java.lang.NullPointerException) NPE from NullToString");
     }
+
+    /** TAP5-966 */
+
+    @Test
+    public void module_loading()
+    {
+        clickThru("Test Only Service Demo");
+
+        assertText("message", "TestOnly service message");
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Tue Jan  5 18:39:32 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 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.
@@ -65,6 +65,8 @@
 
     private static final List<Item> ITEMS = CollectionFactory
             .newList(
+                    new Item("TestOnlyServiceDemo", "Test Only Service Demo",
+                            "IoC module available via web.xml configuration"),
 
                     new Item("RenderObjectExceptionDemo", "RenderObject Exception Demo",
                             "Demonstrate how exceptions when rendering default objects are displayed."),

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TestOnlyServiceDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TestOnlyServiceDemo.java?rev=896168&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TestOnlyServiceDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TestOnlyServiceDemo.java Tue Jan  5 18:39:32 2010
@@ -0,0 +1,26 @@
+// 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.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.integration.app1.services.TestOnly;
+import org.apache.tapestry5.ioc.annotations.Inject;
+
+public class TestOnlyServiceDemo
+{
+    @Property
+    @Inject
+    private TestOnly service;
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TestOnlyServiceDemo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnly.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnly.java?rev=896168&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnly.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnly.java Tue Jan  5 18:39:32 2010
@@ -0,0 +1,20 @@
+// 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.integration.app1.services;
+
+public interface TestOnly
+{
+    String getMessage();
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnly.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnlyModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnlyModule.java?rev=896168&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnlyModule.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnlyModule.java Tue Jan  5 18:39:32 2010
@@ -0,0 +1,34 @@
+// 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.integration.app1.services;
+
+/**
+ * This module is available only due to configuration inside web.xml, as part of the default
+ * ("production") execution mode.
+ */
+public class TestOnlyModule
+{
+    public TestOnly build()
+    {
+        return new TestOnly()
+        {
+            public String getMessage()
+            {
+                return "TestOnly service message";
+            }
+        };
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/TestOnlyModule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/RegistryBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/RegistryBuilder.java?rev=896168&r1=896167&r2=896168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/RegistryBuilder.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/RegistryBuilder.java Tue Jan  5 18:39:32 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 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.
@@ -135,7 +135,7 @@
     }
 
     /**
-     * Adds a number of module classes (specified by fully qualified class name) to the registry, returning the builder
+     * Adds a  modle class (specified by fully qualified class name) to the registry, returning the builder
      * for further configuration.
      *
      * @see org.apache.tapestry5.ioc.annotations.SubModule