From: Michael D. <mik...@us...> - 2004-08-09 03:26:16
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10133/Impl Modified Files: SessionFactoryImpl.cs SessionImpl.cs Added Files: SessionFactoryObjectFactory.cs Log Message: Added [Serializable] and code required to make them serializable to classes. Also synched up some more with h2.0.3. Index: SessionImpl.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl/SessionImpl.cs,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** SessionImpl.cs 6 Aug 2004 15:34:57 -0000 1.36 --- SessionImpl.cs 9 Aug 2004 03:25:55 -0000 1.37 *************** *** 194,198 **** /// </remarks> [Serializable] ! internal class SessionImpl : ISessionImplementor { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(SessionImpl)); --- 194,198 ---- /// </remarks> [Serializable] ! internal class SessionImpl : ISessionImplementor, ISerializable, IDeserializationCallback { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(SessionImpl)); *************** *** 211,217 **** private IDictionary proxiesByKey; //key=Key, value=HibernateProxy ! [NonSerialized] private IdentityMap entries;//key=Object, value=Entry ! [NonSerialized] private IdentityMap arrayHolders; //key=array, value=ArrayHolder ! [NonSerialized] private IdentityMap collections; //key=PersistentCollection, value=CollectionEntry private IDictionary nullifiables = new Hashtable(); //set of Keys of deleted objects --- 211,218 ---- private IDictionary proxiesByKey; //key=Key, value=HibernateProxy ! //IdentityMaps are serializable in NH ! private IdentityMap entries;//key=Object, value=Entry ! private IdentityMap arrayHolders; //key=array, value=ArrayHolder ! private IdentityMap collections; //key=PersistentCollection, value=CollectionEntry private IDictionary nullifiables = new Hashtable(); //set of Keys of deleted objects *************** *** 240,244 **** // (discarding them at the end of a "shortcircuited" auto-flush) and then // we would keep them in a list - //[NonSerialized] private IDictionary updates; [NonSerialized] private ArrayList updates; // Actually the semantics of the next three are really "Bag" --- 241,244 ---- *************** *** 257,264 **** [NonSerialized] private IBatcher batcher; ! // For serialization ! [NonSerialized] private SerializationInfo siInfo; ! ! private IPreparer preparer; --- 257,261 ---- [NonSerialized] private IBatcher batcher; ! [NonSerialized] private IPreparer preparer; *************** *** 531,542 **** } } ! SessionImpl(SerializationInfo info, StreamingContext context) { ! //The graph is not valid until OnDeserialization() has been called. ! siInfo = info; } ! public void GetObjectData(SerializationInfo info, StreamingContext context) { if ( IsConnected ) throw new InvalidOperationException("Cannot serialize a Session while connected"); --- 528,575 ---- } } + + + #region System.Runtime.Serialization.ISerializable Members ! /// <summary> ! /// Constructor used to recreate the Session during the deserialization. ! /// </summary> ! /// <param name="info"></param> ! /// <param name="context"></param> ! /// <remarks> ! /// This is needed because we have to do some checking before the serialization process ! /// begins. I don't know how to add logic in ISerializable.GetObjectData and have .net ! /// write all of the serializable fields out. ! /// </remarks> ! protected SessionImpl(SerializationInfo info, StreamingContext context) { ! this.factory = (SessionFactoryImpl)info.GetValue( "factory", typeof(SessionFactoryImpl) ); ! this.autoClose = info.GetBoolean("autoClose"); ! this.timestamp = info.GetInt64("timestamp"); ! this.closed = info.GetBoolean("closed"); ! this.flushMode = (FlushMode)info.GetValue( "flushMode", typeof(FlushMode) ); ! this.callAfterTransactionCompletionFromDisconnect = info.GetBoolean("callAfterTransactionCompletionFromDisconnect"); ! this.entitiesByKey = (IDictionary)info.GetValue( "entitiesByKey", typeof(IDictionary) ); ! this.proxiesByKey = (IDictionary)info.GetValue( "proxiesByKey", typeof(IDictionary) ); ! this.nullifiables = (IDictionary)info.GetValue( "nullifiables", typeof(IDictionary) ); ! this.interceptor = (IInterceptor)info.GetValue( "interceptor", typeof(IInterceptor) ); ! ! this.entries = (IdentityMap)info.GetValue( "entries", typeof(IdentityMap) ); ! this.collections = (IdentityMap)info.GetValue( "collections", typeof(IdentityMap) ); ! this.arrayHolders = (IdentityMap)info.GetValue( "arrayHolders", typeof(IdentityMap) ); ! } ! /// <summary> ! /// Verify the ISession can be serialized and write the fields to the Serializer. ! /// </summary> ! /// <param name="info"></param> ! /// <param name="context"></param> ! /// <remarks> ! /// The fields are marked with [NonSerializable] as just a point of reference. This method ! /// has complete control and what is serialized and those attributes are ignored. However, ! /// this method should be in synch with the attributes for easy readability. ! /// </remarks> ! void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { if ( IsConnected ) throw new InvalidOperationException("Cannot serialize a Session while connected"); *************** *** 546,560 **** log.Info("serializing session"); ! info.AddValue("entries", entries); ! info.AddValue("collections", collections); ! info.AddValue("arrayHolders", arrayHolders); } ! public void OnDeserialization(Object sender) { log.Info("deserializing session"); ! entries = (IdentityMap)siInfo.GetValue("entries", typeof(IdentityMap)); ! collections = (IdentityMap)siInfo.GetValue("collections", typeof(IdentityMap)); ! arrayHolders = (IdentityMap)siInfo.GetValue("arrayHolders", typeof(IdentityMap)); InitTransientCollections(); foreach(DictionaryEntry e in collections) --- 579,613 ---- log.Info("serializing session"); ! info.AddValue( "factory", factory, typeof(SessionFactoryImpl) ); ! info.AddValue( "autoClose", autoClose ); ! info.AddValue( "timestamp", timestamp ); ! info.AddValue( "closed", closed ); ! info.AddValue( "flushMode", flushMode ); ! info.AddValue( "callAfterTransactionCompletionFromDisconnect", callAfterTransactionCompletionFromDisconnect ); ! info.AddValue( "entitiesByKey", entitiesByKey, typeof(IDictionary) ); ! info.AddValue( "proxiesByKey", proxiesByKey, typeof(IDictionary) ); ! info.AddValue( "nullifiables", nullifiables, typeof(IDictionary) ); ! info.AddValue( "interceptor", interceptor, typeof(IInterceptor) ); ! ! info.AddValue( "entries", entries, typeof(IdentityMap) ); ! info.AddValue( "collections", collections, typeof(IdentityMap) ); ! info.AddValue( "arrayHolders", arrayHolders, typeof(IdentityMap) ); } + #endregion ! #region System.Runtime.Serialization.IDeserializationCallback Members ! ! /// <summary> ! /// Once the entire object graph has been deserialized then we can hook the ! /// collections, proxies, and entities back up to the ISession. ! /// </summary> ! /// <param name="sender"></param> ! void IDeserializationCallback.OnDeserialization(Object sender) { log.Info("deserializing session"); ! ! // don't need any section for IdentityMaps because .net does not have a problem ! // serializing them like java does. ! InitTransientCollections(); foreach(DictionaryEntry e in collections) *************** *** 573,588 **** } ! IDictionary newProxiesByKey = new Hashtable(proxiesByKey); ! foreach(object proxy in proxiesByKey) ! { ! if (proxy is HibernateProxy) ! HibernateProxyHelper.GetLazyInitializer(proxy as HibernateProxy).SetSession(this); ! else ! newProxiesByKey.Remove(proxy); ! } ! proxiesByKey = newProxiesByKey; ! newProxiesByKey = null; ! foreach(EntityEntry e in entries) { try --- 626,646 ---- } ! // TODO: figure out why proxies are having problems. The enumerator appears to be throwing ! // a null reference exception when the proxiesByKey.Count==0 ! // foreach(object proxy in proxiesByKey.Values) ! // { ! // object proxy = proxyEnumer.Current; ! // if (proxy is HibernateProxy) ! // { ! // HibernateProxyHelper.GetLazyInitializer(proxy as HibernateProxy).SetSession(this); ! // } ! // else ! // { ! // // the proxy was pruned during the serialization process ! // proxiesByKey.Remove(proxy); ! // } ! // } ! foreach(EntityEntry e in entries.Values) { try *************** *** 597,600 **** --- 655,659 ---- } } + #endregion internal SessionImpl(IDbConnection connection, SessionFactoryImpl factory, bool autoClose, long timestamp, IInterceptor interceptor) Index: SessionFactoryImpl.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl/SessionFactoryImpl.cs,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -d -r1.22 -r1.23 *** SessionFactoryImpl.cs 14 Jul 2004 21:24:51 -0000 1.22 --- SessionFactoryImpl.cs 9 Aug 2004 03:25:55 -0000 1.23 *************** *** 1,9 **** using System; - using System.IO; - using System.Xml; - using System.Data; using System.Collections; using System.Runtime.CompilerServices; using System.Text; using NHibernate.Cache; --- 1,10 ---- using System; using System.Collections; + using System.Data; + using System.IO; using System.Runtime.CompilerServices; + using System.Runtime.Serialization; using System.Text; + using System.Xml; using NHibernate.Cache; *************** *** 25,32 **** using HibernateDialect = NHibernate.Dialect.Dialect; ! ! ! namespace NHibernate.Impl { ! /// <summary> /// Concrete implementation of a SessionFactory. --- 26,31 ---- using HibernateDialect = NHibernate.Dialect.Dialect; ! namespace NHibernate.Impl ! { /// <summary> /// Concrete implementation of a SessionFactory. *************** *** 60,64 **** /// </para> /// </remarks> ! internal class SessionFactoryImpl : ISessionFactory, ISessionFactoryImplementor { --- 59,64 ---- /// </para> /// </remarks> ! [Serializable] ! internal class SessionFactoryImpl : ISessionFactory, ISessionFactoryImplementor, IObjectReference { *************** *** 68,91 **** private string uuid; ! private IDictionary classPersisters; ! private IDictionary classPersistersByName; ! private IDictionary collectionPersisters; ! private IDictionary namedQueries; ! private IDictionary imports; ! private IConnectionProvider connectionProvider; ! private IDictionary properties; ! private bool showSql; ! private bool useOuterJoin; ! //private Templates templates; ! private IDictionary querySubstitutions; ! private Dialect.Dialect dialect; ! private PreparedStatementCache statementCache; ! private ITransactionFactory transactionFactory; ! private int adoBatchSize; ! private bool useScrollableResultSets; ! private string defaultSchema; ! private object statementFetchSize; ! private IInterceptor interceptor; private static IIdentifierGenerator uuidgen = new UUIDHexGenerator(); --- 68,92 ---- private string uuid; ! [NonSerialized] private IDictionary classPersisters; ! [NonSerialized] private IDictionary classPersistersByName; ! [NonSerialized] private IDictionary collectionPersisters; ! [NonSerialized] private IDictionary namedQueries; ! [NonSerialized] private IDictionary imports; ! [NonSerialized] private IConnectionProvider connectionProvider; ! [NonSerialized] private IDictionary properties; ! [NonSerialized] private bool showSql; ! [NonSerialized] private bool useOuterJoin; ! // TODO: figure out why this is commented out in nh and not h2.0.3 ! //[NonSerialized] private Templates templates; ! [NonSerialized] private IDictionary querySubstitutions; ! [NonSerialized] private Dialect.Dialect dialect; ! [NonSerialized] private PreparedStatementCache statementCache; ! [NonSerialized] private ITransactionFactory transactionFactory; ! [NonSerialized] private int adoBatchSize; ! [NonSerialized] private bool useScrollableResultSets; ! [NonSerialized] private string defaultSchema; ! [NonSerialized] private object statementFetchSize; ! [NonSerialized] private IInterceptor interceptor; private static IIdentifierGenerator uuidgen = new UUIDHexGenerator(); *************** *** 188,198 **** IClassPersister cp; //TODO: H2.0.3 created a PersisterFactory ! if (persisterClass==null || persisterClass==typeof(EntityPersister)) { ! cp = new EntityPersister(model, this); ! } else if (persisterClass==typeof(NormalizedEntityPersister)) { ! cp = new NormalizedEntityPersister(model, this); ! } else { ! cp = InstantiatePersister(persisterClass, model); ! } classPersisters[model.PersistentClazz] = cp; classPersistersByName[model.Name] = cp ; --- 189,200 ---- IClassPersister cp; //TODO: H2.0.3 created a PersisterFactory ! cp = PersisterFactory.Create(model, this); ! // if (persisterClass==null || persisterClass==typeof(EntityPersister)) { ! // cp = new EntityPersister(model, this); ! // } else if (persisterClass==typeof(NormalizedEntityPersister)) { ! // cp = new NormalizedEntityPersister(model, this); ! // } else { ! // cp = InstantiatePersister(persisterClass, model); ! // } classPersisters[model.PersistentClazz] = cp; classPersistersByName[model.Name] = cp ; *************** *** 221,224 **** --- 223,227 ---- } + SessionFactoryObjectFactory.AddInstance(uuid, name, this, properties); // queries: *************** *** 242,248 **** // It is better to hold strong references on some (LRU/MRU) queries private const int MaxStrongRefCount = 128; ! private readonly object[] strongRefs = new object[MaxStrongRefCount]; ! private int strongRefIndex = 0; ! private readonly IDictionary softQueryCache = new Hashtable(); //TODO: make soft reference map //TODO: All --- 245,251 ---- // It is better to hold strong references on some (LRU/MRU) queries private const int MaxStrongRefCount = 128; ! [NonSerialized] private readonly object[] strongRefs = new object[MaxStrongRefCount]; ! [NonSerialized] private int strongRefIndex = 0; ! [NonSerialized] private readonly IDictionary softQueryCache = new Hashtable(); //TODO: make soft reference map //TODO: All *************** *** 534,539 **** --- 537,579 ---- //TODO: Serialization stuff + // will have to do a diff serialization object and then deserialization // private void readObject() // private void writeObject() + #region System.Runtime.Serialization.IObjectReference Members + + public object GetRealObject(StreamingContext context) + { + // the SessionFactory that was serialized only has values in the properties + // "name" and "uuid". In here convert the serialized SessionFactory into + // an instance of the SessionFactory in the current AppDomain. + log.Debug("Resolving serialized SessionFactory"); + + // look for the instance by uuid - this will work when a SessionFactory + // is serialized and deserialized in the same AppDomain. + ISessionFactory result = SessionFactoryObjectFactory.GetInstance(uuid); + if(result==null) + { + // if we were deserialized into a different AppDomain, look for an instance with the + // same name. + result = SessionFactoryObjectFactory.GetNamedInstance(name); + if(result==null) + { + throw new NullReferenceException("Could not find a SessionFactory named " + name + " or identified by uuid " + uuid ); + } + else + { + log.Debug("resolved SessionFactory by name"); + } + } + else + { + log.Debug("resolved SessionFactory by uuid"); + } + + return result; + } + + #endregion + public IType[] GetReturnTypes(string queryString) *************** *** 564,581 **** } - //TODO: h2.0.3 - replace with PersisterFactory - private IClassPersister InstantiatePersister(System.Type persisterClass, PersistentClass model) { - - try { - return (IClassPersister) Activator.CreateInstance( persisterClass, new object[] { model, this } ); - } catch (Exception e) { - if ( e is HibernateException ) { - throw (HibernateException) e; - } else { - throw new MappingException( "Could not instantiate persiser " + persisterClass.Name, e); - } - } - } - public IClassMetadata GetClassMetadata(System.Type persistentClass) { --- 604,607 ---- *************** *** 660,665 **** finally { ! //TODO: H2.0.3 ! //SessionFactoryObjectFactory.removeInstance(uuid, name, properties); } } --- 686,690 ---- finally { ! SessionFactoryObjectFactory.RemoveInstance(uuid, name, properties); } } *************** *** 688,691 **** --- 713,717 ---- if(p.HasCache) p.CacheConcurrencyStrategy.Clear(); } + } } --- NEW FILE: SessionFactoryObjectFactory.cs --- using System; using System.Collections; namespace NHibernate.Impl { /// <summary> /// Resolves <see cref="ISessionFactory"/> lookups and deserialization. /// </summary> /// <remarks> /// <para> /// This is used heavily be Deserialization. Currently a SessionFactory is not really serialized. /// All that is serialized is it's name and uid. During Deserializaiton the serialized SessionFactory /// is converted to the one contained in this object. So if you are serializing across AppDomains /// you should make sure that "name" is specified for the SessionFactory in the hbm.xml file and that the /// other AppDomain has a configured SessionFactory with the same name. If /// you are serializing in the same AppDomain then there will be no problem because the uid will /// be in this object. /// </para> /// <para> /// TODO: verify that the AppDomain statements are correct. /// </para> /// </remarks> public class SessionFactoryObjectFactory { // to stop this class from being unloaded - this is a comment // from h2.0.3 - is this applicable to .net also??? private static readonly SessionFactoryObjectFactory Instance; private static readonly log4net.ILog log; static SessionFactoryObjectFactory() { log = log4net.LogManager.GetLogger( typeof(SessionFactoryObjectFactory) ); Instance = new SessionFactoryObjectFactory(); log.Debug("initializing class SessionFactoryObjectFactory"); } // in h2.0.3 these use a class called "FastHashMap" private static readonly Hashtable Instances = new Hashtable(); private static readonly Hashtable NamedInstances = new Hashtable(); /// <summary> /// Adds an Instance of the SessionFactory to the local "cache". /// </summary> /// <param name="uid">The identifier of the ISessionFactory.</param> /// <param name="name">The name of the ISessionFactory.</param> /// <param name="instance">The ISessionFactory.</param> /// <param name="properties">The configured properties for the ISessionFactory.</param> public static void AddInstance(string uid, string name, ISessionFactory instance, IDictionary properties) { if(log.IsDebugEnabled) { string nameMsg = "unnamed"; if(name!=null && name!=String.Empty) { nameMsg = name; } log.Debug( "registered: " + uid + "(" + name + ")" ); } Instances[uid] = instance; if(name!=null && name!=String.Empty) { log.Info("Factory name:" + name); NamedInstances[name] = instance; } else { log.Info("no name configured"); } } /// <summary> /// Removes the Instance of the SessionFactory from the local "cache". /// </summary> /// <param name="uid">The identifier of the ISessionFactory.</param> /// <param name="name">The name of the ISessionFactory.</param> /// <param name="properties">The configured properties for the ISessionFactory.</param> public static void RemoveInstance(string uid, string name, IDictionary properties) { if(name!=null && name!=String.Empty) { log.Info("unbinding factory: " + name); NamedInstances.Remove(name); } Instances.Remove(uid); } /// <summary> /// Returns a Named Instance of the SessionFactory from the local "cache" identified by name. /// </summary> /// <param name="name">The name of the ISessionFactory.</param> /// <returns>An instantiated ISessionFactory.</returns> public static ISessionFactory GetNamedInstance(string name) { log.Debug( "lookup: name=" + name); ISessionFactory factory = NamedInstances[name] as ISessionFactory; if(factory==null) { log.Warn( "Not found: " + name ); } return factory; } /// <summary> /// Returns an Instance of the SessionFactory from the local "cache" identified by UUID. /// </summary> /// <param name="uid">The identifier of the ISessionFactory.</param> /// <returns>An instantiated ISessionFactory.</returns> public static ISessionFactory GetInstance(string uid) { log.Debug( "lookup: uid=" + uid ); ISessionFactory factory = Instances[uid] as ISessionFactory; if(factory==null) { log.Warn( "Not found: " + uid ); } return factory; } } } |