From: <fab...@us...> - 2009-06-12 15:34:45
|
Revision: 4458 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4458&view=rev Author: fabiomaulo Date: 2009-06-12 15:34:31 +0000 (Fri, 12 Jun 2009) Log Message: ----------- Fix NH-1623 Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Bytecode/AbstractBytecodeProvider.cs trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs trunk/nhibernate/src/NHibernate/Cfg/Environment.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/BytecodeProviderFixture.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Bytecode/IInjectableCollectionTypeFactoryClass.cs trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/ProductLine.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Bytecode/AbstractBytecodeProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Bytecode/AbstractBytecodeProvider.cs 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate/Bytecode/AbstractBytecodeProvider.cs 2009-06-12 15:34:31 UTC (rev 4458) @@ -4,11 +4,12 @@ namespace NHibernate.Bytecode { - public abstract class AbstractBytecodeProvider : IBytecodeProvider, IInjectableProxyFactoryFactory + public abstract class AbstractBytecodeProvider : IBytecodeProvider, IInjectableProxyFactoryFactory, IInjectableCollectionTypeFactoryClass { private readonly IObjectsFactory objectsFactory = new ActivatorObjectsFactory(); protected System.Type proxyFactoryFactory; private ICollectionTypeFactory collectionTypeFactory; + private System.Type collectionTypeFactoryClass = typeof(Type.DefaultCollectionTypeFactory); #region IBytecodeProvider Members @@ -39,7 +40,7 @@ get { return objectsFactory; } } - public ICollectionTypeFactory CollectionTypeFactory + public virtual ICollectionTypeFactory CollectionTypeFactory { get { @@ -48,7 +49,7 @@ try { collectionTypeFactory = - (ICollectionTypeFactory) ObjectsFactory.CreateInstance(typeof (Type.DefaultCollectionTypeFactory)); + (ICollectionTypeFactory) ObjectsFactory.CreateInstance(collectionTypeFactoryClass); } catch (Exception e) { @@ -57,14 +58,6 @@ } return collectionTypeFactory; } - protected set - { - if(value == null) - { - throw new InvalidOperationException("The CollectionTypeFactory can't be null."); - } - collectionTypeFactory = value; - } } #endregion @@ -92,5 +85,36 @@ } #endregion + + #region Implementation of IInjectableCollectionTypeFactoryClass + + public void SetCollectionTypeFactoryClass(string typeAssemblyQualifiedName) + { + if (string.IsNullOrEmpty(typeAssemblyQualifiedName)) + { + throw new ArgumentNullException("typeAssemblyQualifiedName"); + } + System.Type ctf= ReflectHelper.ClassForName(typeAssemblyQualifiedName); + SetCollectionTypeFactoryClass(ctf); + } + + public void SetCollectionTypeFactoryClass(System.Type type) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + if (typeof(ICollectionTypeFactory).IsAssignableFrom(type) == false) + { + throw new HibernateByteCodeException(type.FullName + " does not implement " + typeof(ICollectionTypeFactory).FullName); + } + if (collectionTypeFactory != null) + { + throw new InvalidOperationException("CollectionTypeFactory in use, can't change it."); + } + collectionTypeFactoryClass = type; + } + + #endregion } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Bytecode/IInjectableCollectionTypeFactoryClass.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Bytecode/IInjectableCollectionTypeFactoryClass.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Bytecode/IInjectableCollectionTypeFactoryClass.cs 2009-06-12 15:34:31 UTC (rev 4458) @@ -0,0 +1,8 @@ +namespace NHibernate.Bytecode +{ + public interface IInjectableCollectionTypeFactoryClass + { + void SetCollectionTypeFactoryClass(string typeAssemblyQualifiedName); + void SetCollectionTypeFactoryClass(System.Type type); + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2009-06-12 15:34:31 UTC (rev 4458) @@ -55,6 +55,7 @@ public const string DefaultHibernateCfgFileName = "hibernate.cfg.xml"; private string currentDocumentName; + private bool preMappingBuildProcessed; protected IDictionary<string, PersistentClass> classes; // entityName, PersistentClass protected IDictionary<string, NHibernate.Mapping.Collection> collections; @@ -523,12 +524,38 @@ /// </summary> public Mappings CreateMappings(Dialect.Dialect dialect) { + ProcessPreMappingBuildProperties(); return new Mappings(classes, collections, tables, NamedQueries, NamedSQLQueries, SqlResultSetMappings, Imports, secondPasses, propertyReferences, namingStrategy, typeDefs, FilterDefinitions, extendsQueue, auxiliaryDatabaseObjects, tableNameBinding, columnNameBindingPerTable, defaultAssembly, defaultNamespace, dialect); } + private void ProcessPreMappingBuildProperties() + { + if(preMappingBuildProcessed) + { + return; + } + ConfigureCollectionTypeFactory(); + preMappingBuildProcessed = true; + } + + private void ConfigureCollectionTypeFactory() + { + var ctfc = GetProperty(Environment.CollectionTypeFactoryClass); + if(string.IsNullOrEmpty(ctfc)) + { + return; + } + var ictfc = Environment.BytecodeProvider as IInjectableCollectionTypeFactoryClass; + if(ictfc == null) + { + return; + } + ictfc.SetCollectionTypeFactoryClass(ctfc); + } + /// <summary> /// Read mappings from a <see cref="Stream" />. /// </summary> Modified: trunk/nhibernate/src/NHibernate/Cfg/Environment.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Environment.cs 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate/Cfg/Environment.cs 2009-06-12 15:34:31 UTC (rev 4458) @@ -158,6 +158,8 @@ public const string DefaultBatchFetchSize = "default_batch_fetch_size"; + public const string CollectionTypeFactoryClass = "collectiontype.factory_class"; + private static readonly Dictionary<string, string> GlobalProperties; private static IBytecodeProvider BytecodeProviderInstance; Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-06-12 15:34:31 UTC (rev 4458) @@ -451,6 +451,7 @@ <Compile Include="Bytecode\AbstractBytecodeProvider.cs" /> <Compile Include="Bytecode\ActivatorObjectsFactory.cs" /> <Compile Include="Bytecode\HibernateByteCodeException.cs" /> + <Compile Include="Bytecode\IInjectableCollectionTypeFactoryClass.cs" /> <Compile Include="Bytecode\IObjectsFactory.cs" /> <Compile Include="Bytecode\ProxyFactoryFactoryNotConfiguredException.cs" /> <Compile Include="Bytecode\UnableToLoadProxyFactoryFactoryException.cs" /> Modified: trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd =================================================================== --- trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd 2009-06-12 15:34:31 UTC (rev 4458) @@ -102,6 +102,7 @@ <xs:enumeration value="default_entity_mode" /> <xs:enumeration value="use_sql_comments" /> <xs:enumeration value="format_sql" /> + <xs:enumeration value="collectiontype.factory_class" /> </xs:restriction> </xs:simpleType> </xs:attribute> Modified: trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/BytecodeProviderFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/BytecodeProviderFixture.cs 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/BytecodeProviderFixture.cs 2009-06-12 15:34:31 UTC (rev 4458) @@ -1,6 +1,8 @@ +using System; using NHibernate.Bytecode; using NHibernate.Bytecode.Lightweight; using NUnit.Framework; +using Environment=NHibernate.Cfg.Environment; namespace NHibernate.Test.Bytecode.Lightweight { @@ -71,5 +73,85 @@ Assert.That(e.Message,Text.StartsWith("Failed to create an instance of")); } } + + [Test] + public void NotConfiguredCollectionTypeFactory() + { + // our BytecodeProvider should ever have a CollectionTypeFactory + var bcp = new BytecodeProviderImpl(); + Assert.That(bcp.CollectionTypeFactory, Is.Not.Null); + } + + [Test] + public void SetCollectionTypeFactoryClassByName() + { + string nullName = null; + var bcp = new BytecodeProviderImpl(); + + Assert.Throws<ArgumentNullException>(() => bcp.SetCollectionTypeFactoryClass(nullName)); + Assert.Throws<ArgumentNullException>(() => bcp.SetCollectionTypeFactoryClass(string.Empty)); + Assert.Throws<TypeLoadException>(() => bcp.SetCollectionTypeFactoryClass("whatever")); + } + + [Test] + public void SetCollectionTypeFactoryClassByType() + { + System.Type nullType = null; + var bcp = new BytecodeProviderImpl(); + Assert.Throws<ArgumentNullException>(() => bcp.SetCollectionTypeFactoryClass(nullType)); + Assert.Throws<HibernateByteCodeException>(() => bcp.SetCollectionTypeFactoryClass(GetType()), "should allow only ICollectionTypeFactory type"); + } + + private class NoDefaultCtor: Type.DefaultCollectionTypeFactory + { + public NoDefaultCtor(int something) {} + } + + [Test] + public void InvalidCollectionTypeFactoryCtor() + { + ICollectionTypeFactory ctf; + var bcp = new BytecodeProviderImpl(); + bcp.SetCollectionTypeFactoryClass(typeof (NoDefaultCtor)); + Assert.Throws<HibernateByteCodeException>(() => ctf = bcp.CollectionTypeFactory); + } + + [Test] + public void CollectionTypeFactoryCantChangeAfterUsage() + { + ICollectionTypeFactory ctf; + var bcp = new BytecodeProviderImpl(); + ctf = bcp.CollectionTypeFactory; // initialize the instance + // try to set it + Assert.Throws<InvalidOperationException>(() => bcp.SetCollectionTypeFactoryClass(typeof(Type.DefaultCollectionTypeFactory))); + } + + private class CustomCollectionTypeFactory : Type.DefaultCollectionTypeFactory + { + } + + [Test] + [Explicit("The BytecodeProvider is static and can't be different in the same application.")] + public void AllowCustomCollectionTypeFactoryBeforeBuildFirstMapping() + { + // Allow set of CustomCollectionTypeFactory class after configure BUT before add the first mapping. + // for real we need CustomCollectionTypeFactory before BuildSessionFactory but for possible future + // "mapping-sources" is better to limitate the moment of injectability. + var cfg = TestConfigurationHelper.GetDefaultConfiguration(); + cfg.SetProperty(Environment.CollectionTypeFactoryClass, typeof(CustomCollectionTypeFactory).AssemblyQualifiedName); + Dialect.Dialect dialect = Dialect.Dialect.GetDialect(cfg.Properties); + cfg.CreateMappings(dialect); + Assert.That(Environment.BytecodeProvider.CollectionTypeFactory, Is.TypeOf<CustomCollectionTypeFactory>()); + } + + [Test] + [Explicit("The BytecodeProvider is static and can't be different in the same application.")] + public void WorkAddingMappings() + { + var cfg = TestConfigurationHelper.GetDefaultConfiguration(); + cfg.SetProperty(Environment.CollectionTypeFactoryClass, typeof(CustomCollectionTypeFactory).AssemblyQualifiedName); + cfg.AddResource("NHibernate.Test.Bytecode.Lightweight.ProductLine.hbm.xml", GetType().Assembly); + Assert.That(Environment.BytecodeProvider.CollectionTypeFactory, Is.TypeOf<CustomCollectionTypeFactory>()); + } } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/ProductLine.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/ProductLine.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Bytecode/Lightweight/ProductLine.hbm.xml 2009-06-12 15:34:31 UTC (rev 4458) @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> + + <class entity-name="ProductLine"> + <id name="Id" type="int"> + <generator class="hilo"/> + </id> + <property name="Description" not-null="true" length="200" type="string"/> + + <bag name="Models" cascade="all" inverse="true"> + <key column="productId"/> + <one-to-many class="Model"/> + </bag> + + </class> + + <class entity-name="Model"> + <id name="Id" type="int"> + <generator class="hilo"/> + </id> + + <property name="Name" not-null="true" length="25" type="string"/> + <property name="Description" not-null="true" length="200" type="string"/> + <many-to-one name="ProductLine" column="productId" not-null="true" class="ProductLine"/> + </class> + +</hibernate-mapping> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-06-11 21:49:52 UTC (rev 4457) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-06-12 15:34:31 UTC (rev 4458) @@ -1901,6 +1901,7 @@ <EmbeddedResource Include="Ado\AlmostSimple.hbm.xml" /> <EmbeddedResource Include="CacheTest\EntityWithFilters.xml" /> <EmbeddedResource Include="Classic\EntityWithLifecycle.hbm.xml" /> + <EmbeddedResource Include="Bytecode\Lightweight\ProductLine.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> <EmbeddedResource Include="NHSpecificTest\NH1821\Mappings.hbm.xml" /> <EmbeddedResource Include="TypeParameters\EntityCustomId.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |