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;
+ }
+}