From: Michael D. <mik...@us...> - 2004-12-09 17:52:28
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18504/Proxy Modified Files: LazyInitializer.cs Added Files: INHibernateProxy.cs IProxyGenerator.cs NHibernateProxyHelper.cs ProxyGeneratorFactory.cs Removed Files: HibernateProxy.cs HibernateProxyHelper.cs IHibernateProxy.cs Log Message: Migrated most Proxy items from proxy branch to this one. Have not moved the actual proxy code. Will do that when the serialization bug in DynamicProxy is fixed. --- NEW FILE: NHibernateProxyHelper.cs --- using System; namespace NHibernate.Proxy { /// <summary> /// NHibernateProxyHelper provides convenience methods for working with /// objects that might be instances of Classes or the Proxied version of /// the Class. /// </summary> public sealed class NHibernateProxyHelper { private NHibernateProxyHelper() { //can't instantiate } /// <summary> /// Gets the NLazyInitializer that is used by the Proxy. /// </summary> /// <param name="proxy">The Proxy object</param> /// <returns>A reference to NLazyInitializer that contains the details of the Proxied object.</returns> public static LazyInitializer GetLazyInitializer(INHibernateProxy proxy) { LazyInitializer li = ProxyGeneratorFactory.GetProxyGenerator().GetLazyInitializer( proxy ); return li; } /// <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 static System.Type GetClass(object obj) { if (obj is INHibernateProxy) { INHibernateProxy proxy = (INHibernateProxy) obj; LazyInitializer li = NHibernateProxyHelper.GetLazyInitializer( proxy ); return li.PersistentClass; } else { return obj.GetType(); } } } } --- IHibernateProxy.cs DELETED --- --- NEW FILE: IProxyGenerator.cs --- using System; using System.Reflection; using NHibernate.Engine; namespace NHibernate.Proxy { /// <summary> /// Summary description for IProxyGenerator. /// </summary> public interface IProxyGenerator { /// <summary> /// Build a proxy using the Castle.DynamicProxy library. /// </summary> /// <param name="persistentClass">The PersistentClass to proxy.</param> /// <param name="interfaces">The extra interfaces the Proxy should implement.</param> /// <param name="identifierPropertyInfo">The PropertyInfo to get/set the Id.</param> /// <param name="id">The value for the Id.</param> /// <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); } } --- NEW FILE: INHibernateProxy.cs --- using System; using System.Runtime.Serialization; namespace NHibernate.Proxy { /// <summary> /// A marker interface so NHibernate can know if it is dealing with /// an object that is a Proxy. /// </summary> /// <remarks> /// This interface should not be implemented by anything other than /// the Dynamically generated Proxy. It has to be public scope because /// the Proxies are created in a seperate DLL than NHibernate. /// </remarks> public interface INHibernateProxy { } } Index: LazyInitializer.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Proxy/LazyInitializer.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** LazyInitializer.cs 21 Nov 2004 22:56:30 -0000 1.2 --- LazyInitializer.cs 9 Dec 2004 17:52:16 -0000 1.3 *************** *** 1,171 **** using System; using System.Reflection; using NHibernate.Engine; using NHibernate.Util; - using log4net; - namespace NHibernate.Proxy { /// <summary> ! /// Summary description for LazyInitializer. /// </summary> ! public abstract class LazyInitializer { ! protected static readonly object INVOKE_IMPLEMENTATION = new object(); ! ! private object target = null; ! private object id; ! private ISessionImplementor session; ! private System.Type persistentClass; ! private MethodInfo getIdentifierMethod; ! private bool overridesEquals; ! public LazyInitializer(System.Type persistentClass, object id, MethodInfo getIdentifierMethod, ISessionImplementor session) { ! this.id = id; ! this.session = session; ! this.persistentClass = persistentClass; ! this.getIdentifierMethod = getIdentifierMethod; ! overridesEquals = ReflectHelper.OverridesEquals(persistentClass); ! } ! public void Initialize() { ! if (target==null) { ! if ( session==null ) { ! throw new HibernateException("Could not initialize proxy - no Session"); } ! else if ( !session.IsOpen ) { ! throw new HibernateException("Could not initialize proxy - the owning Session was closed"); } ! else { ! target = session.ImmediateLoad(persistentClass, id); } } } ! private void InitializeWrapExceptions() { ! try { Initialize(); } ! catch (Exception e) { ! LogManager.GetLogger( typeof(LazyInitializer) ).Error("Exception initializing proxy", e); throw new LazyInitializationException(e); } } ! protected abstract object SerializableProxy(); ! protected object Invoke(MethodInfo method, object[] args) { ! ! string methodName = method.Name; ! int pars = method.GetParameters().Length; ! if ( pars==0 ) { ! if ( "WriteReplace".Equals(methodName) ) { ! if (target==null && session!=null ) target = session.GetEntity( ! new Key( id, session.Factory.GetPersister(persistentClass) ) ! ); ! if (target==null) { ! /*if ( session==null || !session.isOpen() ) { ! return session.getFactory().getPersister(persistentClass).instantiate(id); //A little "empty" object ! } ! else {*/ ! return SerializableProxy(); ! //} } ! else { ! return target; } - - } - else if ( !overridesEquals && getIdentifierMethod!=null && "GetHashCode".Equals(methodName) ) { - // kinda dodgy, since it redefines the hashcode of the proxied object. - // but necessary if we are to keep proxies in HashSets without - // forcing them to be initialized - return id.GetHashCode(); - } - else if ( method.Equals(getIdentifierMethod) ) { - return id; - } - else if ( "Finalize".Equals( methodName ) ) { - return null; } - } ! else if ( pars==1 && !overridesEquals && getIdentifierMethod!=null && "Equals".Equals(methodName) ) { ! // less dodgy because Hibernate forces == to be same as identifier equals ! return (bool) id.Equals( getIdentifierMethod.Invoke( args[0], null ) ); ! } ! ! // otherwise: ! return INVOKE_IMPLEMENTATION; ! /*try { ! return method.invoke( getImplementation(), args ); ! } ! catch (InvocationTargetException ite) { ! throw ite.getTargetException(); ! }*/ } ! public object Identifier { ! get { ! return id; } ! } ! ! public System.Type PersistentClass { ! get { ! return persistentClass; } ! } ! ! public bool IsUninitialized { ! get { ! return target == null; } ! } ! ! public ISessionImplementor Session { ! get { ! return session; } ! } ! ! public void SetSession(ISessionImplementor s) { ! if (s!=session) { ! if ( session!=null && session.IsOpen ) { ! //TODO: perhaps this should be some other RuntimeException... ! throw new LazyInitializationException("Illegally attempted to associate a proxy with two open Sessions"); ! } ! else { ! session = s; ! } } - } - /// <summary> - /// Return the underlying persistent object, initializing if necessary - /// </summary> - public object GetImplementation() { - InitializeWrapExceptions(); - return target; - } - - /// <summary> - /// Return the underlying persistent object in the given Session, or null - /// </summary> - /// <param name="s"></param> - /// <returns></returns> - public object GetImplementation(ISessionImplementor s) { - return s.GetEntity( new Key( - Identifier, - s.Factory.GetPersister( PersistentClass ) - ) ); } } ! } \ No newline at end of file --- 1,232 ---- using System; + using System.Collections; using System.Reflection; + using System.Runtime.Serialization; using NHibernate.Engine; using NHibernate.Util; namespace NHibernate.Proxy { /// <summary> ! /// Provides the base functionallity to Handle Member calls into a dynamically ! /// generated NHibernate Proxy. /// </summary> ! /// <remarks> ! /// This could be an extension point later if the .net framework ever gets a Proxy ! /// class that is similar to the java.lang.reflect.Proxy or if a library similar ! /// to cglib was made in .net. ! /// </remarks> ! [Serializable] ! public abstract class LazyInitializer { ! /// <summary> ! /// If this is returned by Invoke then the subclass needs to Invoke the ! /// method call against the object that is being proxied. ! /// </summary> ! protected static readonly object InvokeImplementation = new object(); ! private object _target = null; ! private object _id; ! [NonSerialized] ! private ISessionImplementor _session; ! private System.Type _persistentClass; ! private PropertyInfo _identifierPropertyInfo; ! private bool _overridesEquals; ! /// <summary> ! /// Create a LazyInitializer to handle all of the Methods/Properties that are called ! /// on the Proxy. ! /// </summary> ! /// <param name="persistentClass">The Class to Proxy.</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> ! protected LazyInitializer(System.Type persistentClass, object id, PropertyInfo identifierPropertyInfo, ISessionImplementor session) ! { ! _persistentClass = persistentClass; ! _id = id; ! _session = session; ! _identifierPropertyInfo = identifierPropertyInfo; ! _overridesEquals = ReflectHelper.OverridesEquals(_persistentClass); ! } ! ! /// <summary> ! /// Perform an ImmediateLoad of the actual object for the Proxy. ! /// </summary> ! /// <exception cref="HibernateException"> ! /// Thrown when the Proxy has no Session or the Session is not open. ! /// </exception> ! public void Initialize() ! { ! if( _target==null ) ! { ! if( _session==null ) ! { ! throw new HibernateException( "Could not initialize proxy - no Session." ); } ! else if( _session.IsOpen==false ) ! { ! throw new HibernateException( "Could not initialize proxy - the owning Session was closed." ); } ! else ! { ! _target = _session.ImmediateLoad( _persistentClass, _id ); } } } ! /// <summary> ! /// Initializes the Proxy. ! /// </summary> ! /// <remarks> ! /// If an Exception is thrown then it will be logged and wrapped into a ! /// <see cref="LazyInitializationException" />. ! /// </remarks> ! /// <exception cref="LazyInitializationException"> ! /// Thrown whenever a problem is encountered during the Initialization of the Proxy. ! /// </exception> ! private void InitializeWrapExceptions() ! { ! try ! { Initialize(); } ! catch( Exception e ) ! { ! log4net.LogManager.GetLogger(typeof(LazyInitializer)).Error("Exception initializing proxy.", e); throw new LazyInitializationException(e); } } ! /// <summary> ! /// Adds all of the information into the SerializationInfo that is needed to ! /// reconstruct the proxy during deserialization or to replace the proxy ! /// with the instantiated target. ! /// </summary> ! /// <param name="info">The <see cref="SerializationInfo"/> to write the object to.</param> ! protected virtual void AddSerializationInfo(SerializationInfo info) ! { ! } ! public object Identifier ! { ! get { return _id; } ! } ! public System.Type PersistentClass ! { ! get { return _persistentClass; } ! } ! public bool IsUninitialized ! { ! get { return (_target==null); } ! } ! public ISessionImplementor Session ! { ! get { return _session; } ! set ! { ! if(value!=_session) ! { ! if( _session!=null && _session.IsOpen ) ! { ! //TODO: perhaps this should be some other RuntimeException... ! throw new LazyInitializationException("Illegally attempted to associate a proxy with two open Sessions"); } ! else ! { ! _session = value; } } } ! } ! /// <summary> ! /// Return the Underlying Persistent Object, initializing if necessary. ! /// </summary> ! /// <returns>The Persistent Object this proxy is Proxying.</returns> ! public object GetImplementation() ! { ! InitializeWrapExceptions(); ! return _target; ! } + /// <summary> + /// Return the Underlying Persistent Object in a given <see cref="ISession"/>, or null. + /// </summary> + /// <param name="s">The Session to get the object from.</param> + /// <returns>The Persistent Object this proxy is Proxying, or <c>null</c>.</returns> + public object GetImplementation(ISessionImplementor s) + { + Key key = new Key( Identifier, s.Factory.GetPersister(PersistentClass) ); + return s.GetEntity(key); } ! /// <summary> ! /// Invokes the method if this is something that the LazyInitializer can handle ! /// without the underlying proxied object being instantiated. ! /// </summary> ! /// <param name="methodName">The name of the method/property to Invoke.</param> ! /// <param name="args">The arguments to pass the method/property.</param> ! /// <returns> ! /// The result of the Invoke if the underlying proxied object is not needed. If the ! /// underlying proxied object is needed then it returns the result <see cref="InvokeImplementation"/> ! /// which indicates that the Proxy will need to forward to the real implementation. ! /// </returns> ! public virtual object Invoke(MethodBase method, params object[] args) ! { ! // all Proxies must implement INHibernateProxy which extends ISerializable ! // not true anymore - DynamicProxy now handles the serialization. All Proxy ! // Generators should make sure that ISerializable is implemented if their ! // Proxy doesn't do it by default. ! if( method.Name.Equals("GetObjectData") ) ! { ! SerializationInfo info = (SerializationInfo)args[0]; ! StreamingContext context = (StreamingContext)args[1]; ! ! if( _target==null & _session!=null ) ! { ! Key key = new Key(_id, _session.Factory.GetPersister( _persistentClass ) ); ! _target = _session.GetEntity( key ); ! } ! ! // let the specific LazyInitializer write its requirements for deserialization ! // into the stream. ! AddSerializationInfo( info ); ! ! // don't need a return value for proxy. ! return null; } ! else if( !_overridesEquals && _identifierPropertyInfo!=null && method.Name.Equals("GetHashCode") ) ! { ! // kinda dodgy, since it redefines the hashcode of the proxied object. ! // but necessary if we are to keep proxies in HashSets without ! // forcing them to be initialized ! return _id.GetHashCode(); } ! else if( _identifierPropertyInfo!=null && method.Equals( _identifierPropertyInfo.GetGetMethod(true) ) ) ! { ! return _id; } ! else if( method.Name.Equals( "Dispose" ) ) ! { ! return null; } ! ! else if ( args.Length==1 && !_overridesEquals && _identifierPropertyInfo!=null && method.Name.Equals( "Equals" ) ) ! { ! // less dodgy because NHibernate forces == to be the same as Identifier Equals ! return _id.Equals( _identifierPropertyInfo.GetValue( _target, null ) ); ! } ! ! else ! { ! return InvokeImplementation; } } } ! } --- HibernateProxy.cs DELETED --- --- NEW FILE: ProxyGeneratorFactory.cs --- using System; using System.Reflection; //TODO: build a version //using Castle.DynamicProxy; using NHibernate.Engine; namespace NHibernate.Proxy { /// <summary> /// A Factory for getting the ProxyGenerator. /// </summary> public sealed class ProxyGeneratorFactory { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( typeof(ProxyGeneratorFactory) ); //TODO: build a version private static IProxyGenerator _generator = null;// new CastleProxyGenerator(); 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; } } } --- HibernateProxyHelper.cs DELETED --- |