protected virtual ReadOnlyClone UnloadIfExpired(ReadOnlyClone clone)
 {
     if (IsExpired(clone))
     {
         UnloadClone(clone);
         return(null);
     }
     return(clone);
 }
        public virtual void Deserialize(object obj)
        {
            string id  = this.Context.ObjectManager.GetObjectIdentity(obj);
            string key = GetKey(obj, id);

            lock (ReadOnlyObjectCache)
            {
                ReadOnlyClone clone = (ReadOnlyClone)ReadOnlyObjectCache.ObjectCache[key];
                if (clone == null)
                {
                    throw new ObjectNotFoundException("Could not find object with identity " + id + " and of type " + obj.GetType() + " in read-only cache!");
                }
                DeserializeClone(obj, clone);
                clone.IncUseCount();
            }
        }
        public virtual void Serialize(object obj)
        {
            string id  = this.Context.ObjectManager.GetObjectIdentity(obj);
            string key = GetKey(obj, id);

            lock (ReadOnlyObjectCache)
            {
                ReadOnlyClone clone = (ReadOnlyClone)ReadOnlyObjectCache.ObjectCache[key];
                if (clone == null)
                {
                    clone = new ReadOnlyClone();
                    ReadOnlyObjectCache.ObjectCache[key] = clone;
                }
                SerializeClone(obj, clone, id, key);
            }
        }
        public virtual bool HasObject(object obj)
        {
            string id  = this.Context.ObjectManager.GetObjectIdentity(obj);
            string key = GetKey(obj, id);

            lock (ReadOnlyObjectCache)
            {
                ReadOnlyClone clone = (ReadOnlyClone)ReadOnlyObjectCache.ObjectCache[key];
                if (clone != null)
                {
                    clone = UnloadIfExpired(clone);
                }
                if (clone != null)
                {
                    return(true);
                }
            }
            return(false);
        }
        protected virtual bool IsExpired(ReadOnlyClone clone)
        {
            IObjectManager     om          = this.Context.ObjectManager;
            IClassMap          classMap    = this.Context.DomainMap.MustGetClassMap(clone.Type);
            TimeToLiveBehavior ttlBehavior = om.GetTimeToLiveBehavior(classMap);

            if (ttlBehavior == TimeToLiveBehavior.Default || ttlBehavior == TimeToLiveBehavior.On)
            {
                long ttl = om.GetTimeToLive(classMap);
                if (ttl > 0)
                {
                    if (clone.LoadedTime.AddSeconds(ttl) < DateTime.Now)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
        protected virtual void UnloadAllExpired(long max)
        {
            long cntUnloaded = 0;

            foreach (ReadOnlyClone clone in ReadOnlyObjectCache.ObjectCache.Values)
            {
                ReadOnlyClone check = UnloadIfExpired(clone);
                if (check == null)
                {
                    cntUnloaded++;
                    if (max > 0)
                    {
                        if (cntUnloaded == max)
                        {
                            return;
                        }
                    }
                }
            }
        }
        private void UnloadClone(ReadOnlyClone clone)
        {
            string key = clone.Key;

            ReadOnlyObjectCache.ObjectCache.Remove(key);
        }
        protected virtual void DeserializeClone(object obj, ReadOnlyClone clone)
        {
            IObjectManager   om       = this.Context.ObjectManager;
            IDomainMap       dm       = this.Context.DomainMap;
            IAssemblyManager am       = this.Context.AssemblyManager;
            IClassMap        classMap = dm.MustGetClassMap(obj.GetType());
            IListManager     lm       = this.Context.ListManager;

            foreach (IPropertyMap propertyMap in classMap.GetAllPropertyMaps())
            {
                if (propertyMap.ReferenceType == ReferenceType.None)
                {
                    if (propertyMap.IsCollection)
                    {
                        IList values = (IList)clone.PropertyValues[propertyMap.Name];
                        IList list   = (IList)om.GetPropertyValue(obj, propertyMap.Name);

                        bool stackMute           = false;
                        IInterceptableList mList = list as IInterceptableList;
                        if (mList != null)
                        {
                            stackMute        = mList.MuteNotify;
                            mList.MuteNotify = true;
                        }
                        list.Clear();

                        foreach (object value in values)
                        {
                            list.Add(value);
                        }

                        IList cloneList = new ArrayList(list);

                        if (mList != null)
                        {
                            mList.MuteNotify = stackMute;
                        }

                        om.SetOriginalPropertyValue(obj, propertyMap.Name, cloneList);
                        om.SetNullValueStatus(obj, propertyMap.Name, false);
                    }
                    else
                    {
                        object value = clone.PropertyValues[propertyMap.Name];
                        om.SetPropertyValue(obj, propertyMap.Name, value);
                        om.SetOriginalPropertyValue(obj, propertyMap.Name, value);
                        om.SetNullValueStatus(obj, propertyMap.Name, (bool)clone.NullValueStatuses[propertyMap.Name]);
                    }
                }
                else
                {
                    IClassMap refClassMap = propertyMap.MustGetReferencedClassMap();
                    if (refClassMap.IsReadOnly)
                    {
                        if (propertyMap.IsCollection)
                        {
                            IList values = (IList)clone.PropertyValues[propertyMap.Name];
                            IList list   = (IList)om.GetPropertyValue(obj, propertyMap.Name);

                            bool stackMute           = false;
                            IInterceptableList mList = list as IInterceptableList;
                            if (mList != null)
                            {
                                stackMute        = mList.MuteNotify;
                                mList.MuteNotify = true;
                            }
                            list.Clear();

                            foreach (SerializedReference refId in values)
                            {
                                object value = null;
                                if (refId != null)
                                {
                                    refClassMap = dm.MustGetClassMap(refId.Type);
                                    Type refType = am.GetTypeFromClassMap(refClassMap);
                                    value = this.Context.GetObjectById(refId.Identity, refType, true);
                                    list.Add(value);
                                }
                            }

                            IList cloneList = new ArrayList(list);

                            if (mList != null)
                            {
                                mList.MuteNotify = stackMute;
                            }

                            om.SetOriginalPropertyValue(obj, propertyMap.Name, cloneList);
                            om.SetNullValueStatus(obj, propertyMap.Name, false);
                        }
                        else
                        {
                            object value = null;
                            SerializedReference refId = (SerializedReference)clone.PropertyValues[propertyMap.Name];
                            if (refId != null)
                            {
                                refClassMap = dm.MustGetClassMap(refId.Type);
                                Type refType = am.GetTypeFromClassMap(refClassMap);
                                value = this.Context.GetObjectById(refId.Identity, refType, true);
                            }
                            om.SetPropertyValue(obj, propertyMap.Name, value);
                            om.SetOriginalPropertyValue(obj, propertyMap.Name, value);
                            om.SetNullValueStatus(obj, propertyMap.Name, (bool)clone.NullValueStatuses[propertyMap.Name]);
                        }
                    }
                }
            }
        }
        protected virtual void SerializeClone(object obj, ReadOnlyClone clone, string id, string key)
        {
            IObjectManager   om       = this.Context.ObjectManager;
            IDomainMap       dm       = this.Context.DomainMap;
            IAssemblyManager am       = this.Context.AssemblyManager;
            IClassMap        classMap = dm.MustGetClassMap(obj.GetType());
            IListManager     lm       = this.Context.ListManager;

            clone.Identity = id;
            clone.Key      = key;
            clone.Type     = classMap.GetFullName();
            foreach (IPropertyMap propertyMap in classMap.GetAllPropertyMaps())
            {
                if (propertyMap.ReferenceType == ReferenceType.None)
                {
                    if (propertyMap.IsCollection)
                    {
                        IList values = new ArrayList();
                        IList list   = (IList)om.GetPropertyValue(obj, propertyMap.Name);

                        foreach (object value in list)
                        {
                            values.Add(value);
                        }

                        clone.PropertyValues[propertyMap.Name]    = values;
                        clone.NullValueStatuses[propertyMap.Name] = false;
                    }
                    else
                    {
                        object value = om.GetPropertyValue(obj, propertyMap.Name);
                        clone.PropertyValues[propertyMap.Name]    = value;
                        clone.NullValueStatuses[propertyMap.Name] = om.GetNullValueStatus(obj, propertyMap.Name);
                    }
                }
                else
                {
                    IClassMap refClassMap = propertyMap.MustGetReferencedClassMap();
                    if (refClassMap.IsReadOnly)
                    {
                        if (propertyMap.IsCollection)
                        {
                            IList values = new ArrayList();
                            IList list   = (IList)om.GetPropertyValue(obj, propertyMap.Name);

                            foreach (object value in list)
                            {
                                if (value != null)
                                {
                                    refClassMap = dm.MustGetClassMap(value.GetType());
                                    string refIdentity        = om.GetObjectIdentity(value);
                                    SerializedReference refId = new SerializedReference(refIdentity, refClassMap.GetFullName());
                                    values.Add(refId);
                                }
                            }
                            clone.PropertyValues[propertyMap.Name]    = values;
                            clone.NullValueStatuses[propertyMap.Name] = false;
                        }
                        else
                        {
                            object value = om.GetPropertyValue(obj, propertyMap.Name);
                            if (value != null)
                            {
                                refClassMap = dm.MustGetClassMap(value.GetType());
                                string refIdentity        = om.GetObjectIdentity(value);
                                SerializedReference refId = new SerializedReference(refIdentity, refClassMap.GetFullName());
                                value = refId;
                            }
                            clone.PropertyValues[propertyMap.Name]    = value;
                            clone.NullValueStatuses[propertyMap.Name] = om.GetNullValueStatus(obj, propertyMap.Name);
                        }
                    }
                }
            }
        }