From: Michael D. <mik...@us...> - 2004-10-05 15:27:12
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26229/src/NHibernate/Proxy Modified Files: Tag: alpha_avalon-proxy AvalonLazyInitializer.cs AvalonProxyDeserializer.cs AvalonProxyGenerator.cs IProxyGenerator.cs LazyInitializer.cs NHibernateProxyHelper.cs ProxyGeneratorFactory.cs Added Files: Tag: alpha_avalon-proxy AvalonCustomProxyGenerator.cs Log Message: much work done to implement proxies with classes and virtual properties. All test that are being run now pass with proxy="some class" Index: NHibernateProxyHelper.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/Attic/NHibernateProxyHelper.cs,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** NHibernateProxyHelper.cs 27 Sep 2004 03:42:03 -0000 1.1.2.1 --- NHibernateProxyHelper.cs 5 Oct 2004 15:25:05 -0000 1.1.2.2 *************** *** 22,30 **** public static LazyInitializer GetLazyInitializer(INHibernateProxy proxy) { ! // have to hard code in "handler" - very dependant on them not changing their ! // implementation - email Hammet about this - or atleast to provide a static ! // field ! object fieldValue = proxy.GetType().GetField( "handler" ).GetValue(proxy); ! return (LazyInitializer)fieldValue; } --- 22,28 ---- public static LazyInitializer GetLazyInitializer(INHibernateProxy proxy) { ! LazyInitializer li = ProxyGeneratorFactory.GetProxyGenerator().GetLazyInitializer( proxy ); ! return li; ! } *************** *** 40,44 **** { INHibernateProxy proxy = (INHibernateProxy) obj; ! LazyInitializer li = GetLazyInitializer(proxy); return li.PersistentClass; } --- 38,42 ---- { INHibernateProxy proxy = (INHibernateProxy) obj; ! LazyInitializer li = NHibernateProxyHelper.GetLazyInitializer( proxy ); return li.PersistentClass; } Index: AvalonProxyGenerator.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/Attic/AvalonProxyGenerator.cs,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -C2 -d -r1.1.2.2 -r1.1.2.3 *** AvalonProxyGenerator.cs 3 Oct 2004 16:58:13 -0000 1.1.2.2 --- AvalonProxyGenerator.cs 5 Oct 2004 15:25:05 -0000 1.1.2.3 *************** *** 19,25 **** private static readonly log4net.ILog log = log4net.LogManager.GetLogger( typeof(AvalonProxyGenerator) ); ! private ProxyGenerator _generator; ! private DefaultProxyBuilder _defaultBuilder; private GeneratorContext _context; /// <summary> --- 19,28 ---- private static readonly log4net.ILog log = log4net.LogManager.GetLogger( typeof(AvalonProxyGenerator) ); ! // key = mapped type ! // value = proxy type ! private IDictionary cachedProxyTypes; ! private GeneratorContext _context; + private ModuleScope _scope; /// <summary> *************** *** 28,41 **** internal AvalonProxyGenerator() { ! _defaultBuilder = new DefaultProxyBuilder( ); // the EnhanceTypeDelegate will add custom code gen that DynamicProxy does not provide // by default. _context = new GeneratorContext( new EnhanceTypeDelegate( EnhanceInterfaceType ), null ); - - // only create the genator once so I should be okay with the DefaultProxyBuilder - // maintaining the ModuleScope - _generator = new ProxyGenerator(); - } --- 31,41 ---- internal AvalonProxyGenerator() { ! cachedProxyTypes = new Hashtable(); ! ! _scope = new ModuleScope(); // the EnhanceTypeDelegate will add custom code gen that DynamicProxy does not provide // by default. _context = new GeneratorContext( new EnhanceTypeDelegate( EnhanceInterfaceType ), null ); } *************** *** 53,59 **** private void EnhanceInterfaceType(TypeBuilder mainType, FieldBuilder handlerFieldBuilder, ConstructorBuilder constructorBuilder) { ! ConstructorInfo serAttConstructor = typeof(SerializableAttribute).GetConstructor( new System.Type[0] ); ! CustomAttributeBuilder serializableAttBuilder = new CustomAttributeBuilder( serAttConstructor, new object[0] ); ! mainType.SetCustomAttribute( serializableAttBuilder ); } --- 53,66 ---- private void EnhanceInterfaceType(TypeBuilder mainType, FieldBuilder handlerFieldBuilder, ConstructorBuilder constructorBuilder) { ! bool isSerializableAttFound = false; ! System.Type baseType = mainType.BaseType; ! ! // I don't know why I can't find the [Serializable] on the generated type ! if( isSerializableAttFound==false ) ! { ! ConstructorInfo serAttConstructor = typeof(SerializableAttribute).GetConstructor( new System.Type[0] ); ! CustomAttributeBuilder serializableAttBuilder = new CustomAttributeBuilder( serAttConstructor, new object[0] ); ! mainType.SetCustomAttribute( serializableAttBuilder ); ! } } *************** *** 69,91 **** /// <param name="session">The Session the proxy is in.</param> /// <returns>A fully built <c>INHibernateProxy</c>.</returns> ! public INHibernateProxy GetProxy(System.Type persistentClass, System.Type[] interfaces, PropertyInfo identifierPropertyInfo, object id, ISessionImplementor session) { try { ! AvalonLazyInitializer initializer = new AvalonLazyInitializer( persistentClass, interfaces, id, identifierPropertyInfo, session ); ! // if the pc is an interface then we need to add the interface to the ! // interfaces array that was passed in because it only includes the extra ! // interfaces for that persistent class. ! if( persistentClass.IsInterface ) { ! System.Type[] temp = new System.Type[ interfaces.Length + 1 ]; ! interfaces.CopyTo( temp, 0 ); ! temp[ interfaces.Length ] = persistentClass; ! interfaces = temp; ! } ! System.Type proxyType = _defaultBuilder.CreateCustomInterfaceProxy( interfaces, _context ); object generatedProxy = Activator.CreateInstance( proxyType, new object[] { initializer } ); return (INHibernateProxy)generatedProxy; --- 76,123 ---- /// <param name="session">The Session the proxy is in.</param> /// <returns>A fully built <c>INHibernateProxy</c>.</returns> ! public INHibernateProxy GetProxy(System.Type persistentClass, System.Type concreteProxy, System.Type[] interfaces, PropertyInfo identifierPropertyInfo, object id, ISessionImplementor session) { try { ! AvalonLazyInitializer initializer = new AvalonLazyInitializer( persistentClass, concreteProxy, interfaces, id, identifierPropertyInfo, session ); ! System.Type proxyType = null; ! // if I try to generate a proxy twice for the same type the Avalon library will do the same ! // in one ModuleBuilder. The ModuleBuilder throws an exception (not suprisingly) when you try ! // to define the same type twice in it. So nh needs to keep a cache of the proxy types that have ! // already been generated. ! lock( cachedProxyTypes.SyncRoot ) { ! proxyType = cachedProxyTypes[ concreteProxy ] as System.Type; ! if( proxyType==null ) ! { ! // if the pc is an interface then we need to add the interface to the ! // interfaces array that was passed in because it only includes the extra ! // interfaces for that persistent class. ! //if( persistentClass.IsInterface ) ! if( concreteProxy.IsInterface ) ! { ! //TODO: figure out if this is necessary because the concreteProxy is ! // already included in the interfaces array... ! System.Type[] temp = new System.Type[ interfaces.Length + 1 ]; ! interfaces.CopyTo( temp, 0 ); ! temp[ interfaces.Length ] = concreteProxy; //persistentClass; ! interfaces = temp; ! ! InterfaceProxyGenerator _interfaceGenerator = new InterfaceProxyGenerator( _scope, _context ); ! proxyType = _interfaceGenerator.GenerateCode( interfaces ); ! ! } ! else ! { ! AvalonCustomProxyGenerator _classGenerator = new AvalonCustomProxyGenerator( _scope, _context ); ! proxyType = _classGenerator.GenerateCode( concreteProxy ); ! } ! ! cachedProxyTypes[ concreteProxy ] = proxyType; ! } ! } object generatedProxy = Activator.CreateInstance( proxyType, new object[] { initializer } ); return (INHibernateProxy)generatedProxy; *************** *** 99,102 **** --- 131,168 ---- } + /// <summary> + /// Gets the <see cref="LazyInitializer"/> that is used by the Proxy. + /// </summary> + /// <param name="proxy">The Proxy object</param> + /// <returns>The <see cref="LazyInitializer"/> that contains the details of the Proxied object.</returns> + public LazyInitializer GetLazyInitializer(INHibernateProxy proxy) + { + // have to hard code in "handler" - very dependant on them not changing their + // implementation - email Hammet about this - or atleast to provide a static + // field + object fieldValue = proxy.GetType().GetField( "handler" ).GetValue( proxy ); + return (LazyInitializer)fieldValue; + } + + /// <summary> + /// Convenience method to figure out the underlying type for the object regardless of it + /// is a Proxied object or the real object. + /// </summary> + /// <param name="obj">The object to get the type of.</param> + /// <returns>The Underlying Type for the object regardless of if it is a Proxy.</returns> + public System.Type GetClass(object obj) + { + if (obj is INHibernateProxy) + { + INHibernateProxy proxy = (INHibernateProxy) obj; + LazyInitializer li = GetLazyInitializer( proxy ); + return li.PersistentClass; + } + else + { + return obj.GetType(); + } + } + #endregion } Index: IProxyGenerator.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/Attic/IProxyGenerator.cs,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -C2 -d -r1.1.2.2 -r1.1.2.3 *** IProxyGenerator.cs 3 Oct 2004 16:58:13 -0000 1.1.2.2 --- IProxyGenerator.cs 5 Oct 2004 15:25:05 -0000 1.1.2.3 *************** *** 21,25 **** /// <param name="session">The Session the proxy is in.</param> /// <returns>A fully built <c>INHibernateProxy</c>.</returns> ! INHibernateProxy GetProxy(System.Type persistentClass, System.Type[] interfaces, PropertyInfo identifierPropertyInfo, object id, ISessionImplementor session); } } --- 21,40 ---- /// <param name="session">The Session the proxy is in.</param> /// <returns>A fully built <c>INHibernateProxy</c>.</returns> ! INHibernateProxy GetProxy(System.Type persistentClass, System.Type concreteProxy, System.Type[] interfaces, PropertyInfo identifierPropertyInfo, object id, ISessionImplementor session); ! ! /// <summary> ! /// Gets the <see cref="LazyInitializer"/> that is used by the Proxy. ! /// </summary> ! /// <param name="proxy">The Proxy object</param> ! /// <returns>The <see cref="LazyInitializer"/> that contains the details of the Proxied object.</returns> ! LazyInitializer GetLazyInitializer(INHibernateProxy proxy); ! ! /// <summary> ! /// Convenience method to figure out the underlying type for the object regardless of it ! /// is a Proxied object or the real object. ! /// </summary> ! /// <param name="obj">The object to get the type of.</param> ! /// <returns>The Underlying Type for the object regardless of if it is a Proxy.</returns> ! System.Type GetClass(object obj); } } Index: LazyInitializer.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/LazyInitializer.cs,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -C2 -d -r1.1.2.3 -r1.1.2.4 *** LazyInitializer.cs 4 Oct 2004 13:13:04 -0000 1.1.2.3 --- LazyInitializer.cs 5 Oct 2004 15:25:05 -0000 1.1.2.4 *************** *** 104,108 **** /// </summary> /// <param name="info">The <see cref="SerializationInfo"/> to write the object to.</param> ! protected abstract void AddSerializationInfo(SerializationInfo info); public object Identifier --- 104,108 ---- /// </summary> /// <param name="info">The <see cref="SerializationInfo"/> to write the object to.</param> ! protected abstract void AddSerailizationInfo(SerializationInfo info); public object Identifier *************** *** 189,193 **** // let the specific LazyInitializer write its requirements for deserialization // into the stream. ! AddSerializationInfo( info ); // don't need a return value for proxy. --- 189,193 ---- // let the specific LazyInitializer write its requirements for deserialization // into the stream. ! AddSerailizationInfo( info ); // don't need a return value for proxy. Index: AvalonLazyInitializer.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/Attic/AvalonLazyInitializer.cs,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -C2 -d -r1.1.2.3 -r1.1.2.4 *** AvalonLazyInitializer.cs 4 Oct 2004 13:13:04 -0000 1.1.2.3 --- AvalonLazyInitializer.cs 5 Oct 2004 15:25:05 -0000 1.1.2.4 *************** *** 17,38 **** private static readonly log4net.ILog log = log4net.LogManager.GetLogger( typeof(AvalonLazyInitializer) ); private System.Type[] _interfaces; /// <summary> ! /// /// </summary> ! /// <param name="persistentClass"></param> ! /// <param name="interfaces"></param> ! /// <param name="id"></param> ! /// <param name="identifierProperty"></param> ! /// <param name="session"></param> ! internal AvalonLazyInitializer(System.Type persistentClass, System.Type[] interfaces, object id, PropertyInfo identifierPropertyInfo, ISessionImplementor session) : base (persistentClass, id, identifierPropertyInfo, session) { _interfaces = interfaces; } ! protected override void AddSerializationInfo(SerializationInfo info) { // the AvalonProxyDeserializer will be the Type that is actually serialized for this --- 17,41 ---- private static readonly log4net.ILog log = log4net.LogManager.GetLogger( typeof(AvalonLazyInitializer) ); + private System.Type _concreteProxy; private System.Type[] _interfaces; /// <summary> ! /// Initializes a new <see cref="AvalonLazyInitializer"/> object. /// </summary> ! /// <param name="persistentClass">The Class to Proxy.</param> ! /// <param name="concreteProxy">The <see cref="System.Type"/> to use as the Proxy.</param> ! /// <param name="interfaces">An array of <see cref="System.Type"/> interfaces that the Proxy should implement.</param> ! /// <param name="id">The Id of the Object we are Proxying.</param> ! /// <param name="identifierPropertyInfo">The PropertyInfo for the <id> property.</param> ! /// <param name="session">The ISession this Proxy is in.</param> ! internal AvalonLazyInitializer(System.Type persistentClass, System.Type concreteProxy, System.Type[] interfaces, object id, PropertyInfo identifierPropertyInfo, ISessionImplementor session) : base (persistentClass, id, identifierPropertyInfo, session) { + _concreteProxy = concreteProxy; _interfaces = interfaces; } ! protected override void AddSerailizationInfo(SerializationInfo info) { // the AvalonProxyDeserializer will be the Type that is actually serialized for this *************** *** 42,45 **** --- 45,49 ---- info.AddValue( "_target", _target ); info.AddValue( "_persistentClass", _persistentClass ); + info.AddValue( "_concreteProxy", _concreteProxy ); info.AddValue( "_interfaces", _interfaces ); info.AddValue( "_identifierPropertyInfo", _identifierPropertyInfo ); --- NEW FILE: AvalonCustomProxyGenerator.cs --- using System; using System.Reflection.Emit; using Apache.Avalon.DynamicProxy; using Apache.Avalon.DynamicProxy.Builder.CodeGenerators; namespace NHibernate.Proxy { /// <summary> /// This will build a proxy for a <see cref="System.Type"/> that is /// a <c>Class</c> and then add the <see cref="INHibernateProxy"/> /// interface to it. /// </summary> public class AvalonCustomProxyGenerator : ClassProxyGenerator { public AvalonCustomProxyGenerator(ModuleScope scope) : base(scope) { } public AvalonCustomProxyGenerator(ModuleScope scope, GeneratorContext context) : base(scope, context) { } protected override TypeBuilder CreateTypeBuilder(System.Type baseType, System.Type[] interfaces) { bool isImplemented = false; // check to see if this implements INHibernateProxy - if not then make it // implement the interface for( int i=0; i<interfaces.Length; i++) { if( interfaces[i].Equals( typeof(INHibernateProxy) ) ) { isImplemented = true; } } if( isImplemented==false ) { int length = interfaces.Length; System.Type[] newInterfaces = new System.Type[ length + 1 ]; Array.Copy( interfaces, 0, newInterfaces, 0, length ); newInterfaces[ length ] = typeof(INHibernateProxy); interfaces = newInterfaces; } TypeBuilder builder = base.CreateTypeBuilder(baseType, interfaces); // the CreateTypeBuilder for a Proxy of a Class ignores the interfaces parameter - // so we need to tell the ProxyGenerator to specifically generate the // implementation of INHibernateProxy : ISerializable GenerateInterfaceImplementation( interfaces ); return builder; } } } Index: ProxyGeneratorFactory.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/Attic/ProxyGeneratorFactory.cs,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -C2 -d -r1.1.2.2 -r1.1.2.3 *** ProxyGeneratorFactory.cs 3 Oct 2004 16:58:13 -0000 1.1.2.2 --- ProxyGeneratorFactory.cs 5 Oct 2004 15:25:05 -0000 1.1.2.3 *************** *** 19,22 **** --- 19,24 ---- public static IProxyGenerator GetProxyGenerator() { + //TODO: make this read from a configuration file!!! At this point anybody + // could substitue in their own IProxyGenerator and LazyInitializer. return _generator; } Index: AvalonProxyDeserializer.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/Attic/AvalonProxyDeserializer.cs,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** AvalonProxyDeserializer.cs 3 Oct 2004 16:58:13 -0000 1.1.2.1 --- AvalonProxyDeserializer.cs 5 Oct 2004 15:25:05 -0000 1.1.2.2 *************** *** 15,18 **** --- 15,19 ---- private object _target = null; private System.Type _persistentClass = null; + private System.Type _concreteProxy = null; private System.Type[] _interfaces = null; private PropertyInfo _identifierPropertyInfo = null; *************** *** 36,39 **** --- 37,41 ---- object proxy = generator.GetProxy( _persistentClass + , _concreteProxy , _interfaces , _identifierPropertyInfo |