You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2008/12/29 23:59:12 UTC

svn commit: r730009 [1/2] - in /tapestry/tapestry5/trunk: ./ quickstart/src/main/resources/archetype-resources/src/main/resources/ src/site/apt/guide/ tapestry-core/ tapestry-core/src/main/java/org/apache/tapestry5/internal/ tapestry-core/src/main/java...

Author: hlship
Date: Mon Dec 29 14:59:10 2008
New Revision: 730009

URL: http://svn.apache.org/viewvc?rev=730009&view=rev
Log:
TAP5-427: Allow injection of Tapestry services into Spring beans

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/AbstractContributionDef.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/ApplicationContextCustomizer.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/CustomizingContextLoader.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModule.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/TapestyBeanFactory.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestryApplicationContext.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/CustomizingContextLoaderTest.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryApplicationContextTest.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Bedrock.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/AppModule.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/CustomizedFilter.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/Flintstone.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/FlintstoneImpl.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/SpringStatusProvider.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/StringTransformer.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/UpcaseStringTransformerImpl.java
Removed:
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/SpringMessages.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/resources/org/apache/tapestry5/spring/SpringStrings.properties
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestrySpringFilterTest.java
Modified:
    tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j.properties
    tapestry/tapestry5/trunk/src/site/apt/guide/coercion.apt
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/SyntheticSymbolSourceContributionDef.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderQueueImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentMethodInvocation.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PageDocumentGenerator.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml
    tapestry/tapestry5/trunk/tapestry-hibernate-core/src/site/apt/index.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractServiceCreator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDecoratorImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImplTest.java
    tapestry/tapestry5/trunk/tapestry-project.ipr
    tapestry/tapestry5/trunk/tapestry-spring/pom.xml
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java
    tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestrySpringFilter.java
    tapestry/tapestry5/trunk/tapestry-spring/src/site/apt/index.apt
    tapestry/tapestry5/trunk/tapestry-spring/src/test/conf/testng.xml
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestrySpringIntegrationTest.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Start.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/services/UpcaseImpl.java
    tapestry/tapestry5/trunk/tapestry-spring/src/test/resources/log4j.properties
    tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp/Start.tml
    tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp/WEB-INF/applicationContext.xml
    tapestry/tapestry5/trunk/tapestry-spring/src/test/webapp/WEB-INF/web.xml
    tapestry/tapestry5/trunk/tapestry-spring/tapestry-spring.iml

Modified: tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j.properties?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j.properties (original)
+++ tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j.properties Mon Dec 29 14:59:10 2008
@@ -31,13 +31,14 @@
 
 # log4j.category.tapestry.events.${packageName}.pages.Index=debug
 
-# Turning on trace mode for a page's render provides extended information about every step
+# Turning on trace mode for a page's render logger provides extended information about every step
 # in rendering (this is not generally helpful).  Turning on debug mode will add a one-line
-# summary that includes the elapsed render time.
+# summary that includes the elapsed render time, which can be useful in tracking down
+# performance issues.
 
 # log4j.category.tapestry.render.${packageName}.pages.Index=debug
 
 # Turn on some verbose debugging about everything in the application. This is nice initially,
 # while getting everything set up.  You'll probably want to remove this once you are 
-# up and running, replacing it with more selecting debugging output.
+# up and running, replacing it with more selective debugging output.
 log4j.category.${packageName}=debug
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/src/site/apt/guide/coercion.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/guide/coercion.apt?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/guide/coercion.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/guide/coercion.apt Mon Dec 29 14:59:10 2008
@@ -42,7 +42,7 @@
 TypeCoercer Service
 
   The TypeCoercer service is responsible for this type coercion. This service is part of the tapestry-ioc module, and 
-  is {{{../../tapestry-ioc/coerce.html}documented there}}.  The service
+  is {{{../tapestry-ioc/coerce.html}documented there}}.  The service
   is quite extensible, allowing for new types and coercions to be added easily.  The TapestryModule contributes a few additional
   coercions into the TypeCoercer service.
   

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/AbstractContributionDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/AbstractContributionDef.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/AbstractContributionDef.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/AbstractContributionDef.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,40 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal;
+
+import org.apache.tapestry5.ioc.*;
+import org.apache.tapestry5.ioc.def.ContributionDef;
+
+/**
+ * Partially implements {@link org.apache.tapestry5.ioc.def.ContributionDef}, providing empty implementations of the
+ * three contribute() methods.
+ */
+public abstract class AbstractContributionDef implements ContributionDef
+{
+    public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
+                           Configuration configuration)
+    {
+    }
+
+    public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
+                           OrderedConfiguration configuration)
+    {
+    }
+
+    public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
+                           MappedConfiguration configuration)
+    {
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/SyntheticSymbolSourceContributionDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/SyntheticSymbolSourceContributionDef.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/SyntheticSymbolSourceContributionDef.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/SyntheticSymbolSourceContributionDef.java Mon Dec 29 14:59:10 2008
@@ -14,14 +14,15 @@
 
 package org.apache.tapestry5.internal;
 
-import org.apache.tapestry5.ioc.*;
-import org.apache.tapestry5.ioc.def.ContributionDef;
+import org.apache.tapestry5.ioc.ModuleBuilderSource;
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.ServiceResources;
 import org.apache.tapestry5.ioc.services.SymbolProvider;
 
 /**
  * Makes a contribution to the SymbolSource service configuration.
  */
-public class SyntheticSymbolSourceContributionDef implements ContributionDef
+public class SyntheticSymbolSourceContributionDef extends AbstractContributionDef
 {
     private final String contributionName;
 
@@ -37,10 +38,6 @@
         this.constraints = constraints;
     }
 
-    public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
-                           Configuration configuration)
-    {
-    }
 
     @SuppressWarnings("unchecked")
     public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
@@ -49,10 +46,6 @@
         configuration.add(contributionName, provider, constraints);
     }
 
-    public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
-                           MappedConfiguration configuration)
-    {
-    }
 
     /**
      * Returns "SymbolSource".

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderQueueImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderQueueImpl.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderQueueImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderQueueImpl.java Mon Dec 29 14:59:10 2008
@@ -89,7 +89,7 @@
         long endNanos = System.nanoTime();
 
         long elapsedNanos = endNanos - startNanos;
-        double elapsedSeconds = ((float) elapsedNanos) / 1000000000F;
+        double elapsedSeconds = ((double) elapsedNanos) / 1000000000d;
 
         logger.debug(TapestryMarkers.RENDER_COMMANDS,
                      String.format("Executed %,d rendering commands (max queue depth: %,d) in %.3f seconds",

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentMethodInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentMethodInvocation.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentMethodInvocation.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentMethodInvocation.java Mon Dec 29 14:59:10 2008
@@ -14,17 +14,14 @@
 
 package org.apache.tapestry5.services;
 
-import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.ioc.Invocation;
+import org.apache.tapestry5.runtime.ComponentResourcesAware;
 
 /**
  * Encapsulates the parameters, thrown exceptions, and result of a method invocation, allowing a {@link
- * org.apache.tapestry5.services.ComponentMethodAdvice} to encapsulate the invocation.
+ * org.apache.tapestry5.services.ComponentMethodAdvice} to encapsulate the invocation. Extends Invocation with the
+ * {@link org.apache.tapestry5.ComponentResources} of the component for which a method is being advised.
  */
-public interface ComponentMethodInvocation extends Invocation
+public interface ComponentMethodInvocation extends Invocation, ComponentResourcesAware
 {
-    /**
-     * Returns the component resources for the component whose method is being intercepted.
-     */
-    ComponentResources getComponentResources();
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PageDocumentGenerator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PageDocumentGenerator.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PageDocumentGenerator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PageDocumentGenerator.java Mon Dec 29 14:59:10 2008
@@ -18,7 +18,8 @@
 
 /**
  * Interface used to programatically render a page, forming a {@link org.apache.tapestry5.dom.Document} which can then
- * be manipulated or {@link org.apache.tapestry5.dom.Document#toMarkup(java.io.PrintWriter) streamed to a PrintWriter}.
+ * be manipulated or {@linkplain org.apache.tapestry5.dom.Document#toMarkup(java.io.PrintWriter) streamed to a
+ * PrintWriter}.
  */
 public interface PageDocumentGenerator
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java Mon Dec 29 14:59:10 2008
@@ -20,14 +20,6 @@
  * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
  * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
  * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
- * <p/>
- * The expression consist of one or more terms, seperated by periods. Each term may be either the name of a JavaBean
- * property, or the name of a method (a method that takes no parameters). Method names are distinguished from property
- * names by appending empty parens. Using a method term as the final term will make the expression read-only.
- * <p/>
- * Alternately, the seperator between property names may be "?." (i.e., "user?.name").  This allows an "if not null"
- * connection: if the term is null, then the expression evaluates to null, otherwise, the expression evaluation
- * continues to the next property.  The helps avoid NullPointerExceptions.
  */
 public interface PropertyConduitSource
 {
@@ -35,6 +27,11 @@
      * Returns property conduit instance for the given expression. PropertyConduitSource caches the conduits it returns,
      * so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if a change
      * to component classes is observed.
+     * <p/>
+     * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
+     * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
+     * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
+     * and classloaders).
      *
      * @param rootType   the type of the root object to which the expression is applied
      * @param expression expression to be evaluated on instances of the root class

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Mon Dec 29 14:59:10 2008
@@ -1030,13 +1030,17 @@
     {
         ServletApplicationInitializer terminator = new ServletApplicationInitializer()
         {
-            public void initializeApplication(ServletContext context)
+            public void initializeApplication(ServletContext servletContext)
             {
-                applicationGlobals.storeServletContext(context);
+                applicationGlobals.storeServletContext(servletContext);
 
                 // And now, down the (Web) ApplicationInitializer pipeline ...
 
-                initializer.initializeApplication(new ContextImpl(context));
+                ContextImpl context = new ContextImpl(servletContext);
+
+                applicationGlobals.storeContext(context);
+
+                initializer.initializeApplication(context);
             }
         };
 

Modified: tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml Mon Dec 29 14:59:10 2008
@@ -9,9 +9,12 @@
       <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/target/generated-sources/antlr" isTestSource="false" />
-      <excludeFolder url="file://$MODULE_DIR$/target/Tapestry Core" />
       <excludeFolder url="file://$MODULE_DIR$/target/classes" />
+      <excludeFolder url="file://$MODULE_DIR$/target/cobertura" />
+      <excludeFolder url="file://$MODULE_DIR$/target/generated-classes" />
+      <excludeFolder url="file://$MODULE_DIR$/target/generated-site" />
       <excludeFolder url="file://$MODULE_DIR$/target/maven-archiver" />
+      <excludeFolder url="file://$MODULE_DIR$/target/site" />
       <excludeFolder url="file://$MODULE_DIR$/target/surefire-reports" />
       <excludeFolder url="file://$MODULE_DIR$/target/test-classes" />
       <excludeFolder url="file://$MODULE_DIR$/test-output" />

Modified: tapestry/tapestry5/trunk/tapestry-hibernate-core/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate-core/src/site/apt/index.apt?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate-core/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate-core/src/site/apt/index.apt Mon Dec 29 14:59:10 2008
@@ -16,7 +16,7 @@
 Licensing Issues
 
   Hibernate is licensed under the Lesser GNU Public License. This is more restrictive license than the Apache Software
-  License used by the rest of Tapestry. The restrictions mostly apply to redistricuting Hibernate, especially in
+  License used by the rest of Tapestry. The restrictions mostly apply to redistributing Hibernate, especially in
   any altered form, and will likely be irrelvant to the vast majority of users, but you should be aware.
 
   This library is compiled against version <<3.3.1.GA>> of Hibernate (and version 3.4.0.GA of hibernate-annotations),

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java Mon Dec 29 14:59:10 2008
@@ -54,8 +54,7 @@
     <T> T getService(Class<T> serviceInterface);
 
     /**
-     * Obtains an object indirectly, using an {@link org.apache.tapestry5.ioc.ObjectProvider} identified by the prefix
-     * of the reference.
+     * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
      *
      * @param objectType         the type of object to be returned
      * @param annotationProvider provides access to annotations on the field or parameter for which a value is to be

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractServiceCreator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractServiceCreator.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractServiceCreator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractServiceCreator.java Mon Dec 29 14:59:10 2008
@@ -14,10 +14,7 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.ServiceBuilderResources;
-import org.apache.tapestry5.ioc.ServiceResources;
+import org.apache.tapestry5.ioc.*;
 import static org.apache.tapestry5.ioc.internal.ConfigurationType.*;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.DelegatingInjectionResources;
@@ -68,6 +65,7 @@
         injectionResources.put(ServiceResources.class, resources);
         injectionResources.put(Logger.class, logger);
         injectionResources.put(Class.class, resources.getServiceInterface());
+        injectionResources.put(OperationTracker.class, resources.getTracker());
     }
 
     /**

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java Mon Dec 29 14:59:10 2008
@@ -368,6 +368,7 @@
 
         resourcesMap.put(Logger.class, logger);
         resourcesMap.put(ObjectLocator.class, locator);
+        resourcesMap.put(OperationTracker.class, registry);
 
         InjectionResources resources = new MapInjectionResources(resourcesMap);
 

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java Mon Dec 29 14:59:10 2008
@@ -16,6 +16,7 @@
 
 import org.apache.tapestry5.ioc.OperationTracker;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.Defense;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.Invokable;
 import org.apache.tapestry5.ioc.util.Stack;
@@ -41,6 +42,9 @@
 
     public void run(String description, final Runnable operation)
     {
+        Defense.notBlank(description, "description");
+        Defense.notNull(operation, "operation");
+
         operations.push(description);
 
         try
@@ -84,6 +88,9 @@
 
     public <T> T invoke(String description, Invokable<T> operation)
     {
+        Defense.notBlank(description, "description");
+        Defense.notNull(operation, "operation");
+
         InvokableToRunnable<T> i2r = new InvokableToRunnable<T>(operation);
 
         run(description, i2r);

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java Mon Dec 29 14:59:10 2008
@@ -767,8 +767,10 @@
         final ObjectLocator locator = this;
         final OperationTracker tracker = this;
 
-        Map<Class, Object> empty = Collections.emptyMap();
-        final InjectionResources resources = new MapInjectionResources(empty);
+        Map<Class, Object> resourcesMap = CollectionFactory.newMap();
+        resourcesMap.put(OperationTracker.class, tracker);
+
+        final InjectionResources resources = new MapInjectionResources(resourcesMap);
 
 
         final Invokable<T> operation = new Invokable<T>()

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDecoratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDecoratorImpl.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDecoratorImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDecoratorImpl.java Mon Dec 29 14:59:10 2008
@@ -14,10 +14,7 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import org.apache.tapestry5.ioc.ModuleBuilderSource;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.ServiceDecorator;
-import org.apache.tapestry5.ioc.ServiceResources;
+import org.apache.tapestry5.ioc.*;
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
 import org.apache.tapestry5.ioc.internal.util.InjectionResources;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -66,6 +63,7 @@
         parameterDefaults.put(ServiceResources.class, resources);
         parameterDefaults.put(Logger.class, logger);
         parameterDefaults.put(Class.class, serviceInterface);
+        parameterDefaults.put(OperationTracker.class, resources.getTracker());
     }
 
     @Override
@@ -94,7 +92,8 @@
         Object result = null;
         Throwable failure = null;
 
-        Object moduleBuilder = InternalUtils.isStatic(decoratorMethod) ? null
+        Object moduleBuilder = InternalUtils.isStatic(decoratorMethod)
+                               ? null
                                : moduleBuilderSource.getModuleBuilder();
 
         try

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImpl.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImpl.java Mon Dec 29 14:59:10 2008
@@ -17,6 +17,9 @@
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.ObjectProvider;
+import org.apache.tapestry5.ioc.OperationTracker;
+import org.apache.tapestry5.ioc.internal.util.Invokable;
+import org.apache.tapestry5.ioc.services.ClassFabUtils;
 import org.apache.tapestry5.ioc.services.MasterObjectProvider;
 
 import java.util.List;
@@ -25,27 +28,37 @@
 {
     private final List<ObjectProvider> configuration;
 
-    public MasterObjectProviderImpl(List<ObjectProvider> configuration)
+    private final OperationTracker tracker;
+
+    public MasterObjectProviderImpl(List<ObjectProvider> configuration, OperationTracker tracker)
     {
         this.configuration = configuration;
+        this.tracker = tracker;
     }
 
-    public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator,
-                         boolean required)
+    public <T> T provide(final Class<T> objectType, final AnnotationProvider annotationProvider,
+                         final ObjectLocator locator,
+                         final boolean required)
     {
-        for (ObjectProvider provider : configuration)
+        return tracker.invoke(String.format("Resolving object of type %s using MasterObjectProvider",
+                                            ClassFabUtils.toJavaClassName(objectType)), new Invokable<T>()
         {
-            T result = provider.provide(objectType, annotationProvider, locator);
-
-            if (result != null) return result;
-        }
-
-        // If required, then we must obtain it the hard way, by
-        // seeing if there's a single service that implements the interface.
-
-        if (required) return locator.getService(objectType);
-
-        return null;
+            public T invoke()
+            {
+                for (ObjectProvider provider : configuration)
+                {
+                    T result = provider.provide(objectType, annotationProvider, locator);
+
+                    if (result != null) return result;
+                }
+
+                // If required, then we must obtain it the hard way, by
+                // seeing if there's a single service that implements the interface.
+
+                if (required) return locator.getService(objectType);
+
+                return null;
+            }
+        });
     }
-
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt Mon Dec 29 14:59:10 2008
@@ -111,6 +111,9 @@
 
    []
 
+   In addition, {{{../apidocs/org/apache/tapestry5/ioc/OperationTracker.html}OperationTracker}} is available
+   for injection via constructor, method or field.
+
    If field type does not match any of the available resource types, or the Inject annotation is present,
    logic continues to the next step.
 
@@ -211,6 +214,13 @@
   if present, the annotation's value is the exact service id to inject.  This is necessary because
   injections into <component> fields are always triggered by the Inject annotation.
 
+** SpringBean ObjectProvider (tapestry-spring)
+
+   Attempts to resolve a Spring bean purely by object type (Spring qualifiers are not supported). If no beans
+   are assignable to the type, then processing continues. If exactly one is assignable, it is used as the injection value.
+   If more than one bean is assignable, it is an error (and a list of matching beans names will be part of the thrown
+   exception).
+
 * Service Lookup
 
   If none of the ObjectProviders can identify the value to inject, a last step occurs: lookup by service type.

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImplTest.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/MasterObjectProviderImplTest.java Mon Dec 29 14:59:10 2008
@@ -17,6 +17,7 @@
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.ObjectProvider;
+import org.apache.tapestry5.ioc.internal.QuietOperationTracker;
 import org.apache.tapestry5.ioc.services.MasterObjectProvider;
 import org.apache.tapestry5.ioc.test.IOCTestCase;
 import org.testng.annotations.Test;
@@ -43,7 +44,7 @@
 
         replay();
 
-        MasterObjectProvider master = new MasterObjectProviderImpl(configuration);
+        MasterObjectProvider master = new MasterObjectProviderImpl(configuration, new QuietOperationTracker());
 
         assertSame(master.provide(type, ap, locator, true), expected);
 
@@ -68,7 +69,7 @@
 
         replay();
 
-        MasterObjectProvider master = new MasterObjectProviderImpl(configuration);
+        MasterObjectProvider master = new MasterObjectProviderImpl(configuration, new QuietOperationTracker());
 
         assertSame(master.provide(type, ap, locator, true), expected);
 
@@ -92,7 +93,7 @@
 
         replay();
 
-        MasterObjectProvider master = new MasterObjectProviderImpl(configuration);
+        MasterObjectProvider master = new MasterObjectProviderImpl(configuration, new QuietOperationTracker());
 
         assertNull(master.provide(type, ap, locator, false));
 
@@ -119,7 +120,7 @@
 
         replay();
 
-        MasterObjectProvider master = new MasterObjectProviderImpl(configuration);
+        MasterObjectProvider master = new MasterObjectProviderImpl(configuration, new QuietOperationTracker());
 
         assertSame(master.provide(type, ap, locator, true), expected);
 

Modified: tapestry/tapestry5/trunk/tapestry-project.ipr
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-project.ipr?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-project.ipr (original)
+++ tapestry/tapestry5/trunk/tapestry-project.ipr Mon Dec 29 14:59:10 2008
@@ -1901,6 +1901,61 @@
         <root url="jar://$MAVEN_REPOSITORY$/org/antlr/stringtemplate/3.1-b1/stringtemplate-3.1-b1-sources.jar!/" />
       </SOURCES>
     </library>
+    <library name="Maven: org.springframework:spring-web:2.5.6">
+      <CLASSES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-web/2.5.6/spring-web-2.5.6.jar!/" />
+      </CLASSES>
+      <JAVADOC>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-web/2.5.6/spring-web-2.5.6-javadoc.jar!/" />
+      </JAVADOC>
+      <SOURCES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-web/2.5.6/spring-web-2.5.6-sources.jar!/" />
+      </SOURCES>
+    </library>
+    <library name="Maven: commons-logging:commons-logging:1.1.1">
+      <CLASSES>
+        <root url="jar://$MAVEN_REPOSITORY$/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar!/" />
+      </CLASSES>
+      <JAVADOC>
+        <root url="jar://$MAVEN_REPOSITORY$/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1-javadoc.jar!/" />
+      </JAVADOC>
+      <SOURCES>
+        <root url="jar://$MAVEN_REPOSITORY$/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1-sources.jar!/" />
+      </SOURCES>
+    </library>
+    <library name="Maven: org.springframework:spring-beans:2.5.6">
+      <CLASSES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/2.5.6/spring-beans-2.5.6.jar!/" />
+      </CLASSES>
+      <JAVADOC>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/2.5.6/spring-beans-2.5.6-javadoc.jar!/" />
+      </JAVADOC>
+      <SOURCES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/2.5.6/spring-beans-2.5.6-sources.jar!/" />
+      </SOURCES>
+    </library>
+    <library name="Maven: org.springframework:spring-core:2.5.6">
+      <CLASSES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/2.5.6/spring-core-2.5.6.jar!/" />
+      </CLASSES>
+      <JAVADOC>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/2.5.6/spring-core-2.5.6-javadoc.jar!/" />
+      </JAVADOC>
+      <SOURCES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/2.5.6/spring-core-2.5.6-sources.jar!/" />
+      </SOURCES>
+    </library>
+    <library name="Maven: org.springframework:spring-context:2.5.6">
+      <CLASSES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/2.5.6/spring-context-2.5.6.jar!/" />
+      </CLASSES>
+      <JAVADOC>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/2.5.6/spring-context-2.5.6-javadoc.jar!/" />
+      </JAVADOC>
+      <SOURCES>
+        <root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/2.5.6/spring-context-2.5.6-sources.jar!/" />
+      </SOURCES>
+    </library>
   </component>
   <UsedPathMacros>
     <macro name="MAVEN_REPOSITORY" />

Modified: tapestry/tapestry5/trunk/tapestry-spring/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/pom.xml?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/pom.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/pom.xml Mon Dec 29 14:59:10 2008
@@ -27,8 +27,7 @@
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-web</artifactId>
-            <version>2.0</version>
-            <scope>provided</scope>
+            <version>2.5.6</version>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
@@ -70,6 +69,19 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestEntries>
+                            <Tapestry-Module-Classes>
+                                org.apache.tapestry5.internal.spring.SpringModule
+                            </Tapestry-Module-Classes>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
     <reporting>

Added: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/ApplicationContextCustomizer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/ApplicationContextCustomizer.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/ApplicationContextCustomizer.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/ApplicationContextCustomizer.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,37 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.spring;
+
+import org.springframework.web.context.ConfigurableWebApplicationContext;
+
+import javax.servlet.ServletContext;
+
+/**
+ * A bridge from Spring's approach to customizing the application context, over to Tapestry's.  This is how it is
+ * possible to subclass and override {@link  org.apache.tapestry5.spring.TapestrySpringFilter#customizeApplicationContext(javax.servlet.ServletContext,
+ * org.springframework.web.context.ConfigurableWebApplicationContext)}.
+ */
+public interface ApplicationContextCustomizer
+{
+    /**
+     * Allows the instantiated application context to be customized before it is initially {@linkplain
+     * org.springframework.context.ConfigurableApplicationContext#refresh() refreshed}.
+     *
+     * @param servletContext
+     * @param applicationContext
+     */
+    void customizeApplicationContext(ServletContext servletContext,
+                                     ConfigurableWebApplicationContext applicationContext);
+}

Added: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/CustomizingContextLoader.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/CustomizingContextLoader.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/CustomizingContextLoader.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/CustomizingContextLoader.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,61 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.spring;
+
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.spring.TapestryApplicationContext;
+import org.springframework.context.ApplicationContextException;
+import org.springframework.web.context.ConfigurableWebApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import javax.servlet.ServletContext;
+
+public class CustomizingContextLoader extends ContextLoader
+{
+    private final ApplicationContextCustomizer customizer;
+
+    public CustomizingContextLoader(ApplicationContextCustomizer customizer)
+    {
+        this.customizer = customizer;
+    }
+
+    @Override
+    protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext)
+    {
+        customizer.customizeApplicationContext(servletContext, applicationContext);
+    }
+
+    @Override
+    protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException
+    {
+        String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
+
+        if (InternalUtils.isNonBlank(contextClassName))
+        {
+            Class result = super.determineContextClass(servletContext);
+
+            if (!TapestryApplicationContext.class.isAssignableFrom(result))
+                throw new IllegalArgumentException(String.format(
+                        "When using the Tapestry/Spring integration library, you must specifiy a context class that extends from %s. Class %s does not. Update the '%s' servlet context init parameter.",
+                        TapestryApplicationContext.class.getName(),
+                        result.getName(),
+                        CONTEXT_CLASS_PARAM));
+
+            return result;
+        }
+
+        return TapestryApplicationContext.class;
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModule.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModule.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModule.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,53 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.spring;
+
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.services.ApplicationInitializer;
+import org.apache.tapestry5.services.ApplicationInitializerFilter;
+import org.apache.tapestry5.services.Context;
+import org.slf4j.Logger;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.SpringVersion;
+
+/**
+ * Module for Tapestry/Spring Integration. This module exists to force the load of the Spring ApplicationContext as part
+ * of Tapestry application initialization.
+ */
+public class SpringModule
+{
+    private final Logger logger;
+
+    public SpringModule(Logger logger)
+    {
+        this.logger = logger;
+    }
+
+    public void contributeApplicationInitializer(
+            OrderedConfiguration<ApplicationInitializerFilter> configuration, final ApplicationContext springContext)
+    {
+        ApplicationInitializerFilter filter = new ApplicationInitializerFilter()
+        {
+            public void initializeApplication(Context context, ApplicationInitializer initializer)
+            {
+                logger.info(String.format("Spring version %s with %,d defined beans.",
+                                          SpringVersion.getVersion(),
+                                          springContext.getBeanDefinitionCount()));
+            }
+        };
+
+        configuration.add("SpringContextInitialization", filter);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/SpringModuleDef.java Mon Dec 29 14:59:10 2008
@@ -14,21 +14,28 @@
 
 package org.apache.tapestry5.internal.spring;
 
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.ScopeConstants;
-import org.apache.tapestry5.ioc.ServiceBuilderResources;
+import org.apache.tapestry5.internal.AbstractContributionDef;
+import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.def.ContributionDef;
 import org.apache.tapestry5.ioc.def.DecoratorDef;
 import org.apache.tapestry5.ioc.def.ModuleDef;
 import org.apache.tapestry5.ioc.def.ServiceDef;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
-import org.springframework.beans.factory.BeanFactoryUtils;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.Invokable;
+import org.apache.tapestry5.ioc.services.ClassFabUtils;
+import org.apache.tapestry5.ioc.services.RegistryShutdownHub;
+import org.apache.tapestry5.ioc.services.RegistryShutdownListener;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.SpringVersion;
+import org.springframework.web.context.ConfigurableWebApplicationContext;
 import org.springframework.web.context.WebApplicationContext;
 
+import javax.servlet.ServletContext;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * A wrapper that converts a Spring {@link ApplicationContext} into a set of service definitions, compatible with
@@ -36,90 +43,79 @@
  */
 public class SpringModuleDef implements ModuleDef
 {
-    private static final String CONTEXT_SERVICE_ID = WebApplicationContext.class.getSimpleName();
+    private static final String SERVICE_ID = "ApplicationContext";
 
-    private final Map<String, ServiceDef> serviceDefs = newCaseInsensitiveMap();
+    private final Map<String, ServiceDef> services = CollectionFactory.newMap();
 
-    public SpringModuleDef(final ApplicationContext context)
+    private final AtomicBoolean applicationContextCreated = new AtomicBoolean(false);
+
+    public SpringModuleDef(final ServletContext servletContext, final ApplicationContextCustomizer customizer)
     {
-        for (final String beanName : BeanFactoryUtils.beanNamesIncludingAncestors(context))
+        ServiceDef sd = new ServiceDef()
         {
-            ServiceDef serviceDef = new ServiceDef()
+            public ObjectCreator createServiceCreator(final ServiceBuilderResources resources)
             {
-                private Object getBean()
-                {
-                    return context.getBean(beanName);
-                }
-
-                private Class getBeanType()
-                {
-                    return context.getType(beanName);
-                }
+                final CustomizingContextLoader loader = new CustomizingContextLoader(
+                        customizer);
 
-                public ObjectCreator createServiceCreator(ServiceBuilderResources resources)
+                final RegistryShutdownListener shutdownListener = new RegistryShutdownListener()
                 {
-                    return new ObjectCreator()
+                    public void registryDidShutdown()
                     {
-                        public Object createObject()
-                        {
-                            return getBean();
-                        }
-                    };
-                }
-
-                public String getServiceId()
-                {
-                    return beanName;
-                }
-
-                public Class getServiceInterface()
-                {
-                    return getBeanType();
-                }
-
-                public String getServiceScope()
-                {
-                    return ScopeConstants.DEFAULT;
-                }
-
-                public boolean isEagerLoad()
-                {
-                    return false;
-                }
-
-                /** Returns an empty set, Spring has no concept of a marker annotation. */
-                public Set<Class> getMarkers()
-                {
-                    return Collections.emptySet();
-                }
-            };
+                        loader.closeWebApplicationContext(servletContext);
+                    }
+                };
 
-            serviceDefs.put(beanName, serviceDef);
-        }
+                final RegistryShutdownHub shutdownHub = resources.getService(RegistryShutdownHub.class);
 
-        // And add one service that is the Spring WebApplicationContext.
 
-        ServiceDef serviceDef = new ServiceDef()
-        {
-            public ObjectCreator createServiceCreator(ServiceBuilderResources resources)
-            {
                 return new ObjectCreator()
                 {
                     public Object createObject()
                     {
-                        return context;
+                        return resources.getTracker().invoke(
+                                "Creating Spring ApplicationContext via ContextLoader",
+                                new Invokable<Object>()
+                                {
+                                    public Object invoke()
+                                    {
+                                        resources.getLogger().info(String.format(
+                                                "Starting Spring (version %s)",
+                                                SpringVersion.getVersion()));
+
+                                        WebApplicationContext context = loader.initWebApplicationContext(
+                                                servletContext);
+
+                                        shutdownHub.addRegistryShutdownListener(shutdownListener);
+
+                                        applicationContextCreated.set(true);
+
+                                        return context;
+                                    }
+                                });
+                    }
+
+                    @Override
+                    public String toString()
+                    {
+                        return "ObjectCreator for Spring ApplicationContext";
                     }
                 };
             }
 
             public String getServiceId()
             {
-                return CONTEXT_SERVICE_ID;
+                return SERVICE_ID;
+            }
+
+            public Set<Class> getMarkers()
+            {
+                return Collections.emptySet();
             }
 
             public Class getServiceInterface()
             {
-                return WebApplicationContext.class;
+                return ConfigurableWebApplicationContext.class;
             }
 
             public String getServiceScope()
@@ -131,15 +127,9 @@
             {
                 return false;
             }
-
-            /** Returns null. */
-            public Set<Class> getMarkers()
-            {
-                return Collections.emptySet();
-            }
         };
 
-        serviceDefs.put(CONTEXT_SERVICE_ID, serviceDef);
+        services.put(SERVICE_ID, sd);
     }
 
     public Class getBuilderClass()
@@ -148,11 +138,96 @@
     }
 
     /**
-     * Returns an empty set.
+     * Returns a contribution, "SpringBean", to the MasterObjectProvider service.  It is ordered after the built-in
+     * contributions.
      */
     public Set<ContributionDef> getContributionDefs()
     {
-        return Collections.emptySet();
+        ContributionDef def = createContributionToMasterObjectProvider();
+
+        return CollectionFactory.newSet(def);
+    }
+
+    private ContributionDef createContributionToMasterObjectProvider()
+    {
+        final ObjectProvider springBeanProvider = new ObjectProvider()
+        {
+            public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator)
+            {
+                ApplicationContext context = locator.getService(SERVICE_ID, ApplicationContext.class);
+
+                Map beanMap = context.getBeansOfType(objectType);
+
+                switch (beanMap.size())
+                {
+                    case 0:
+                        return null;
+
+                    case 1:
+
+                        Object bean = beanMap.values().iterator().next();
+
+                        return objectType.cast(bean);
+
+                    default:
+
+                        String message = String.format("Spring context contains %d beans assignable to type %s: %s.",
+                                                       beanMap.size(),
+                                                       ClassFabUtils.toJavaClassName(objectType),
+                                                       InternalUtils.joinSorted(beanMap.keySet()));
+
+                        throw new IllegalArgumentException(message);
+                }
+            }
+        };
+
+        ContributionDef def = new AbstractContributionDef()
+        {
+            public String getServiceId()
+            {
+                return "MasterObjectProvider";
+            }
+
+            @Override
+            public void contribute(ModuleBuilderSource moduleBuilderSource, ServiceResources resources,
+                                   OrderedConfiguration configuration)
+            {
+                final OperationTracker tracker = resources.getTracker();
+
+                final ObjectProvider springBeanProviderInvoker = new ObjectProvider()
+                {
+                    public <T> T provide(final Class<T> objectType, final AnnotationProvider annotationProvider,
+                                         final ObjectLocator locator)
+                    {
+                        return tracker.invoke(
+                                "Resolving dependency by searching Spring ApplicationContext",
+                                new Invokable<T>()
+                                {
+                                    public T invoke()
+                                    {
+                                        return springBeanProvider.provide(objectType, annotationProvider, locator);
+                                    }
+                                });
+                    }
+                };
+
+                ObjectProvider outerCheck = new ObjectProvider()
+                {
+                    public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider,
+                                         ObjectLocator locator)
+                    {
+                        if (!applicationContextCreated.get()) return null;
+
+                        return springBeanProviderInvoker.provide(objectType, annotationProvider, locator);
+                    }
+                };
+
+
+                configuration.add("SpringBean", outerCheck, "after:Service,Alias,Autobuild");
+            }
+        };
+
+        return def;
     }
 
     /**
@@ -170,11 +245,11 @@
 
     public ServiceDef getServiceDef(String serviceId)
     {
-        return serviceDefs.get(serviceId);
+        return services.get(serviceId);
     }
 
     public Set<String> getServiceIds()
     {
-        return serviceDefs.keySet();
+        return services.keySet();
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/TapestyBeanFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/TapestyBeanFactory.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/TapestyBeanFactory.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/internal/spring/TapestyBeanFactory.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,77 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.spring;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.InjectService;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.TypeConverter;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.config.DependencyDescriptor;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+/**
+ * Identifies dependencies whose field or method parameter contains the {@link org.apache.tapestry5.ioc.annotations.Inject}
+ * or {@link org.apache.tapestry5.ioc.annotations.InjectService} annotations and, if so, invokes {@link
+ * org.apache.tapestry5.ioc.Registry#getObject(Class, org.apache.tapestry5.ioc.AnnotationProvider)} to provide the
+ * value.
+ */
+public class TapestyBeanFactory extends DefaultListableBeanFactory
+{
+    private final Registry registry;
+
+    public TapestyBeanFactory(BeanFactory parentBeanFactory, Registry registry)
+    {
+        super(parentBeanFactory);
+
+        this.registry = registry;
+    }
+
+    @Override
+    public Object resolveDependency(final DependencyDescriptor descriptor, String beanName, Set autowiredBeanNames,
+                                    TypeConverter typeConverter) throws BeansException
+    {
+
+        Class objectType = descriptor.getDependencyType();
+
+        final Object[] annotations = descriptor.getAnnotations();
+
+        if (annotations != null)
+        {
+            AnnotationProvider provider = new AnnotationProvider()
+            {
+                public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+                {
+                    for (Object a : annotations)
+                    {
+                        if (annotationClass.isInstance(a)) return annotationClass.cast(a);
+                    }
+
+                    return null;
+                }
+            };
+
+            if (provider.getAnnotation(Inject.class) != null || provider.getAnnotation(InjectService.class) != null)
+                return registry.getObject(objectType, provider);
+        }
+
+        return super.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
+    }
+}
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestryApplicationContext.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestryApplicationContext.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestryApplicationContext.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestryApplicationContext.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,42 @@
+// Copyright 2008 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.spring;
+
+import org.apache.tapestry5.TapestryFilter;
+import org.apache.tapestry5.internal.spring.TapestyBeanFactory;
+import org.apache.tapestry5.ioc.Registry;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.web.context.support.XmlWebApplicationContext;
+
+/**
+ * Extension of Spring's {@link org.springframework.web.context.support.XmlWebApplicationContext} that includes hooks to
+ * resolve some injections into Spring beans as Tapestry services. When using the Tapestry/Spring Integration Library,
+ * this class (or a subclass) must be the configured context class.  If not specified, this  class is the default
+ * context class.
+ */
+public class TapestryApplicationContext extends XmlWebApplicationContext
+{
+    @Override
+    protected DefaultListableBeanFactory createBeanFactory()
+    {
+        Registry registry = (Registry) getServletContext().getAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME);
+
+        if (registry == null)
+            throw new IllegalStateException(
+                    "Expected a Tapestry IoC Registry to be stored in the ServletContext, but the attribute was null.");
+
+        return new TapestyBeanFactory(getInternalParentBeanFactory(), registry);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestrySpringFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestrySpringFilter.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestrySpringFilter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/main/java/org/apache/tapestry5/spring/TapestrySpringFilter.java Mon Dec 29 14:59:10 2008
@@ -15,10 +15,11 @@
 package org.apache.tapestry5.spring;
 
 import org.apache.tapestry5.TapestryFilter;
+import org.apache.tapestry5.internal.spring.ApplicationContextCustomizer;
 import org.apache.tapestry5.internal.spring.SpringModuleDef;
 import org.apache.tapestry5.ioc.def.ModuleDef;
 import org.springframework.context.ApplicationContext;
-import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.ConfigurableWebApplicationContext;
 
 import javax.servlet.ServletContext;
 
@@ -27,26 +28,25 @@
  * were Tapestry IoC services. This is done using a filter, so that the Spring beans can be "mixed into" the Tapestry
  * IoC Registry before it even starts up.
  */
-public class TapestrySpringFilter extends TapestryFilter
+public class TapestrySpringFilter extends TapestryFilter implements ApplicationContextCustomizer
 {
     @Override
     protected ModuleDef[] provideExtraModuleDefs(ServletContext context)
     {
-        ApplicationContext springContext = null;
-
-        try
-        {
-            springContext = (ApplicationContext) context
-                    .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
-        }
-        catch (Exception ex)
-        {
-            throw new RuntimeException(SpringMessages.failureObtainingContext(ex), ex);
-        }
-
-        if (springContext == null) throw new RuntimeException(SpringMessages.missingContext());
+        return new ModuleDef[] {
+                new SpringModuleDef(context, this)
+        };
+    }
 
-        return new ModuleDef[]
-                { new SpringModuleDef(springContext) };
+    /**
+     * This implementation does nothing; subclasses may override to perform additional customizations and
+     * initializations of the application context.
+     *
+     * @param servletContext
+     * @param applicationContext
+     */
+    public void customizeApplicationContext(ServletContext servletContext,
+                                            ConfigurableWebApplicationContext applicationContext)
+    {
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-spring/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/site/apt/index.apt?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/site/apt/index.apt Mon Dec 29 14:59:10 2008
@@ -6,31 +6,31 @@
 
   Provides integration between Tapestry and Spring, allowing beans defined by Spring to be injected into Tapestry IoC services, and into
   Tapestry components.
-  
-Version
 
-  This module is compiled and tested against Spring 1.2.8.  However, Spring 2.0 is fully backwards compatible to Spring 1.2.8.
-  
-  This module uses the Maven scope "provided" for the dependencies on Spring. This means that in your own POM, you will need to specify your own
-  dependency to Spring, including the correct version.  Example:
-  
-+---+
-<dependency>
-  <groupId>org.springframework</groupId>
-  <artifactId>spring-web</artifactId>
-  <version>1.2.8</version>
-</dependency>    
-+----+
+Changes From 5.0
 
-  With the default Maven scope, the Spring JARs and dependencies will be packaged into your application's WAR file.
-  
+ You may now use the @Inject or @InjectService annotations inside Spring beans; these will be resolved to
+ Tapestry services or other objects available via the MasterObjectProvider.  Please see
+ the {{{../tapestry-ioc/injection.html}detailed guide to Injection}}.
+
+ The dependency on Spring is no longer scope "provider" and has changed to 2.5.6.
+
+ <<Spring Beans are no longer exposed as services.>>
+
+ You no longer create a ContextLoaderListener.
   
+Spring Version
+
+  This module is compiled and tested against Spring 2.5.6.  It should be resonable to override the dependency to earlier versions
+  of Spring, though the code makes use of some APIs that were added to Spring to support JDK 1.5 annotations. 
+    
 Usage
 
   The integration is designed to be a very thin layer on top of Spring's normal configuration for a web application.
   
   Detailed instructions are available in the
-  {{{http://static.springframework.org/spring/docs/1.2.x/reference/beans.html#context-create}Spring 1.2.x documentation}}.
+  {{{http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#context-create}Spring documentation}}. Please omit
+  the part about creating a ContextLoaderListener: this is now done automatically by Tapestry.
   
 * web.xml changes
   
@@ -46,25 +46,17 @@
   </filter>
 +---+  
  
-   Secondly, you must add the normal Spring configuration, consisting of a \<listener\> element,
-   and (optionally) a \<context-param\> identifying which Spring bean configuration file(s) to load:
+   Secondly, you may add the normal Spring configuration, consisting of an optional \<context-param\> identifying which Spring bean configuration file(s) to load:
  
 +---+
 <context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
 </context-param>
-
-<listener>
-  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
-</listener>
 +---+
 
   The \<context-param\> lists the Spring bean configuration file.  It is optional and defaults to just /WEB-INF/applicationContext.xml if omitted.
-  
-  The ContextLoaderListener is responsible for reading the bean configuration file (or files) and storing the result in the application context, where
-  the Tapestry-Spring integration code can make use of it.
-  
+
 * Injecting beans
 
   Inside your component classes, you may use the 
@@ -76,39 +68,16 @@
   private UserDAO userDAO;
 +----+
 
-  If you have multiple beans that implement the same interface (for instance, if you have wrapped your bean using a transaction interceptor), you must disambiguate.  The easiest way
-  to accomplish this is to add a 
-  {{{../apidocs/org/apache/tapestry5/annotations/Service.html}Service}}
-  annotation to identify the name of the
-  Spring bean:
-  
-+----+
-  @Inject
-  @Service("UserDAO")
-  private UserDAO userDAO;
-+----+  
-  
-  Injection of Spring beans via service builder methods or autobuilding occurs just the same: the Spring beans masquerade as Tapestry IoC services and all is well.
- 
-Case Insensitivity
+  Searching for Spring beans is threaded into the {{{../tapestry-ioc/injection.html}MasterObjectProvider service}}. The Spring context becomes one
+  more place that Tapestry searches when determining the injection for a injected field or method parameter.
 
-  Spring beans names are treated exactly as Tapestry IoC service ids.  Since service ids are case insensitive, access to Spring beans by bean name will also
-  be case insensitive.
   
-WebApplicationContext Service
+ApplicationContext Service
 
-  The Spring WebApplicationContext is also added as a service, in addition to any services defined within the context.
+  The Spring ApplicationContext is also added as a service.
   
 Limitations
 
-  The names of beans are obtained at application start up. If new beans are programattically added to the Spring application context at runtime,
-  these will not be visible for injection.
-  
-  Only the bean <name> is used, not any of the bean's <aliases>.
-  
-  No check is made for name clashes that would occur when two beans have names that differ only in terms of capitalization.  If you're going to go around naming beans "userDAO" and "UserDao",
-  you're just asking for trouble.
-  
   Non-singleton beans are not handled properly. Tapestry will request the beans from the application context in a manner unsuitable for their lifecycle.
-  For the moment, you should consider the non-singleton beans to be not-injectable.  Instead, inject the WebApplicationContext service and
+  For the moment, you should consider the non-singleton beans to be not-injectable.  Instead, inject the ApplicationContext service and
   obtain the non-singleton beans as needed.

Modified: tapestry/tapestry5/trunk/tapestry-spring/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/test/conf/testng.xml?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/test/conf/testng.xml Mon Dec 29 14:59:10 2008
@@ -19,6 +19,7 @@
     <test name="Tapestry Spring Integration">
         <packages>
             <package name="org.apache.tapestry5.spring"/>
+            <package name="org.apache.tapestry5.internal.spring"/>
         </packages>
     </test>
 </suite>

Added: tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/CustomizingContextLoaderTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/CustomizingContextLoaderTest.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/CustomizingContextLoaderTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/internal/spring/CustomizingContextLoaderTest.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,79 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.spring;
+
+import org.apache.tapestry5.ioc.test.TestBase;
+import org.apache.tapestry5.spring.TapestryApplicationContext;
+import org.springframework.web.context.ContextLoader;
+import org.springframework.web.context.support.XmlWebApplicationContext;
+import org.testng.annotations.Test;
+
+import javax.servlet.ServletContext;
+
+public class CustomizingContextLoaderTest extends TestBase
+{
+    @Test
+    public void specified_context_class_is_not_compatible()
+    {
+        ServletContext context = mockServletContext();
+
+        train_getInitParameter(context, ContextLoader.CONTEXT_CLASS_PARAM, XmlWebApplicationContext.class.getName());
+
+        replay();
+
+        CustomizingContextLoader ccl = new CustomizingContextLoader(null);
+
+        try
+        {
+            ccl.determineContextClass(context);
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertMessageContains(ex,
+                                  "context class that extends from org.apache.tapestry5.spring.TapestryApplicationContext",
+                                  "Class org.springframework.web.context.support.XmlWebApplicationContext does not.",
+                                  "Update the 'contextClass' servlet context init parameter.");
+        }
+
+        verify();
+    }
+
+    protected final void train_getInitParameter(ServletContext context, String parameterName, String parameterValue)
+    {
+        expect(context.getInitParameter(parameterName)).andReturn(parameterValue).atLeastOnce();
+    }
+
+    protected final ServletContext mockServletContext()
+    {
+        return newMock(ServletContext.class);
+    }
+
+    @Test
+    public void specified_context_class_is_compatible()
+    {
+        ServletContext context = mockServletContext();
+
+        train_getInitParameter(context, ContextLoader.CONTEXT_CLASS_PARAM, TapestryApplicationContext.class.getName());
+
+        replay();
+
+        CustomizingContextLoader ccl = new CustomizingContextLoader(null);
+
+        assertSame(ccl.determineContextClass(context), TapestryApplicationContext.class);
+
+        verify();
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryApplicationContextTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryApplicationContextTest.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryApplicationContextTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestryApplicationContextTest.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,49 @@
+// Copyright 2008 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.spring;
+
+import org.apache.tapestry5.TapestryFilter;
+import org.apache.tapestry5.ioc.test.TestBase;
+import org.testng.annotations.Test;
+
+import javax.servlet.ServletContext;
+
+public class TapestryApplicationContextTest extends TestBase
+{
+    @Test
+    public void no_registry_in_servlet_context()
+    {
+        ServletContext context = newMock(ServletContext.class);
+
+        expect(context.getAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME)).andReturn(null);
+
+        replay();
+
+        TapestryApplicationContext tac = new TapestryApplicationContext();
+
+        tac.setServletContext(context);
+
+        try
+        {
+            tac.createBeanFactory();
+            unreachable();
+        }
+        catch (IllegalStateException ex)
+        {
+        }
+
+        verify();
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestrySpringIntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestrySpringIntegrationTest.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestrySpringIntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/apache/tapestry5/spring/TapestrySpringIntegrationTest.java Mon Dec 29 14:59:10 2008
@@ -40,6 +40,24 @@
     {
         open(BASE_URL);
 
-        assertTextPresent("[upcase]");
+        String text = getText("beans");
+        assertTrue(text.contains("upcase"));
+    }
+
+    @Test
+    public void customize_method_of_filter_subclass_invoked() throws Exception
+    {
+        open(BASE_URL);
+
+        assertText("message", "SPRING VERSION 2.5.6: FILTER INITIALIZED");
+    }
+
+    @Test
+    public void too_many_spring_beans_are_assignable()
+    {
+        open(BASE_URL + "bedrock");
+
+        assertTextPresent(
+                "Spring context contains 2 beans assignable to type org.example.testapp.services.Flintstone: barney, fred.");
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Bedrock.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Bedrock.java?rev=730009&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Bedrock.java (added)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Bedrock.java Mon Dec 29 14:59:10 2008
@@ -0,0 +1,27 @@
+// Copyright 2008 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.example.testapp.pages;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.example.testapp.services.Flintstone;
+
+/**
+ * Not intstantiable because there is more than one Flintstone implementation bean inside the Spring context.
+ */
+public class Bedrock
+{
+    @Inject
+    private Flintstone citizen;
+}

Modified: tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Start.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Start.java?rev=730009&r1=730008&r2=730009&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Start.java (original)
+++ tapestry/tapestry5/trunk/tapestry-spring/src/test/java/org/example/testapp/pages/Start.java Mon Dec 29 14:59:10 2008
@@ -14,11 +14,13 @@
 
 package org.example.testapp.pages;
 
+import org.apache.tapestry5.annotations.Property;
 import org.apache.tapestry5.annotations.Retain;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.example.testapp.services.SpringStatusProvider;
 import org.example.testapp.services.Upcase;
-import org.springframework.web.context.WebApplicationContext;
+import org.springframework.context.ApplicationContext;
 
 import java.util.Arrays;
 
@@ -32,7 +34,11 @@
     private Upcase upcaseBean;
 
     @Inject
-    private WebApplicationContext context;
+    private ApplicationContext applicationContext;
+
+    @Inject
+    @Property
+    private SpringStatusProvider statusProvider;
 
     void onSuccess()
     {
@@ -51,7 +57,6 @@
 
     public String getSpringBeans()
     {
-        return InternalUtils.join(Arrays.asList(context.getBeanDefinitionNames()));
+        return InternalUtils.join(Arrays.asList(applicationContext.getBeanDefinitionNames()));
     }
-
 }