Пример #1
0
        /// <summary>
        /// Generic implementation of the get methods for the particular
        /// <see cref="IFilter"/> provided.
        /// </summary>
        /// <param name="cache">
        /// The <see cref="ICache"/> to be queried.
        /// </param>
        /// <param name="dictIndex">
        /// The <see cref="IDictionary"/> of indexes.
        /// </param>
        /// <param name="filter">
        /// The <see cref="IFilter"/> object representing the criteria that
        /// the entries of this cache should satisfy.
        /// </param>
        /// <param name="queryType">
        /// An enum value that defines whether return array should be values,
        /// keys or entries.
        /// </param>
        /// <param name="sort">
        /// If <b>true</b>, sort the result-set before returning.
        /// </param>
        /// <param name="comparer">
        /// The <see cref="IComparer"/> to use for sorting (optional).
        /// </param>
        /// <returns>
        /// A collection of the keys/values for entries that satisfy the
        /// specified criteria.
        /// </returns>
        public static object[] Query(ICache cache, IDictionary dictIndex,
                                     IFilter filter, QueryType queryType, bool sort, IComparer comparer)
        {
            IFilter filterOrig = filter;

            if (AlwaysFilter.Instance.Equals(filter))
            {
                filter = null;
            }

            object[] results; // may contain keys, values, or entries

            // try to apply an index (if available)
            if (dictIndex != null && filter is IIndexAwareFilter)
            {
                // take a thread-safe snapshot of the cache key set; this
                // differs a from the Java version in which the Set interface,
                // SubSet class, and thread-safe Collection.toArray() methods
                // are at our disposal
                ICollection keys;
                CollectionUtils.AcquireReadLock(cache);
                try
                {
                    keys = new HashSet(cache.Keys);
                }
                finally
                {
                    CollectionUtils.ReleaseReadLock(cache);
                }

                filter  = ((IIndexAwareFilter)filter).ApplyIndex(dictIndex, keys);
                results = CollectionUtils.ToArray(keys);
            }
            else
            {
                // perform a thread-safe conversion of the cache key set into
                // an object array; again, this differs a bit from the Java
                // version
                CollectionUtils.AcquireReadLock(cache);
                try
                {
                    results = CollectionUtils.ToArray(cache.Keys);
                }
                finally
                {
                    CollectionUtils.ReleaseReadLock(cache);
                }
            }

            int resultCount = 0;

            if (filter == null && queryType == QueryType.Keys)
            {
                resultCount = results.Length;
            }
            else
            {
                // we still have a filter to evaluate or we need an entry set
                // or values collection
                for (int i = 0, c = results.Length; i < c; i++)
                {
                    var key   = results[i];
                    var value = cache[key];

                    if (value != null || cache.Contains(key))
                    {
                        ICacheEntry entry = new CacheEntry(key, value);
                        if (filter == null || EvaluateEntry(filter, entry))
                        {
                            object result;
                            switch (queryType)
                            {
                            case QueryType.Entries:
                                result = entry;
                                break;

                            case QueryType.Keys:
                                result = key;
                                break;

                            default:
                                result = value;
                                break;
                            }
                            results[resultCount++] = result;
                        }
                    }
                }
            }

            // convert the result array into an array of the appropriate
            // type and length; this differs from the Java version in which
            // this method returns a Set and not an array
            if (queryType == QueryType.Entries)
            {
                var entries = new ICacheEntry[resultCount];
                Array.Copy(results, 0, entries, 0, resultCount);
                results = entries;
            }
            else if (resultCount < results.Length)
            {
                var newResults = new object[resultCount];
                Array.Copy(results, 0, newResults, 0, resultCount);
                results = newResults;
            }

            // sort the results; this differs from the Java version in which
            // this method only can return keys or entries (and not values)
            if (sort)
            {
                if (comparer == null)
                {
                    comparer = SafeComparer.Instance;
                }
                if (queryType == QueryType.Entries)
                {
                    comparer = new EntryComparer(comparer);
                }
                Array.Sort(results, 0, resultCount, comparer);
            }

            // if the original filter is a LimitFilter then we can only return
            // a page at a time
            if (filterOrig is LimitFilter)
            {
                var filterLimit = filterOrig as LimitFilter;
                filterLimit.Comparer = null;

                results              = filterLimit.ExtractPage(results);
                resultCount          = results.Length;
                filterLimit.Comparer = comparer; // for debug output only
            }

            // convert the result array into an array of the appropriate
            // type and length; this differs from the Java version in which
            // this method returns a Set and not an array
            if (queryType == QueryType.Entries)
            {
                var entries = new ICacheEntry[resultCount];
                Array.Copy(results, 0, entries, 0, resultCount);
                results = entries;
            }
            else if (resultCount < results.Length)
            {
                var newResults = new object[resultCount];
                Array.Copy(results, 0, newResults, 0, resultCount);
                results = newResults;
            }

            return(results);
        }