Esempio n. 1
0
        /// <summary>
        /// Updates the object value from a source object of the same type.
        /// </summary>
        /// <param name="loader"></param>
        /// <param name="source"></param>
        private void UpdateFrom(ValueLoader loader, object source)
        {
            Version++;

            // if no one is holding the value, don't bother updating.
            //
            if (!CheckIfAnyoneCares())
            {
                return;
            }

            int version = Version;

            object value = ValueInternal;

            // sure source matches dest
            //
            if (!value.GetType().IsInstanceOfType(source))
            {
                throw new InvalidOperationException("Types not compatible");
            }

            Action handler = () =>
            {
                // make sure another update hasn't beat us to the punch.
                if (Version > version)
                {
                    return;
                }

                try {
                    _stats.OnStartUpdate();

                    ReflectionSerializer.UpdateObject(source, value, true, LastUpdatedTime);
                }
                finally {
                    _stats.OnCompleteUpdate();
                }
                // notify successful completion.
                NotifyCompletion(loader, null);
            };

            if (SynchronousMode)
            {
                handler();
            }
            else
            {
                PriorityQueue.AddUiWorkItem(
                    handler
                    );
            }
        }
Esempio n. 2
0
        private CacheEntry Get <T>(LoadContext loadContext, Action <T> completed, Action <Exception> error, bool resetCallbacks) where T : new()
        {
            if (loadContext == null)
            {
                throw new ArgumentNullException("LoadContext required.");
            }

            object identity = loadContext.UniqueKey;

            CacheEntry value;

            lock (_objectCache) {
                if (_objectCache.ContainsKey(typeof(T)) && _objectCache[typeof(T)].TryGetValue(identity, out value))
                {
                    value.LoadContext = loadContext;
                    if (resetCallbacks)
                    {
                        SetupCompletedCallback <T>(completed, error, value);
                    }
                    return(value);
                }
            }

            Type objectType = typeof(T);

            Action <CacheEntry> proxyCallback =
                cacheEntry =>
            {
                var v = (T)cacheEntry.ValueInternal;
                foreach (var proxy in GetProxies <T>(cacheEntry.LoadContext))
                {
                    // copy the values over
                    //
                    ReflectionSerializer.UpdateObject(v, proxy.ProxyReference.Target, true, null);

                    // fire the update notification
                    //
                    if (proxy.UpdateAction != null)
                    {
                        proxy.UpdateAction();
                    }
                }
            };

            // create a new one.
            //
            value = new CacheEntry(loadContext, objectType, proxyCallback);
            value.NextCompletedAction.UnhandledError = OnUnhandledError;

            object loader = GetDataLoader(value);

            // How to create a new value.  It's just a new.
            //
            value.CreateDefaultAction = () =>
            {
                // if there is a proxy already registered, use it as the key value.
                //
                var proxy = GetProxies <T>(loadContext).FirstOrDefault();

                if (proxy != null && proxy.ProxyReference != null && proxy.ProxyReference.IsAlive)
                {
                    return(proxy.ProxyReference.Target);
                }

                var item = new T();

                if (item is ILoadContextItem)
                {
                    ((ILoadContextItem)item).LoadContext = value.LoadContext;
                }

                return(item);
            };

            SetupCompletedCallback <T>(completed, error, value);

            // How to load a new value.
            //
            value.LoadAction = (lvl) =>
            {
                if (loader == null)
                {
                    throw new InvalidOperationException("Could not find loader for type: " + typeof(T).Name);
                }
                // get a loader and ask for a load request.
                //
                Debug.Assert(loader != null, "Failed to get loader for " + typeof(T).Name);
                var request = DataLoaderProxy.GetLoadRequest(loader, value.LoadContext, typeof(T));

                if (request == null)
                {
                    Debug.WriteLine("{0}: Aborting load for {1}, ID={2}, because {3}.GetLoadRequest returned null.", DateTime.Now, typeof(T).Name, value.LoadContext.Identity, loader.GetType().Name);
                    return(false);
                }

                // fire off the load.
                //
                IsLoading = true;
                request.Execute(
                    (result) =>
                {
                    if (result == null)
                    {
                        throw new ArgumentNullException("result", "Execute must return a LoadRequestResult value.");
                    }
                    if (result.Error == null)
                    {
                        lvl.OnLoadSuccess(result.Stream);
                    }
                    else
                    {
                        lvl.OnLoadFail(new LoadRequestFailedException(lvl.CacheEntry.ObjectType, value.LoadContext, result.Error));
                    }
                    IsLoading = false;
                }
                    );
                return(true);
            };



            // how to deserialize.
            value.DeserializeAction = (id, data, isOptimized) =>
            {
                if (loader == null)
                {
                    throw new InvalidOperationException("Could not find loader for type: " + typeof(T).Name);
                }

                // get the loader and ask for deserialization
                //
                object deserializedObject = null;

                if (isOptimized)
                {
                    var idl = (IDataOptimizer)loader;

                    if (idl == null)
                    {
                        throw new InvalidOperationException("Data is optimized but object does not implmenent IDataOptimizer");
                    }
                    deserializedObject = idl.DeserializeOptimizedData(value.LoadContext, objectType, data);
                }
                else
                {
                    deserializedObject = DataLoaderProxy.Deserialize(loader, value.LoadContext, objectType, data);
                }

                if (deserializedObject == null)
                {
                    throw new InvalidOperationException(String.Format("Deserialize returned null for {0}, id='{1}'", objectType.Name, id));
                }

                if (!objectType.IsInstanceOfType(deserializedObject))
                {
                    throw new InvalidOperationException(String.Format("Returned object is {0} when {1} was expected", deserializedObject.GetType().Name, objectType.Name));
                }
                return(deserializedObject);
            };

            // if this thing knows how to optimize, hook that up.
            //
            if (loader is IDataOptimizer)
            {
                value.SerializeOptimizedDataAction = (obj, stream) =>
                {
                    var idl = (IDataOptimizer)loader;
                    return(idl.SerializeOptimizedData(obj, stream));
                };
            }

            // finally push the value into the cache.

            lock (_objectCache) {
                if (!_objectCache.ContainsKey(objectType))
                {
                    Dictionary <object, CacheEntry> typeDictionary = new Dictionary <object, CacheEntry>();
                    _objectCache[typeof(T)] = typeDictionary;
                }
                _objectCache[typeof(T)][identity] = value;
            }
            return(value);
        }
Esempio n. 3
0
        /// <summary>
        /// Merge a list of items with the contents of this ObsColl.
        ///
        /// IMPORTANT: This method assumes that the contents of the this list are sorted
        /// in the same sort order as specified by the compare action.
        ///
        /// If they are not, then the resulting list is likely to be wrong.
        /// </summary>
        /// <param name="newItems">The new list of ites</param>
        /// <param name="compare">The comparison function between two items</param>
        /// <param name="itemMergeBehavior">The way toi handle equivlent items.</param>
        public void Merge(IList <T> newItems, Comparison <T> compare, EquivelentItemMergeBehavior itemMergeBehavior)
        {
            // Shortcuts for 0 items
            //
            if (newItems == null || newItems.Count == 0)
            {
                ClearItems();
                return;
            }

            if (Count == 0)
            {
                AddRange(newItems);
                return;
            }

            CancelBatch();


            var sortedExisting = this; // we have to assume the list is currently sorted by the specified comparer.

            // sort the newArray
            var sortedNew = newItems.ToArray();

            Array.Sort <T>(sortedNew, compare);

            int currentPos = 0;

            // Now walk each item in the new array and compare it against the current
            // items in the collection.
            //
            foreach (var newItem in sortedNew)
            {
                T existingItem = default(T);

                // if we're past the end of the old list,
                // just start adding.
                //
                if (currentPos < Count)
                {
                    existingItem = this[currentPos];
                }
                else
                {
                    Add(newItem);
                    continue;
                }

                int compareResult = compare(newItem, existingItem);

                if (compareResult == 0)
                {
                    // we found the match, so just replace the item
                    // or do nothing.
                    //
                    bool isSameObject = Object.Equals(existingItem, newItem);
                    if (isSameObject)
                    {
                        switch (itemMergeBehavior)
                        {
                        case EquivelentItemMergeBehavior.ReplaceEqualItems:
                            this[currentPos] = newItem;
                            break;

                        case EquivelentItemMergeBehavior.UpdateEqualItems:
                            ReflectionSerializer.UpdateObject(newItem, existingItem, true, null);
                            break;

                        default:
                            break;
                        }
                    }
                    else
                    {
                        // TODO: WRITE TEST FOR THIS CASE
                        // something compared as equal, but it's a different object
                        // so insert the new one before the existing one.
                        //
                        this.Insert(currentPos, newItem);
                    }
                    currentPos++;
                }
                else if (compareResult < 0)
                {
                    // the new item comes before the existing item, so add it.
                    //
                    this.Insert(currentPos, newItem);
                    currentPos++;
                }
                else if (compareResult > 0)
                {
                    // the new item should come after this item,
                    // so just replace the current item with our new item.
                    //
                    this[currentPos] = newItem;
                    currentPos++;
                }
            }

            // remove any that are left in the old list.
            //
            for (int i = this.Count - 1; i >= currentPos; i--)
            {
                this.RemoveAt(i);
            }
        }