Author: hlship
Date: Mon Jan  5 10:19:30 2009
New Revision: 731641

URL: http://svn.apache.org/viewvc?rev=731641&view=rev
Log:
TAP5-316: Add service overriding capabilities to tapestry-ioc, similar to what 
tapestry-core has (the Alias service)

Added:
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceOverrideImpl.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceOverride.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/cookbook/override.apt
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/GreeterServiceOverrideModule.java
Modified:
    tapestry/tapestry5/trunk/src/site/apt/cookbook/exceptions.apt
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/site.xml
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java

Modified: tapestry/tapestry5/trunk/src/site/apt/cookbook/exceptions.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/cookbook/exceptions.apt?rev=731641&r1=731640&r2=731641&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/cookbook/exceptions.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/cookbook/exceptions.apt Mon Jan  5 
10:19:30 2009
@@ -224,8 +224,48 @@
 
 [error3.png] Errors show on Index page
 
+Version 3: Overriding  RequestExceptionHandler using ServiceOverride
+
+  The Alias service is part of tapestry-core; starting in Tapestry 5.1, there 
is an additional service, part of
+  tapestry-ioc, for overriding services. It is a bit simpler than Alias:
+
+  <<AppModule.java>> (partial)
+
+----
+    public RequestExceptionHandler buildAppRequestExceptionHandler(
+            final Logger logger,
+            final ResponseRenderer renderer,
+            final ComponentSource componentSource)
+    {
+        return new RequestExceptionHandler()
+        {
+            public void handleRequestException(Throwable exception) throws 
IOException
+            {
+                logger.error("Unexpected runtime exception: " + 
exception.getMessage(), exception);
+
+                ExceptionReporter index = (ExceptionReporter) 
componentSource.getPage("Index");
+
+                index.reportException(exception);
+
+                renderer.renderPageMarkupResponse("Index");
+            }
+        };
+    }
+
+    public void contributeServiceOverride(
+            MappedConfiguration<Class, Object> configuration,
+
+            @Local
+            RequestExceptionHandler handler)
+    {
+        configuration.add(RequestExceptionHandler.class, handler);
+    }
+----
+
+  This solution is similar to version 3, except that instead of contributing 
to Alias, we contribute
+  to ServiceOverride, and use a mapped configuration.
    
-Version 3: Decorating the RequestExceptionHandler
+Version 4: Decorating the RequestExceptionHandler
 
   A third option is available: we don't define a <new> service, but instead 
<decorate> the existing
   RequestExceptionHandler service. This approach means we don't have to make a 
contribution to the Alias service.

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=731641&r1=731640&r2=731641&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 Jan  5 10:19:30 2009
@@ -552,11 +552,11 @@
             }
         };
 
-        configuration.add("Alias", wrapper, "after:Value,Symbol");
+        configuration.add("Alias", wrapper, "after:ServiceOverride");
 
-        configuration.add("Asset", assetObjectProvider, "before:Alias");
+        configuration.add("Asset", assetObjectProvider, 
"before:AnnotationBasedContributions");
 
-        configuration.add("Service", new ServiceAnnotationObjectProvider(), 
"before:Alias");
+        configuration.add("Service", new ServiceAnnotationObjectProvider(), 
"before:AnnotationBasedContributions");
     }
 
 

Added: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceOverrideImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceOverrideImpl.java?rev=731641&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceOverrideImpl.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceOverrideImpl.java
 Mon Jan  5 10:19:30 2009
@@ -0,0 +1,43 @@
+// Copyright 2009 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.ObjectProvider;
+import org.apache.tapestry5.ioc.services.ServiceOverride;
+
+import java.util.Map;
+
+public class ServiceOverrideImpl implements ServiceOverride
+{
+    private final Map<Class, Object> configuration;
+
+    public ServiceOverrideImpl(Map<Class, Object> configuration)
+    {
+        this.configuration = configuration;
+    }
+
+    public ObjectProvider getServiceOverrideProvider()
+    {
+        return new ObjectProvider()
+        {
+            public <T> T provide(Class<T> objectType, AnnotationProvider 
annotationProvider, ObjectLocator locator)
+            {
+                return objectType.cast(configuration.get(objectType));
+            }
+        };
+    }
+}

Added: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceOverride.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceOverride.java?rev=731641&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceOverride.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceOverride.java
 Mon Jan  5 10:19:30 2009
@@ -0,0 +1,27 @@
+// Copyright 2009 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.ioc.services;
+
+import org.apache.tapestry5.ioc.ObjectProvider;
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+
+/**
+ * Used to override built in services.
+ */
+...@usesmappedconfiguration(key = Class.class, value = Object.class)
+public interface ServiceOverride
+{
+    ObjectProvider getServiceOverrideProvider();
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java?rev=731641&r1=731640&r2=731641&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
 Mon Jan  5 10:19:30 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009 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.
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.ioc.services;
 
 import org.apache.tapestry5.ioc.*;
+import org.apache.tapestry5.ioc.annotations.Local;
 import org.apache.tapestry5.ioc.annotations.Marker;
 import org.apache.tapestry5.ioc.annotations.PreventServiceDecoration;
 import org.apache.tapestry5.ioc.internal.services.*;
@@ -56,6 +57,7 @@
         binder.bind(ClassNameLocator.class, ClassNameLocatorImpl.class);
         binder.bind(AspectDecorator.class, AspectDecoratorImpl.class);
         binder.bind(ClasspathURLConverter.class, 
ClasspathURLConverterImpl.class);
+        binder.bind(ServiceOverride.class, ServiceOverrideImpl.class);
     }
 
     /**
@@ -83,15 +85,33 @@
     }
 
     /**
-     * <dl> <dt>Value</dt> <dd>Supports the {...@link 
org.apache.tapestry5.ioc.annotations.Value} annotation</dd>
-     * <dt>Symbol</dt> <dd>Supports the {...@link 
org.apache.tapestry5.ioc.annotations.Symbol} annotations</dd>
-     * <dt>Autobuild</dt> <dd>Supports the {...@link 
org.apache.tapestry5.ioc.annotations.Autobuild} annotation</dd> </dl>
+     * <dl> <dt>AnnotationBasedContributions</dt> <dd>Empty placeholder used 
to seperate annotation-based ObjectProvider
+     * contributions (which come before) from non-annotation based 
(ServiceOverride here, Alias in tapestry-core) which
+     * come after. </dd> <dt>Value</dt> <dd>Supports the {...@link 
org.apache.tapestry5.ioc.annotations.Value}
+     * annotation</dd> <dt>Symbol</dt> <dd>Supports the {...@link 
org.apache.tapestry5.ioc.annotations.Symbol}
+     * annotations</dd> <dt>Autobuild</dt> <dd>Supports the {...@link 
org.apache.tapestry5.ioc.annotations.Autobuild}
+     * annotation</dd> <dt>ServiceOverride</dt> <dd>Allows simple service 
overrides via the {...@link
+     * org.apache.tapestry5.ioc.services.ServiceOverride} service (and its 
configuration)</dl>
      */
-    public static void 
contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> 
configuration)
+    public static void 
contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> 
configuration,
+                                                      @Local final 
ServiceOverride serviceOverride)
     {
-        configuration.addInstance("Value", ValueObjectProvider.class);
-        configuration.addInstance("Symbol", SymbolObjectProvider.class);
-        configuration.add("Autobuild", new AutobuildObjectProvider());
+        configuration.add("AnnotationBasedContributions", null);
+
+        configuration.addInstance("Value", ValueObjectProvider.class, 
"before:AnnotationBasedContributions");
+        configuration.addInstance("Symbol", SymbolObjectProvider.class, 
"before:AnnotationBasedContributions");
+        configuration.add("Autobuild", new AutobuildObjectProvider(), 
"before:AnnotationBasedContributions");
+
+
+        ObjectProvider wrapper = new ObjectProvider()
+        {
+            public <T> T provide(Class<T> objectType, AnnotationProvider 
annotationProvider, ObjectLocator locator)
+            {
+                return 
serviceOverride.getServiceOverrideProvider().provide(objectType, 
annotationProvider, locator);
+            }
+        };
+
+        configuration.add("ServiceOverride", wrapper, 
"after:AnnotationBasedContributions");
     }
 
     /**

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/cookbook/override.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/cookbook/override.apt?rev=731641&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/cookbook/override.apt 
(added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/cookbook/override.apt 
Mon Jan  5 10:19:30 2009
@@ -0,0 +1,96 @@
+ ----
+ Overriding Services
+ ----
+
+Overriding Services
+
+  Tapestry is designed to be easy to customize, and the IoC container is key 
to that customizability.
+
+  Part of Tapestry's core functionality is resolving injected objects; that 
is, when Tapestry is building an object
+  or service and sees a constructor parameter or a field, what value does it 
plug in?  Most of the time,
+  the injected object is a service defined elsewhere within the container 
(and, in fact, that actual instance
+  will be a proxy to the service, which may not have been fully realized yet).
+
+  However, there are cases where you might want to override how Tapestry 
operates in some specific way.
+
+  The strategy used to determine what object gets injected where is
+  {{{../injection.html}defined inside Tapestry IoC itself}}; thus we can take 
advantage of
+  several features of the IoC container in order to take control over specific 
injections.
+
+Overriding Services
+
+  In most cases, services are injected by matching just type; there no 
@InjectService annotation,
+  just a method or constructor parameter whose type matches the service's 
interface.
+
+  In this case, it is very easy to supply your own alternate implementation of 
a service.
+
+  <<AppModule.java>> (partial)
+
+----
+  public static void 
contributeServiceOverride(MappedConfiguration<Class,Object> configuration)
+  {
+    configuration.add(SomeServiceType.class, new SomeServiceType() { . . . });
+  }
+----
+
+  In this example, the service to be overriden is provided as an  inner class 
implementing the interface.
+
+  Sometimes you'll want to define the override as a service of its own: this 
is useful if you want
+  to inject a Logger specific to the service, or if the overriding 
implementation needs a configuration:
+
+
+  <<AppModule.java>> (partial)
+
+----
+  public static void bind(ServiceBinder binder)
+  {
+    binder.bind(SomeServiceType.class, 
SomeServiceTypeOverrideImpl.class).withId("Override");
+  }
+
+  public static void 
contributeServiceOverride(MappedConfiguration<Class,Object> configuration, 
@Local SomeServiceType override)
+  {
+    configuration.add(SomeServiceType.class, override);
+  }
+----
+
+  Here we're defining a service local to this module using the bind() method.
+
+  Every service in the IoC container must have a unique id, that's why we used 
the withId() method; if we we hadn't,
+  the default service id would have been "SomeServiceType" which is a likely 
conflict with the very service we're trying to
+  override.
+
+  We can inject our overriding implementation of SomeServiceType using the 
special
+  @{{{../../apidocs/org/apache/tapestry5/annotations/Local.html}Local}} 
annotation, which indicates that a service
+  within the same module only should be injected: otherwise there would be a 
problem because the override parameter
+  would need to be resolved using the MasterObjectProvider and, ultimately, 
the ServiceOverride service; this would cause
+  Tapestry to throw an exception indicating that ServiceOverride depends on 
itself.  We defuse that situation by using
+  @Local, which prevents the MasterObjectProvider service from being used to 
resolve the override parameter.
+
+Decorating Services
+
+  Another option is to {{{../deocrator.html}decorate}} the existing service.  
Perhaps you want to extend some of the behavior
+  of the service but keep the rest.
+
+  Alternately, this approach is useful to override a service that is matched 
using marker annotations.
+
+  <<AppModule.java>> (partial)
+
+----
+  public SomeServiceType decorateSomeServiceType(SomeServiceType original)
+  {
+    return new SomeServiceType() { . . . };
+  }
+----
+
+  This decorate method is invoked because its name matches the service id of 
the original service, "SomeServiceType"
+  (you have to adjust the name to match the service id).
+
+  It is passed the original service and its job it to return an <interceptor>, 
and object that implements the same
+  interface, wrapping around the original service.
+
+  Note that the object passed in as original may be the core service 
implementation, or it may be some other
+  interceptor from some other decorator for the same service (often, such a 
parameter is named "delegate" to highlight
+  this ambiguity).
+
+
+

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=731641&r1=731640&r2=731641&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/injection.apt Mon Jan  5 
10:19:30 2009
@@ -179,6 +179,13 @@
    if so, autobuilds the value for the parameter. Of course, the object being 
built will itself
    be configured via injection.
 
+** ServiceOverride ObjectProvider
+
+   Checks any contributions to the
+   
{{{../apidocs/org/apache/tapestry5/ioc/services/ServiceOverride.html}ServiceOverride}}
 service. Contributions
+   map a type to an object of that type. Thus, ServiceOverrides will override 
injections of services
+   that are not qualified with a marker annotation.
+
 ** Alias ObjectProvider  (tapestry-core)
 
   Uses the
@@ -186,7 +193,7 @@
   that can be injected.
 
   This is commonly used to override a built-in service by contributing an 
object with the
-  exact same interface.
+  exact same interface.           This is an older and more complex version of 
the ServiceOverride provider.
 
 ** Asset ObjectProvider (tapestry-core)
 

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/site.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/site.xml?rev=731641&r1=731640&r2=731641&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/site.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/site.xml Mon Jan  5 10:19:30 
2009
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <!-- 
-   Copyright 2006 The Apache Software Foundation
+   Copyright 2006, 2008, 2009 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.
@@ -78,6 +78,7 @@
             <item name="Basics" href="cookbook/basics.html"/>
             <item name="Service Configurations" href="cookbook/servconf.html"/>
             <item name="Using Patterns" href="cookbook/patterns.html"/>
+            <item name="Overriding Services" href="cookbook/override.html"/>
         </menu>
 
 

Added: 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/GreeterServiceOverrideModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/GreeterServiceOverrideModule.java?rev=731641&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/GreeterServiceOverrideModule.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/GreeterServiceOverrideModule.java
 Mon Jan  5 10:19:30 2009
@@ -0,0 +1,40 @@
+// Copyright 2009 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.ioc;
+
+public class GreeterServiceOverrideModule
+{
+    public Greeter buildDefaultGreeter()
+    {
+        return new Greeter()
+        {
+            public String getGreeting()
+            {
+                return "Hello";
+            }
+        };
+    }
+
+    public static void contributeServiceOverride(MappedConfiguration<Class, 
Object> configuration)
+    {
+        configuration.add(Greeter.class, new Greeter()
+        {
+            public String getGreeting()
+            {
+                return "Override Greeting";
+            }
+        });
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java?rev=731641&r1=731640&r2=731641&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
 Mon Jan  5 10:19:30 2009
@@ -1280,4 +1280,17 @@
                                   "Contribution key fred has already been 
overridden");
         }
     }
+
+    /**
+     * TAP5-316
+     */
+    @Test
+    public void service_override()
+    {
+        Registry r = buildRegistry(GreeterServiceOverrideModule.class);
+
+        Greeter g = r.getObject(Greeter.class, null);
+
+        assertEquals(g.getGreeting(), "Override Greeting");
+    }
 }


Reply via email to