Commit 01ca372
Changed files (26)
trunk
product
Gorilla.Commons.Infrastructure.ThirdParty
Gorilla.Commons.Utility
MyMoney
boot
container
registration
mapping
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/New/New.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq.Expressions;
+using Gorilla.Commons.Infrastructure.Castle.DynamicProxy;
+using Gorilla.Commons.Infrastructure.Container;
+using Gorilla.Commons.Utility;
+using Gorilla.Commons.Utility.Core;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace Gorilla.Commons.Infrastructure.New
+{
+ public interface IContainerBuilder : IBuilder<IDependencyRegistry>
+ {
+ IExtendedRegistration<T> register<T>(Expression<Func<T>> func) where T : class;
+ }
+
+ public interface IExtendedRegistration
+ {
+ string pretty_print { get; }
+ }
+
+ public interface IExtendedRegistration<T> : IExtendedRegistration where T: class
+ {
+ IExtendedRegistration<T> as_singleton();
+ IExtendedRegistration<T> with_expiry(string dateTime);
+ IExtendedRegistration<T> with_proxy(IConfiguration<IProxyBuilder<T>> configuration);
+ }
+
+ public class SimpleContainerBuilder : IContainerBuilder
+ {
+ IDictionary<Type, IExtendedRegistration> registries = new Dictionary<Type, IExtendedRegistration>();
+
+ public IDependencyRegistry build()
+ {
+ throw new NotImplementedException();
+ }
+
+ public IExtendedRegistration<T> register<T>(Expression<Func<T>> func) where T : class
+ {
+ try
+ {
+ var reg = new ExtendedRegistration<T>(func);
+ registries.Add(typeof (T), reg);
+ return reg;
+ }
+ catch (ArgumentException e)
+ {
+ throw new TypeAlreadyRegisteredInContainerException(typeof (T), registries[typeof (T)].pretty_print);
+ }
+ }
+ }
+
+ public class ExtendedRegistration<T> : IExtendedRegistration<T> where T : class
+ {
+ Func<T> func;
+ public const string time_format = "dd/MM/yyyy HH:mm:ss";
+
+ public ExtendedRegistration(Expression<Func<T>> expression)
+ {
+ pretty_print = expression.ToString();
+ func = expression.Compile();
+ }
+
+ public string pretty_print { get; set; }
+
+ public IExtendedRegistration<T> as_singleton()
+ {
+ func = func.memorize<T>();
+ return this;
+ }
+
+ public IExtendedRegistration<T> with_expiry(string dateTime)
+ {
+ var theDateTime = DateTime.ParseExact(dateTime, time_format, CultureInfo.InvariantCulture);
+ var original_func = func;
+
+ func = () =>
+ {
+ if (Clock.now() > theDateTime)
+ {
+ throw new ObjectUsageHasExpiredException(original_func().GetType(), dateTime);
+ }
+
+ return original_func();
+ };
+ return this;
+ }
+
+ public IExtendedRegistration<T> with_proxy(IConfiguration<IProxyBuilder<T>> configuration)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class TypeAlreadyRegisteredInContainerException : Exception
+ {
+ public TypeAlreadyRegisteredInContainerException(Type typeNotFound, string registration)
+ : base(build_message(typeNotFound, registration))
+ {
+ }
+
+ static string build_message(Type typeNotFound, string registration)
+ {
+ return string.Format("The type {0} has already been registered with {1} in the container",
+ typeNotFound.FullName, registration);
+ }
+ }
+
+ internal class ObjectUsageHasExpiredException : Exception
+ {
+ public ObjectUsageHasExpiredException(Type type, string dateTime) : base(build_message(type, dateTime))
+ {
+ }
+
+ static string build_message(Type type, string dateTime)
+ {
+ return string.Format("Cannot use {0} after {1}.", type.Name, dateTime);
+ }
+ }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Gorilla.Commons.Infrastructure.ThirdParty.csproj
@@ -131,6 +131,7 @@
<Compile Include="Castle\Windsor\WindsorContainerFactory.cs" />
<Compile Include="Castle\Windsor\WindsorDependencyRegistry.cs" />
<Compile Include="Castle\Windsor\WindsorDependencyRegistrySpecs.cs" />
+ <Compile Include="New\New.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Gorilla.Commons.Infrastructure\Gorilla.Commons.Infrastructure.csproj">
trunk/product/Gorilla.Commons.Utility/Core/Map.cs → trunk/product/Gorilla.Commons.Utility/Core/Mapper.cs
@@ -2,11 +2,11 @@ using System;
namespace Gorilla.Commons.Utility.Core
{
- public class Map<Input, Output> : IMapper<Input, Output>
+ public class Mapper<Input, Output> : IMapper<Input, Output>
{
private readonly Converter<Input, Output> converter;
- public Map(Converter<Input, Output> converter)
+ public Mapper(Converter<Input, Output> converter)
{
this.converter = converter;
}
trunk/product/Gorilla.Commons.Utility/Gorilla.Commons.Utility.csproj
@@ -88,7 +88,7 @@
<Compile Include="Core\IValueReturningVisitor.cs" />
<Compile Include="Core\IVisitable.cs" />
<Compile Include="Core\IVisitor.cs" />
- <Compile Include="Core\Map.cs" />
+ <Compile Include="Core\Mapper.cs" />
<Compile Include="Core\OrSpecification.cs" />
<Compile Include="Core\OrSpecificationSpecs.cs" />
<Compile Include="Core\PredicateSpecification.cs" />
trunk/product/MyMoney/boot/container/registration/mapping/DelegateTargetAction.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class DelegateTargetAction<Destination, Value> : ITargetAction<Destination, Value>
+ {
+ private readonly Action<Destination, Value> action;
+
+ public DelegateTargetAction(Action<Destination, Value> action)
+ {
+ this.action = action;
+ }
+
+ public void act_against(Destination destination, Value value)
+ {
+ action(destination, value);
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/ExpressionSourceEvaluator.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class ExpressionSourceEvaluator<Input, Result> : ISourceEvaluator<Input, Result>
+ {
+ private readonly Expression<Func<Input, Result>> original_expression;
+ private Func<Input, Result> evaluator_expression;
+
+ public ExpressionSourceEvaluator(Expression<Func<Input, Result>> original_expression)
+ {
+ this.original_expression = original_expression;
+ }
+
+ public Result evaluate_against(Input input)
+ {
+ initialize_evaluator();
+ return evaluator_expression(input);
+ }
+
+ private void initialize_evaluator()
+ {
+ if (evaluator_expression != null) return;
+ evaluator_expression = original_expression.Compile();
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/FuncInitializationStep.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class FuncInitializationStep<Destination> : IMapInitializationStep<Destination>
+ {
+ private readonly Func<Destination> func;
+
+ public FuncInitializationStep(Func<Destination> func)
+ {
+ this.func = func;
+ }
+
+ public Destination initialize()
+ {
+ return func();
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/IMap.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Linq.Expressions;
+using Gorilla.Commons.Utility.Core;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface IMap<Input, Output> : IMapper<Input, Output>
+ {
+ void add(IMappingStep<Input, Output> step);
+
+ IMap<Input, Output> map<PropertyType>(Expression<Func<Input, PropertyType>> from,
+ Expression<Func<Output, PropertyType>> to);
+
+ IMap<Input, Output> initialize_mapping_using(Func<Output> initializer_expression);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/IMapInitializationStep.cs
@@ -0,0 +1,7 @@
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface IMapInitializationStep<T>
+ {
+ T initialize();
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/IMappingStep.cs
@@ -0,0 +1,7 @@
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface IMappingStep<Source, Destination>
+ {
+ void map(Source source, Destination destination);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/IMappingStepFactory.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface IMappingStepFactory
+ {
+ IMappingStep<Source, Destination> create_mapping_step_for<Source, Destination, PropertyType>(
+ Expression<Func<Source, PropertyType>> source_expression,
+ Expression<Func<Destination, PropertyType>> destination_expression);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/ImmutablePropertyException.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Reflection;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class ImmutablePropertyException : Exception
+ {
+ public const string exception_message_format = "The property [{0}] on the target type [{1}] is immutable";
+
+ public ImmutablePropertyException(Type target, PropertyInfo property)
+ : base(exception_message_format.formatted_using(property.Name, target.Name))
+
+ {
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/IPropertyResolver.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface IPropertyResolver
+ {
+ PropertyInfo resolve_using<Input, PropertyType>(Expression<Func<Input, PropertyType>> expression);
+ PropertyInfo resolve_using(Type type, string property_name);
+ IEnumerable<PropertyInfo> all_properties_belonging_to(Type type);
+ IEnumerable<PropertyInfo> all_properties_belonging_to<T>();
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/ISourceEvaluator.cs
@@ -0,0 +1,7 @@
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface ISourceEvaluator<Source, Result>
+ {
+ Result evaluate_against(Source source);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/ITargetAction.cs
@@ -0,0 +1,7 @@
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface ITargetAction<Target, ValueType>
+ {
+ void act_against(Target destination, ValueType value);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/ITargetActionFactory.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public interface ITargetActionFactory
+ {
+ ITargetAction<Target, ValueType> create_action_target_from<Target, ValueType>(
+ Expression<Func<Target, ValueType>> target_expression);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/Map.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class Map<Input, Output> : IMap<Input, Output>
+ {
+ private IMapInitializationStep<Output> map_initialization_step;
+ private readonly IList<IMappingStep<Input, Output>> mapping_steps;
+ private readonly IMappingStepFactory mapping_step_factory;
+
+ public Map() : this(new MappingStepFactory())
+ {
+ }
+
+ public Map(IMappingStepFactory mapping_step_factory)
+ : this(
+ new MissingInitializationStep<Output>(), new List<IMappingStep<Input, Output>>(), mapping_step_factory)
+ {
+ }
+
+ public Map(IMapInitializationStep<Output> map_initialization_step,
+ IList<IMappingStep<Input, Output>> mapping_steps, IMappingStepFactory mapping_step_factory)
+ {
+ this.map_initialization_step = map_initialization_step;
+ this.mapping_steps = mapping_steps;
+ this.mapping_step_factory = mapping_step_factory;
+ }
+
+ public void add(IMappingStep<Input, Output> step)
+ {
+ mapping_steps.Add(step);
+ }
+
+ public IMap<Input, Output> map<PropertyType>(Expression<Func<Input, PropertyType>> from,
+ Expression<Func<Output, PropertyType>> to)
+ {
+ add(mapping_step_factory.create_mapping_step_for(from, to));
+ return this;
+ }
+
+ public IMap<Input, Output> initialize_mapping_using(Func<Output> initializer_expression)
+ {
+ map_initialization_step = new FuncInitializationStep<Output>(initializer_expression);
+ return this;
+ }
+
+ public Output map_from(Input input)
+ {
+ var output = map_initialization_step.initialize();
+ mapping_steps.each(x => x.map(input, output));
+ return output;
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/Mappers.cs
@@ -0,0 +1,16 @@
+using Gorilla.Commons.Utility.Core;
+using MoMoney.Domain.Accounting;
+using MoMoney.DTO;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class Mappers
+ {
+ static public IMapper<IBill, BillInformationDTO> bill_mapper =
+ new Map<IBill, BillInformationDTO>()
+ .initialize_mapping_using(() => new BillInformationDTO())
+ .map(x => x.company_to_pay.name, y => y.company_name)
+ .map(x => x.the_amount_owed.ToString(), y => y.the_amount_owed)
+ .map(x => x.due_date.to_date_time(), y => y.due_date);
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/MappingStep.cs
@@ -0,0 +1,20 @@
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class MappingStep<Input, Output, Type> : IMappingStep<Input, Output>
+ {
+ private readonly ISourceEvaluator<Input, Type> input_evaluator;
+ private readonly ITargetAction<Output, Type> action_to_run_against_destination;
+
+ public MappingStep(ISourceEvaluator<Input, Type> source_evaluator, ITargetAction<Output, Type> target_action)
+ {
+ input_evaluator = source_evaluator;
+ action_to_run_against_destination = target_action;
+ }
+
+ public void map(Input input, Output destination)
+ {
+ var value_pulled_from_input_item = input_evaluator.evaluate_against(input);
+ action_to_run_against_destination.act_against(destination, value_pulled_from_input_item);
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/MappingStepFactory.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class MappingStepFactory : IMappingStepFactory
+ {
+ private readonly ITargetActionFactory target_action_factory;
+
+ public MappingStepFactory() : this(new TargetActionFactory())
+ {
+ }
+
+ public MappingStepFactory(ITargetActionFactory target_action_factory)
+ {
+ this.target_action_factory = target_action_factory;
+ }
+
+ public IMappingStep<Source, Destination> create_mapping_step_for<Source, Destination, PropertyType>(
+ Expression<Func<Source, PropertyType>> source_expression,
+ Expression<Func<Destination, PropertyType>> destination_expression)
+ {
+ var source_evaluator = new ExpressionSourceEvaluator<Source, PropertyType>(source_expression);
+
+ var target_action = target_action_factory.create_action_target_from(destination_expression);
+
+ return new MappingStep<Source, Destination, PropertyType>(source_evaluator, target_action);
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/MissingInitializationStep.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class MissingInitializationStep<Output> : IMapInitializationStep<Output>
+ {
+ public Output initialize()
+ {
+ throw new ArgumentException("A map must be provided an initialization step before it can be used to map");
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/PropertyResolutionException.cs
@@ -0,0 +1,19 @@
+using System;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class PropertyResolutionException : Exception
+ {
+ public const string exception_message_format = "Failed to find the property named {0} on type {1}";
+
+ public PropertyResolutionException(Type type_that_did_not_have_the_property,
+ string property_that_could_not_be_found)
+ : base(
+ exception_message_format.formatted_using(property_that_could_not_be_found,
+ type_that_did_not_have_the_property.Name))
+
+ {
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/PropertyResolver.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class PropertyResolver : IPropertyResolver
+ {
+ private BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.FlattenHierarchy;
+
+ public PropertyInfo resolve_using<Input, PropertyType>(Expression<Func<Input, PropertyType>> expression)
+ {
+ var member_accessor = (MemberExpression) expression.Body;
+ return resolve_using(typeof (Input), member_accessor.Member.Name);
+ }
+
+ public PropertyInfo resolve_using(Type type, string property_name)
+ {
+ var property = all_properties_belonging_to(type).Where(x => x.Name.Equals(property_name)).FirstOrDefault();
+
+ if (property == null) throw new PropertyResolutionException(type, property_name);
+
+ return property;
+ }
+
+ public IEnumerable<PropertyInfo> all_properties_belonging_to(Type type)
+ {
+ var stack = new Stack<Type>();
+ stack.Push(type);
+
+ while (stack.Count > 0)
+ {
+ var type_to_interrogate = stack.Pop();
+
+ type_to_interrogate.GetInterfaces().each(stack.Push);
+ foreach (var a_property in all_properties_for(type_to_interrogate))
+ {
+ yield return a_property;
+ }
+ }
+ }
+
+ public IEnumerable<PropertyInfo> all_properties_belonging_to<T>()
+ {
+ return all_properties_belonging_to(typeof (T));
+ }
+
+ private PropertyInfo[] all_properties_for(Type type)
+ {
+ return type.GetProperties(flags);
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/mapping/TargetActionFactory.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MoMoney.boot.container.registration.mapping
+{
+ public class TargetActionFactory : ITargetActionFactory
+ {
+ private readonly IPropertyResolver property_resolver;
+
+ public TargetActionFactory(IPropertyResolver property_resolver)
+ {
+ this.property_resolver = property_resolver;
+ }
+
+ public TargetActionFactory() : this(new PropertyResolver())
+ {
+ }
+
+ public ITargetAction<Target, ValueType> create_action_target_from<Target, ValueType>(
+ Expression<Func<Target, ValueType>> target_expression)
+ {
+ var property = property_resolver.resolve_using(target_expression);
+ if (property.CanWrite)
+ return new DelegateTargetAction<Target, ValueType>((x, y) => property.SetValue(x, y, new object[0]));
+
+ throw new ImmutablePropertyException(typeof (Target), property);
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/wire_up_the_mappers_in_to_the.cs
@@ -18,7 +18,7 @@ namespace MoMoney.boot.container.registration
public void run()
{
- registry.transient(typeof (IMapper<,>), typeof (Map<,>));
+ registry.transient(typeof (IMapper<,>), typeof (Mapper<,>));
registry.singleton<Converter<IBill, BillInformationDTO>>(
() => x => new BillInformationDTO
{
trunk/product/MyMoney/MyMoney.csproj
@@ -167,6 +167,26 @@
<Compile Include="boot\container\registration\auto_wire_components_in_to_the.cs" />
<Compile Include="boot\container\registration\auto_wire_components_in_to_the_specs.cs" />
<Compile Include="boot\container\registration\IStartupCommand.cs" />
+ <Compile Include="boot\container\registration\mapping\Mappers.cs" />
+ <Compile Include="boot\container\registration\mapping\DelegateTargetAction.cs" />
+ <Compile Include="boot\container\registration\mapping\ExpressionSourceEvaluator.cs" />
+ <Compile Include="boot\container\registration\mapping\FuncInitializationStep.cs" />
+ <Compile Include="boot\container\registration\mapping\IMap.cs" />
+ <Compile Include="boot\container\registration\mapping\IMapInitializationStep.cs" />
+ <Compile Include="boot\container\registration\mapping\IMappingStep.cs" />
+ <Compile Include="boot\container\registration\mapping\IMappingStepFactory.cs" />
+ <Compile Include="boot\container\registration\mapping\ImmutablePropertyException.cs" />
+ <Compile Include="boot\container\registration\mapping\IPropertyResolver.cs" />
+ <Compile Include="boot\container\registration\mapping\ISourceEvaluator.cs" />
+ <Compile Include="boot\container\registration\mapping\ITargetAction.cs" />
+ <Compile Include="boot\container\registration\mapping\ITargetActionFactory.cs" />
+ <Compile Include="boot\container\registration\mapping\Map.cs" />
+ <Compile Include="boot\container\registration\mapping\MappingStep.cs" />
+ <Compile Include="boot\container\registration\mapping\MappingStepFactory.cs" />
+ <Compile Include="boot\container\registration\mapping\MissingInitializationStep.cs" />
+ <Compile Include="boot\container\registration\mapping\PropertyResolutionException.cs" />
+ <Compile Include="boot\container\registration\mapping\PropertyResolver.cs" />
+ <Compile Include="boot\container\registration\mapping\TargetActionFactory.cs" />
<Compile Include="boot\container\registration\proxy_configuration\NoConfiguration.cs" />
<Compile Include="boot\container\registration\proxy_configuration\ServiceLayerConfiguration.cs" />
<Compile Include="boot\container\registration\proxy_configuration\SynchronizedConfiguration.cs" />