You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2006/11/18 19:51:40 UTC

svn commit: r476585 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/ioc/services/ main/java/org/apache/tapestry/ioc/services/ main/java/org/apache/tapestry/util/ site/ site/apt/ioc/ test/java/org/apache/tapestry...

Author: hlship
Date: Sat Nov 18 10:51:39 2006
New Revision: 476585

URL: http://svn.apache.org/viewvc?view=rev&rev=476585
Log:
Finish implementation of the StrategyBuilder service (and documentation).

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImpl.java
      - copied, changed from r476234, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyServiceBuilderImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyBuilder.java
      - copied, changed from r476234, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyServiceBuilder.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/strategy.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/KindOf.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImplTest.java
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyServiceBuilderImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyServiceBuilder.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/StrategyRegistry.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImpl.java (from r476234, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyServiceBuilderImpl.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImpl.java?view=diff&rev=476585&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyServiceBuilderImpl.java&r1=476234&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImpl.java&r2=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyServiceBuilderImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImpl.java Sat Nov 18 10:51:39 2006
@@ -12,18 +12,86 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.ioc.services;
-
-import org.apache.tapestry.ioc.services.StrategyServiceBuilder;
-import org.apache.tapestry.util.StrategyRegistry;
-
-public class StrategyServiceBuilderImpl implements StrategyServiceBuilder
-{
-    
-    public <S> S build(StrategyRegistry<S> registry)
-    {
-    
-        return null;
-    }
-
-}
+package org.apache.tapestry.internal.ioc.services;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.MethodIterator;
+import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.ioc.services.StrategyBuilder;
+import org.apache.tapestry.util.BodyBuilder;
+import org.apache.tapestry.util.StrategyRegistry;
+
+public class StrategyBuilderImpl implements StrategyBuilder
+{
+    private final ClassFactory _classFactory;
+
+    public StrategyBuilderImpl(ClassFactory classFactory)
+    {
+        _classFactory = classFactory;
+    }
+
+    public <S> S build(StrategyRegistry<S> registry)
+    {
+        Class<S> interfaceClass = registry.getAdapterType();
+
+        // TODO: Could cache the implClass by interfaceClass ... 
+        
+        Class implClass = createImplClass(interfaceClass);
+
+        try
+        {
+            Object raw = implClass.getConstructors()[0].newInstance(registry);
+
+            return interfaceClass.cast(raw);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private Class createImplClass(Class interfaceClass)
+    {
+        ClassFab cf = _classFactory.newClass(interfaceClass);
+
+        String interfaceClassName = interfaceClass.getName();
+
+        cf.addField("_registry", StrategyRegistry.class);
+        cf.addConstructor(new Class[]
+        { StrategyRegistry.class }, null, "_registry = $1;");
+
+        BodyBuilder builder = new BodyBuilder();
+
+        MethodIterator mi = new MethodIterator(interfaceClass);
+
+        while (mi.hasNext())
+        {
+            MethodSignature sig = mi.next();
+
+            // TODO: Checks for methods that don't have at least one parameter, or don't have a
+            // compatible 1st parameter.  Currently, we'll get a Javassist exception.
+
+            builder.clear();
+            builder.begin();
+
+            builder.addln("Object selector = $1;");
+            builder.addln(
+                    "%s adapter = (%<s) _registry.getByInstance(selector);",
+                    interfaceClassName);
+            builder.addln("return ($r) adapter.%s($$);", sig.getName());
+
+            builder.end();
+
+            cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
+
+        }
+
+        if (!mi.getToString())
+            cf.addToString(String.format("<Strategy for %s>", interfaceClassName));
+
+        return cf.createClass();
+    }
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyBuilder.java (from r476234, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyServiceBuilder.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyBuilder.java?view=diff&rev=476585&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyServiceBuilder.java&r1=476234&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyBuilder.java&r2=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyServiceBuilder.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/StrategyBuilder.java Sat Nov 18 10:51:39 2006
@@ -29,7 +29,7 @@
  * 
  * 
  */
-public interface StrategyServiceBuilder
+public interface StrategyBuilder
 {
     /**
      * Given a number of adapters implementing the service interface, builds a "dispatcher"

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java?view=diff&rev=476585&r1=476584&r2=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java Sat Nov 18 10:51:39 2006
@@ -12,364 +12,374 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.services;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry.internal.ioc.services.ChainBuilderImpl;
-import org.apache.tapestry.internal.ioc.services.DefaultImplementationBuilderImpl;
-import org.apache.tapestry.internal.ioc.services.ExceptionAnalyzerImpl;
-import org.apache.tapestry.internal.ioc.services.ExceptionTrackerImpl;
-import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl;
-import org.apache.tapestry.internal.ioc.services.MasterObjectProvider;
-import org.apache.tapestry.internal.ioc.services.PerThreadServiceLifecycle;
-import org.apache.tapestry.internal.ioc.services.PipelineBuilderImpl;
-import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
-import org.apache.tapestry.internal.ioc.services.PropertyShadowBuilderImpl;
-import org.apache.tapestry.internal.ioc.services.ServiceObjectProvider;
-import org.apache.tapestry.internal.ioc.services.TypeCoercerImpl;
-import org.apache.tapestry.internal.services.ComponentInstantiatorSource;
-import org.apache.tapestry.ioc.Configuration;
-import org.apache.tapestry.ioc.MappedConfiguration;
-import org.apache.tapestry.ioc.ObjectProvider;
-import org.apache.tapestry.ioc.ServiceLifecycle;
-import org.apache.tapestry.ioc.annotations.Id;
-import org.apache.tapestry.ioc.annotations.InjectService;
-import org.apache.tapestry.ioc.annotations.Lifecycle;
-
-/**
- * Defines the base set of services for the Tapestry IOC container.
- */
-@Id("tapestry.ioc")
-public final class TapestryIOCModule
-{
-    private final ClassFactory _classFactory;
-
-    public TapestryIOCModule(@InjectService("ClassFactory")
-    ClassFactory classFactory)
-    {
-        _classFactory = classFactory;
-    }
-
-    /**
-     * The LoggingDecorator service is used to decorate a service implementation so that it logs
-     * method entry and exit (at level debug).
-     */
-    public LoggingDecorator buildLoggingDecorator(@InjectService("ExceptionTracker")
-    ExceptionTracker exceptionTracker)
-    {
-        return new LoggingDecoratorImpl(_classFactory, exceptionTracker);
-    }
-
-    /**
-     * Provides access to additional service lifecycles. Two lifecycles are built in ("singleton"
-     * and "primitive") but additional ones are accessed via this service (and its mapped
-     * configuration).
-     */
-    public static ServiceLifecycleSource buildServiceLifecycleSource(
-            final Map<String, ServiceLifecycle> configuration)
-    {
-        return new ServiceLifecycleSource()
-        {
-            public ServiceLifecycle get(String lifecycleName)
-            {
-                return configuration.get(lifecycleName);
-            }
-        };
-    }
-
-    /** Contributes the "perthread" service lifecycle. */
-    public void contributeServiceLifecycleSource(
-            MappedConfiguration<String, ServiceLifecycle> configuration,
-            @InjectService("ThreadCleanupHub")
-            ThreadCleanupHub threadCleanupHub)
-    {
-        configuration.add("perthread", new PerThreadServiceLifecycle(threadCleanupHub,
-                _classFactory));
-    }
-
-    /**
-     * A service that implements the chain of command pattern, creating an efficient implementation
-     * of a chain of command for an arbitrary interface.
-     */
-    public ChainBuilder buildChainBuilder()
-    {
-        return new ChainBuilderImpl(_classFactory);
-    }
-
-    /**
-     * Services that provides read/write access to JavaBean properties. Encapsulates JavaBean
-     * introspection, including serializing access to the non-thread-safe Introspector object.
-     */
-    public static PropertyAccess buildPropertyAccess()
-    {
-        return new PropertyAccessImpl();
-    }
-
-    /**
-     * Builder that creates a shadow, a projection of a property of some other object.
-     */
-    public PropertyShadowBuilder buildPropertyShadowBuilder(@InjectService("PropertyAccess")
-    PropertyAccess propertyAccess)
-    {
-        return new PropertyShadowBuilderImpl(_classFactory, propertyAccess);
-    }
-
-    /**
-     * Builder that creates a filter pipeline around a simple service interface.
-     */
-    public PipelineBuilder buildPipelineBuilder(@InjectService("DefaultImplementationBuilder")
-    DefaultImplementationBuilder builder)
-    {
-        return new PipelineBuilderImpl(_classFactory, builder);
-    }
-
-    /**
-     * Builder that creates a default implementation of an interface.
-     */
-    public DefaultImplementationBuilder buildDefaultImplementationBuilder()
-    {
-        return new DefaultImplementationBuilderImpl(_classFactory);
-    }
-
-    /**
-     * The master {@link ObjectProvider} is responsible for identifying a particular ObjectProvider
-     * by its prefix, and delegating to that instance.
-     * 
-     * @param configuration
-     *            map of ObjectProviders, keyed on prefix
-     */
-    public static ObjectProvider buildMasterObjectProvider(Map<String, ObjectProvider> configuration)
-    {
-        return new MasterObjectProvider(configuration);
-    }
-
-    /**
-     * Contributes the "service:" object provider.
-     */
-    public static void contributeMasterObjectProvider(
-            MappedConfiguration<String, ObjectProvider> configuration)
-    {
-        configuration.add("service", new ServiceObjectProvider());
-    }
-
-    /** Used by the {@link org.apache.tapestry.ioc.services.LoggingDecorator} service. */
-    @Lifecycle("perthread")
-    public static ExceptionTracker buildExceptionTracker()
-    {
-        return new ExceptionTrackerImpl();
-    }
-
-    public static ExceptionAnalyzer buildExceptionAnalyzer(@InjectService("PropertyAccess")
-    PropertyAccess access)
-    {
-        return new ExceptionAnalyzerImpl(access);
-    }
-
-    /**
-     * Returns the service that can coerce between different types.
-     */
-    public static TypeCoercer buildTypeCoercer(Collection<CoercionTuple> configuration)
-    {
-        return new TypeCoercerImpl(configuration);
-    }
-
-    /**
-     * Contributes a set of standard type coercions:
-     * <ul>
-     * <li>Object to String</li>
-     * <li>String to Double</li>
-     * <li>String to BigDecimal</li>
-     * <li>BigDecimal to Double</li>
-     * <li>Double to BigDecimal</li>
-     * <li>String to BigInteger</li>
-     * <li>BigInteger to Long</li>
-     * <li>String to Long</li>
-     * <li>Long to Byte</li>
-     * <li>Long to Short</li>
-     * <li>Long to Integer</li>
-     * <li>Double to Long</li>
-     * <li>Double to Float</li>
-     * <li>Long to Double</li>
-     * <li>String to Boolean ("false" is always false, other non-blank strings are true)</li>
-     * <li>Long to Boolean (true if long value is non zero)</li>
-     * <li>Null to Boolean (always false)</li>
-     * <li>Collection to Boolean (false if empty)</li>
-     * <li>Object to List (by wrapping as a singleton list)</li>
-     * <li>Null to String (still null)</li>
-     * </ul>
-     * 
-     * @see #buildTypeCoercer(Collection, ComponentInstantiatorSource)
-     */
-
-    public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
-    {
-        add(configuration, Object.class, String.class, new Coercion<Object, String>()
-        {
-            public String coerce(Object input)
-            {
-                return input.toString();
-            }
-        });
-
-        add(configuration, void.class, String.class, new Coercion<Void, String>()
-        {
-
-            public String coerce(Void input)
-            {
-                return null;
-            }
-        });
-
-        add(configuration, String.class, Double.class, new Coercion<String, Double>()
-        {
-            public Double coerce(String input)
-            {
-                return new Double(input);
-            }
-        });
-
-        // String to BigDecimal is important, as String->Double->BigDecimal would lose
-        // precision.
-
-        add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
-        {
-            public BigDecimal coerce(String input)
-            {
-                return new BigDecimal(input);
-            }
-        });
-
-        add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
-        {
-            public Double coerce(BigDecimal input)
-            {
-                return input.doubleValue();
-            }
-        });
-
-        add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
-        {
-            public BigInteger coerce(String input)
-            {
-                return new BigInteger(input);
-            }
-        });
-
-        add(configuration, String.class, Long.class, new Coercion<String, Long>()
-        {
-            public Long coerce(String input)
-            {
-                return new Long(input);
-            }
-        });
-
-        add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
-        {
-            public Byte coerce(Long input)
-            {
-                return input.byteValue();
-            }
-        });
-
-        add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
-        {
-            public Short coerce(Long input)
-            {
-                return input.shortValue();
-            }
-        });
-
-        add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
-        {
-            public Integer coerce(Long input)
-            {
-                return input.intValue();
-            }
-        });
-
-        add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
-        {
-            public Long coerce(Number input)
-            {
-                return input.longValue();
-            }
-        });
-
-        add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
-        {
-            public Float coerce(Double input)
-            {
-                return input.floatValue();
-            }
-        });
-
-        add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
-        {
-            public Double coerce(Long input)
-            {
-                return input.doubleValue();
-            }
-        });
-
-        add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
-        {
-            public Boolean coerce(String input)
-            {
-                String trimmed = input.trim();
-
-                if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
-                    return false;
-
-                // Any non-blank string but "false"
-
-                return true;
-            }
-        });
-
-        add(configuration, Long.class, Boolean.class, new Coercion<Long, Boolean>()
-        {
-            public Boolean coerce(Long input)
-            {
-                return input.longValue() != 0;
-            }
-        });
-
-        add(configuration, void.class, Boolean.class, new Coercion<Void, Boolean>()
-        {
-            public Boolean coerce(Void input)
-            {
-                return false;
-            }
-        });
-
-        add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
-        {
-            public Boolean coerce(Collection input)
-            {
-                return !input.isEmpty();
-            }
-        });
-
-        add(configuration, Object.class, List.class, new Coercion<Object, List>()
-        {
-            public List coerce(Object input)
-            {
-                return Collections.singletonList(input);
-            }
-        });
-    }
-
-    private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
-            Class<T> targetType, Coercion<S, T> coercion)
-    {
-        CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion);
-
-        configuration.add(tuple);
-    }
-}
+package org.apache.tapestry.ioc.services;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.internal.ioc.services.ChainBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.DefaultImplementationBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.ExceptionAnalyzerImpl;
+import org.apache.tapestry.internal.ioc.services.ExceptionTrackerImpl;
+import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl;
+import org.apache.tapestry.internal.ioc.services.MasterObjectProvider;
+import org.apache.tapestry.internal.ioc.services.PerThreadServiceLifecycle;
+import org.apache.tapestry.internal.ioc.services.PipelineBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
+import org.apache.tapestry.internal.ioc.services.PropertyShadowBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.ServiceObjectProvider;
+import org.apache.tapestry.internal.ioc.services.StrategyBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.TypeCoercerImpl;
+import org.apache.tapestry.internal.services.ComponentInstantiatorSource;
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.ObjectProvider;
+import org.apache.tapestry.ioc.ServiceLifecycle;
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.InjectService;
+import org.apache.tapestry.ioc.annotations.Lifecycle;
+import org.apache.tapestry.util.StrategyRegistry;
+
+/**
+ * Defines the base set of services for the Tapestry IOC container.
+ */
+@Id("tapestry.ioc")
+public final class TapestryIOCModule
+{
+    private final ClassFactory _classFactory;
+
+    public TapestryIOCModule(@InjectService("ClassFactory")
+    ClassFactory classFactory)
+    {
+        _classFactory = classFactory;
+    }
+
+    /**
+     * The LoggingDecorator service is used to decorate a service implementation so that it logs
+     * method entry and exit (at level debug).
+     */
+    public LoggingDecorator buildLoggingDecorator(@InjectService("ExceptionTracker")
+    ExceptionTracker exceptionTracker)
+    {
+        return new LoggingDecoratorImpl(_classFactory, exceptionTracker);
+    }
+
+    /**
+     * Provides access to additional service lifecycles. Two lifecycles are built in ("singleton"
+     * and "primitive") but additional ones are accessed via this service (and its mapped
+     * configuration).
+     */
+    public static ServiceLifecycleSource buildServiceLifecycleSource(
+            final Map<String, ServiceLifecycle> configuration)
+    {
+        return new ServiceLifecycleSource()
+        {
+            public ServiceLifecycle get(String lifecycleName)
+            {
+                return configuration.get(lifecycleName);
+            }
+        };
+    }
+
+    /** Contributes the "perthread" service lifecycle. */
+    public void contributeServiceLifecycleSource(
+            MappedConfiguration<String, ServiceLifecycle> configuration,
+            @InjectService("ThreadCleanupHub")
+            ThreadCleanupHub threadCleanupHub)
+    {
+        configuration.add("perthread", new PerThreadServiceLifecycle(threadCleanupHub,
+                _classFactory));
+    }
+
+    /**
+     * A service that implements the chain of command pattern, creating an efficient implementation
+     * of a chain of command for an arbitrary interface.
+     */
+    public ChainBuilder buildChainBuilder()
+    {
+        return new ChainBuilderImpl(_classFactory);
+    }
+
+    /**
+     * A service that implements the strategy pattern, around a {@link StrategyRegistry}.
+     */
+    public StrategyBuilder buildStrategyBuilder()
+    {
+        return new StrategyBuilderImpl(_classFactory);
+    }
+
+    /**
+     * Services that provides read/write access to JavaBean properties. Encapsulates JavaBean
+     * introspection, including serializing access to the non-thread-safe Introspector object.
+     */
+    public static PropertyAccess buildPropertyAccess()
+    {
+        return new PropertyAccessImpl();
+    }
+
+    /**
+     * Builder that creates a shadow, a projection of a property of some other object.
+     */
+    public PropertyShadowBuilder buildPropertyShadowBuilder(@InjectService("PropertyAccess")
+    PropertyAccess propertyAccess)
+    {
+        return new PropertyShadowBuilderImpl(_classFactory, propertyAccess);
+    }
+
+    /**
+     * Builder that creates a filter pipeline around a simple service interface.
+     */
+    public PipelineBuilder buildPipelineBuilder(@InjectService("DefaultImplementationBuilder")
+    DefaultImplementationBuilder builder)
+    {
+        return new PipelineBuilderImpl(_classFactory, builder);
+    }
+
+    /**
+     * Builder that creates a default implementation of an interface.
+     */
+    public DefaultImplementationBuilder buildDefaultImplementationBuilder()
+    {
+        return new DefaultImplementationBuilderImpl(_classFactory);
+    }
+
+    /**
+     * The master {@link ObjectProvider} is responsible for identifying a particular ObjectProvider
+     * by its prefix, and delegating to that instance.
+     * 
+     * @param configuration
+     *            map of ObjectProviders, keyed on prefix
+     */
+    public static ObjectProvider buildMasterObjectProvider(Map<String, ObjectProvider> configuration)
+    {
+        return new MasterObjectProvider(configuration);
+    }
+
+    /**
+     * Contributes the "service:" object provider.
+     */
+    public static void contributeMasterObjectProvider(
+            MappedConfiguration<String, ObjectProvider> configuration)
+    {
+        configuration.add("service", new ServiceObjectProvider());
+    }
+
+    /** Used by the {@link org.apache.tapestry.ioc.services.LoggingDecorator} service. */
+    @Lifecycle("perthread")
+    public static ExceptionTracker buildExceptionTracker()
+    {
+        return new ExceptionTrackerImpl();
+    }
+
+    public static ExceptionAnalyzer buildExceptionAnalyzer(@InjectService("PropertyAccess")
+    PropertyAccess access)
+    {
+        return new ExceptionAnalyzerImpl(access);
+    }
+
+    /**
+     * Returns the service that can coerce between different types.
+     */
+    public static TypeCoercer buildTypeCoercer(Collection<CoercionTuple> configuration)
+    {
+        return new TypeCoercerImpl(configuration);
+    }
+
+    /**
+     * Contributes a set of standard type coercions:
+     * <ul>
+     * <li>Object to String</li>
+     * <li>String to Double</li>
+     * <li>String to BigDecimal</li>
+     * <li>BigDecimal to Double</li>
+     * <li>Double to BigDecimal</li>
+     * <li>String to BigInteger</li>
+     * <li>BigInteger to Long</li>
+     * <li>String to Long</li>
+     * <li>Long to Byte</li>
+     * <li>Long to Short</li>
+     * <li>Long to Integer</li>
+     * <li>Double to Long</li>
+     * <li>Double to Float</li>
+     * <li>Long to Double</li>
+     * <li>String to Boolean ("false" is always false, other non-blank strings are true)</li>
+     * <li>Long to Boolean (true if long value is non zero)</li>
+     * <li>Null to Boolean (always false)</li>
+     * <li>Collection to Boolean (false if empty)</li>
+     * <li>Object to List (by wrapping as a singleton list)</li>
+     * <li>Null to String (still null)</li>
+     * </ul>
+     * 
+     * @see #buildTypeCoercer(Collection, ComponentInstantiatorSource)
+     */
+
+    public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
+    {
+        add(configuration, Object.class, String.class, new Coercion<Object, String>()
+        {
+            public String coerce(Object input)
+            {
+                return input.toString();
+            }
+        });
+
+        add(configuration, void.class, String.class, new Coercion<Void, String>()
+        {
+
+            public String coerce(Void input)
+            {
+                return null;
+            }
+        });
+
+        add(configuration, String.class, Double.class, new Coercion<String, Double>()
+        {
+            public Double coerce(String input)
+            {
+                return new Double(input);
+            }
+        });
+
+        // String to BigDecimal is important, as String->Double->BigDecimal would lose
+        // precision.
+
+        add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
+        {
+            public BigDecimal coerce(String input)
+            {
+                return new BigDecimal(input);
+            }
+        });
+
+        add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
+        {
+            public Double coerce(BigDecimal input)
+            {
+                return input.doubleValue();
+            }
+        });
+
+        add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
+        {
+            public BigInteger coerce(String input)
+            {
+                return new BigInteger(input);
+            }
+        });
+
+        add(configuration, String.class, Long.class, new Coercion<String, Long>()
+        {
+            public Long coerce(String input)
+            {
+                return new Long(input);
+            }
+        });
+
+        add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
+        {
+            public Byte coerce(Long input)
+            {
+                return input.byteValue();
+            }
+        });
+
+        add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
+        {
+            public Short coerce(Long input)
+            {
+                return input.shortValue();
+            }
+        });
+
+        add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
+        {
+            public Integer coerce(Long input)
+            {
+                return input.intValue();
+            }
+        });
+
+        add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
+        {
+            public Long coerce(Number input)
+            {
+                return input.longValue();
+            }
+        });
+
+        add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
+        {
+            public Float coerce(Double input)
+            {
+                return input.floatValue();
+            }
+        });
+
+        add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
+        {
+            public Double coerce(Long input)
+            {
+                return input.doubleValue();
+            }
+        });
+
+        add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
+        {
+            public Boolean coerce(String input)
+            {
+                String trimmed = input.trim();
+
+                if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
+                    return false;
+
+                // Any non-blank string but "false"
+
+                return true;
+            }
+        });
+
+        add(configuration, Long.class, Boolean.class, new Coercion<Long, Boolean>()
+        {
+            public Boolean coerce(Long input)
+            {
+                return input.longValue() != 0;
+            }
+        });
+
+        add(configuration, void.class, Boolean.class, new Coercion<Void, Boolean>()
+        {
+            public Boolean coerce(Void input)
+            {
+                return false;
+            }
+        });
+
+        add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
+        {
+            public Boolean coerce(Collection input)
+            {
+                return !input.isEmpty();
+            }
+        });
+
+        add(configuration, Object.class, List.class, new Coercion<Object, List>()
+        {
+            public List coerce(Object input)
+            {
+                return Collections.singletonList(input);
+            }
+        });
+    }
+
+    private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
+            Class<T> targetType, Coercion<S, T> coercion)
+    {
+        CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion);
+
+        configuration.add(tuple);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/StrategyRegistry.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/StrategyRegistry.java?view=diff&rev=476585&r1=476584&r2=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/StrategyRegistry.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/StrategyRegistry.java Sat Nov 18 10:51:39 2006
@@ -64,7 +64,7 @@
         _cache.clear();
     }
 
-    public Class getAdapterType()
+    public Class<A> getAdapterType()
     {
         return _adapterType;
     }

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/strategy.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/strategy.apt?view=auto&rev=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/strategy.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/strategy.apt Sat Nov 18 10:51:39 2006
@@ -0,0 +1,53 @@
+ ----
+  Strategy Pattern
+ ----
+ 
+Strategy Pattern
+ 
+  Another of the Gang Of Four patterns, the strategy pattern as implemented in Tapestry IOC is a kind of late binding.
+  
+  The idea is that <adapters> for objects are accessed based on the <actual type> of an object.  These adapters supply additional functionality.  The adapters
+  are located using an {{{../apidocs/org/apache/tapestry/util/StrategyRegistry.html}StrategyRegistry}}.
+  
+  The lookup of adapters is based on an inheritance search; thus providing an adapter for type java.util.Map will match any object that implements the Map interface.
+  The inheritance search works its way up the class hierarchy looking for a matching registration. If nothing is found, then all the interfaces directly or indirectly
+  implemented by the selector class are checked. java.lang.Object is always the final match.
+  
+  A runtime exception is thrown if no match can be found. «
+  
+  As a special case, the value null is search for as if it was an instance of the class void.
+    
+  The {{{../apidocs/org/apache/tapestry/ioc/services/StrategyBuilder.html}tapestry.ioc.StrategyBuilder}} service creates a service implementation around a strategy registry.
+  
++---+
+public interface StrategyBuilder
+{
+    <S> S build(StrategyRegistry<S> registry);
+}
++---+  
+  
+  For a given interface (and matching   StrategyRegistry), a service implementation is created.  The service interface is determined from the
+  strategy registry.
+  
+  The first parameter of each method is the <selector>.  Its type is used to locate an adapter.
+  
+  The corresponding method of the adapter is then invoked, passing all parameters.
+  
+  Every method of the service interface should take at least one parameter.  Generally, such interfaces have only one or two methods.
+  
+Example
+
+  You will usually have a service configuration for defining the adapter registry.
+  
+  You conver the configuration into a StrategyRegistry, and use that to build the final service:
+  
++---+
+  public static MyStrategyService buildMyStrategyService(Map<Class, MyStrategyService> configuration,
+    @InjectService("tapestry.ioc.StrategyBuilder")
+    StrategyBuilder builder)
+  {
+     StategyRegistry<MyStrategyService> registry = StrategyRegistry.newInstance(MyStrategyService.class, configuration);
+  
+     return builder.build(registry);
+  }
++---+
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?view=diff&rev=476585&r1=476584&r2=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Sat Nov 18 10:51:39 2006
@@ -80,6 +80,7 @@
             <item name="Object Providers" href="ioc/provider.html"/>
             <item name="Ordering" href="ioc/order.html"/>
             <item name="Chain Of Command" href="ioc/command.html"/>
+            <item name="Strategy" href="ioc/strategy.html"/>
             <item name="Pipeline" href="ioc/pipeline.html"/>
             <item name="Shadow Services" href="ioc/shadow.html"/>
         </menu>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/KindOf.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/KindOf.java?view=auto&rev=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/KindOf.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/KindOf.java Sat Nov 18 10:51:39 2006
@@ -0,0 +1,21 @@
+// Copyright 2006 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.tapestry.internal.ioc.services;
+
+/** Converts an object to a string describing the kind of the object. */
+public interface KindOf
+{
+    String kindOf(Object value);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImplTest.java?view=auto&rev=476585
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/StrategyBuilderImplTest.java Sat Nov 18 10:51:39 2006
@@ -0,0 +1,87 @@
+// Copyright 2006 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.tapestry.internal.ioc.services;
+
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.services.StrategyBuilder;
+import org.apache.tapestry.util.StrategyRegistry;
+import org.testng.annotations.Test;
+
+public class StrategyBuilderImplTest extends InternalBaseTestCase
+{
+    private static class KindOfImpl implements KindOf
+    {
+        private final String _value;
+
+        public KindOfImpl(final String value)
+        {
+            _value = value;
+        }
+
+        public String kindOf(Object value)
+        {
+            return _value;
+        }
+
+    };
+
+    @Test
+    public void standard()
+    {
+        StrategyRegistry<KindOf> registry = buildStrategyRegistry();
+
+        StrategyBuilder builder = getService(StrategyBuilder.class);
+
+        KindOf service = builder.build(registry);
+
+        assertEquals(service.kindOf(Collections.EMPTY_MAP), "MAP");
+        assertEquals(service.kindOf(Collections.EMPTY_LIST), "LIST");
+
+        assertEquals(
+                service.toString(),
+                "<Strategy for org.apache.tapestry.internal.ioc.services.KindOf>");
+
+        try
+        {
+            service.kindOf(null);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "No adapter from type void to type org.apache.tapestry.internal.ioc.services.KindOf is available (registered types are java.util.List, java.util.Map).");
+        }
+    }
+
+    private StrategyRegistry<KindOf> buildStrategyRegistry()
+    {
+        Map<Class, KindOf> registrations = newMap();
+
+        registrations.put(Map.class, new KindOfImpl("MAP"));
+        registrations.put(List.class, new KindOfImpl("LIST"));
+
+        StrategyRegistry<KindOf> registry = StrategyRegistry.newInstance(
+                KindOf.class,
+                registrations);
+        return registry;
+    }
+}