示例#1
0
        public virtual object GetKey(ICUServiceKey key, IServiceFactory factory, out string actualReturn)
        {
            if (factories.Count == 0)
            {
                return(HandleDefault(key, out actualReturn));
            }

            var result = GetKeyCacheEntry(key, factory);

            if (result != null)
            {
                // strip null prefix
                if (result.actualDescriptor.IndexOf('/') == 0)
                {
                    actualReturn = result.actualDescriptor.Substring(1);
                }
                else
                {
                    actualReturn = result.actualDescriptor;
                }

                return(result.service);
            }

            return(HandleDefault(key, out actualReturn));
        }
示例#2
0
 /// <summary>
 /// Return the service instance if the factory's id is equal to
 /// the <paramref name="key"/>'s <see cref="ICUServiceKey.CurrentID"/>.
 /// <paramref name="service"/> is ignored.
 /// </summary>
 public virtual object Create(ICUServiceKey key, ICUService service)
 {
     if (id.Equals(key.CurrentID))
     {
         return(instance);
     }
     return(null);
 }
示例#3
0
        /// <summary>
        /// Return a snapshot of the mapping from display names to visible
        /// IDs for this service.  This set will not change as factories
        /// are added or removed, but the supported ids will, so there is
        /// no guarantee that all and only the ids in the returned map will
        /// be visible and supported by the service in subsequent calls,
        /// nor is there any guarantee that the current display names match
        /// those in the set.  The display names are sorted based on the
        /// comparer provided.
        /// </summary>
        public virtual IDictionary <string, string> GetDisplayNames(UCultureInfo locale, IComparer <string> com, string matchID)
        {
            IDictionary <string, string> dncache = null;
            LocaleRef reference = dnref;

            if (reference != null)
            {
                dncache = reference.Get(locale, com);
            }

            while (dncache == null)
            {
                lock (syncLock)
                {
                    if (reference == dnref || dnref == null)
                    {
                        dncache = new SortedDictionary <string, string>(com); // sorted

                        foreach (var e in GetVisibleIDMap())
                        {
                            string          id = e.Key;
                            IServiceFactory f  = e.Value;
                            dncache[f.GetDisplayName(id, locale)] = id;
                        }

                        dncache = dncache.AsReadOnly();
                        dnref   = new LocaleRef(dncache, locale, com);
                    }
                    else
                    {
                        reference = dnref;
                        dncache   = reference.Get(locale, com);
                    }
                }
            }

            ICUServiceKey matchKey = CreateKey(matchID);

            if (matchKey == null)
            {
                return(dncache.AsReadOnly());
            }

            // ICU4N: Rather than copying and then removing the items (which isn't allowed with
            // .NET iterators), we reverse the logic and add the items only if they are fallback.
            IDictionary <string, string> result = new SortedDictionary <string, string>(com);

            foreach (var e in dncache)
            {
                if (matchKey.IsFallbackOf(e.Value))
                {
                    result.Add(e.Key, e.Value);
                }
            }
            return(result);
        }
示例#4
0
 protected virtual bool HandlesKey(ICUServiceKey key)
 {
     if (key != null)
     {
         string id = key.CurrentID;
         ICollection <string> supported = GetSupportedIDs();
         return(supported.Contains(id));
     }
     return(false);
 }
示例#5
0
        // debugging
        // Map hardRef;

        public virtual object GetKey(ICUServiceKey key, IServiceFactory factory)
        {
            if (factories.Count == 0)
            {
                return(HandleDefault(key, out _));
            }

            var result = GetKeyCacheEntry(key, factory);

            return((result != null) ? result.service : HandleDefault(key, out _));
        }
示例#6
0
        /// <summary>
        /// Implement superclass abstract method.  This checks the <see cref="ICUServiceKey.CurrentID"/>
        /// against the supported IDs, and passes the canonicalLocale and
        /// <see cref="LocaleKey.Kind"/> to <see cref="HandleCreate(UCultureInfo, int, ICUService)"/> (which subclasses must implement).
        /// </summary>
        public virtual object Create(ICUServiceKey key, ICUService service)
        {
            if (HandlesKey(key))
            {
                LocaleKey lkey = (LocaleKey)key;
                int       kind = lkey.Kind;

                UCultureInfo uloc = lkey.GetCurrentCulture();
                return(HandleCreate(uloc, kind, service));
            }
            else
            {
                // System.out.println("factory: " + this + " did not support id: " + key.currentID());
                // System.out.println("supported ids: " + getSupportedIDs());
            }
            return(null);
        }
示例#7
0
        /// <summary>
        /// Convenience override for callers using locales.  This uses
        /// <see cref="CreateKey(string, int)"/> to create a key, calls
        /// <see cref="ICUService.GetKey(ICUServiceKey)"/>, and then
        /// returns the <paramref name="actualResult"/> from
        /// <see cref="ICUService.GetKey(ICUServiceKey)"/> (stripping any prefix)
        /// into a <see cref="UCultureInfo"/>.
        /// </summary>
        /// <param name="locale"></param>
        /// <param name="kind"></param>
        /// <param name="actualResult"></param>
        /// <returns></returns>
        public virtual object Get(UCultureInfo locale, int kind, out UCultureInfo actualResult)
        {
            actualResult = null;
            ICUServiceKey key = CreateKey(locale, kind);

            object result = GetKey(key, out string temp);

            if (result != null)
            {
                int n = temp.IndexOf('/');
                if (n >= 0)
                {
                    temp = temp.Substring(n + 1);
                }
                actualResult = new UCultureInfo(temp);
            }
            return(result);
        }
示例#8
0
        /// <summary>
        /// Returns the service object if kind/locale match.  Service is not used.
        /// </summary>
        public override object Create(ICUServiceKey key, ICUService service)
        {
            if (!(key is LocaleKey))
            {
                return(null);
            }

            LocaleKey lkey = (LocaleKey)key;

            if (kind != LocaleKey.KindAny && kind != lkey.Kind)
            {
                return(null);
            }
            if (!id.Equals(lkey.CurrentID))
            {
                return(null);
            }

            return(obj);
        }
示例#9
0
        /// <summary>
        /// Return a snapshot of the visible IDs for this service.  This
        /// set will not change as Factories are added or removed, but the
        /// supported ids will, so there is no guarantee that all and only
        /// the ids in the returned set are visible and supported by the
        /// service in subsequent calls.
        /// <para/>
        /// <paramref name="matchID"/> is passed to <see cref="CreateKey(string)"/> to create a key.  If the
        /// key is not null, it is used to filter out ids that don't have
        /// the key as a fallback.
        /// </summary>
        public virtual ICollection <string> GetVisibleIDs(string matchID) // ICU4N specific - changed return type from ISet to ICollection to avoid O(n)
        {
            ICollection <string> result = GetVisibleIDMap().Keys;

            ICUServiceKey fallbackKey = CreateKey(matchID);

            if (fallbackKey != null)
            {
                ISet <string> temp = new HashSet <string>(/*result.Count*/);
                foreach (string id in result)
                {
                    if (fallbackKey.IsFallbackOf(id))
                    {
                        temp.Add(id);
                    }
                }
                result = temp;
            }
            return(result);
        }
示例#10
0
        /// <summary>
        /// Given a visible <paramref name="id"/>, return the display name in the requested <paramref name="locale"/>.
        /// If there is no directly supported id corresponding to this id, return
        /// null.
        /// </summary>
        public virtual string GetDisplayName(string id, UCultureInfo locale)
        {
            IDictionary <string, IServiceFactory> m = GetVisibleIDMap();

            if (m.TryGetValue(id, out IServiceFactory f) && f != null)
            {
                return(f.GetDisplayName(id, locale));
            }

            ICUServiceKey key = CreateKey(id);

            while (key.Fallback())
            {
                if (m.TryGetValue(key.CurrentID, out f) && f != null)
                {
                    return(f.GetDisplayName(id, locale));
                }
            }

            return(null);
        }
示例#11
0
        /// <summary>
        /// Return a snapshot of the visible IDs for this service.  This
        /// set will not change as Factories are added or removed, but the
        /// supported ids will, so there is no guarantee that all and only
        /// the ids in the returned set are visible and supported by the
        /// service in subsequent calls.
        /// <para/>
        /// <paramref name="matchID"/> is passed to <see cref="CreateKey(string)"/> to create a key.  If the
        /// key is not null, it is used to filter out ids that don't have
        /// the key as a fallback.
        /// </summary>
        public virtual ICollection <string> GetVisibleIDs(string matchID) // ICU4N specific - changed return type from ISet to ICollection to avoid O(n)
        {
            ICollection <string> result = GetVisibleIDMap().Keys;

            ICUServiceKey fallbackKey = CreateKey(matchID);

            if (fallbackKey != null)
            {
                // ICU4N: We don't need the overhead of HashSet here, since we are pulling
                // keys from a dictionary.
                var temp = new List <string>(result.Count);
                foreach (string id in result)
                {
                    if (fallbackKey.IsFallbackOf(id))
                    {
                        temp.Add(id);
                    }
                }
                result = temp;
            }
            return(result);
        }
示例#12
0
        /// <summary>
        /// Given a visible <paramref name="id"/>, return the display name in the requested <paramref name="locale"/>.
        /// If there is no directly supported id corresponding to this id, return
        /// null.
        /// </summary>
        public virtual string GetDisplayName(string id, ULocale locale)
        {
            IDictionary <string, IServiceFactory> m = GetVisibleIDMap();
            IServiceFactory f = m.Get(id);

            if (f != null)
            {
                return(f.GetDisplayName(id, locale));
            }

            ICUServiceKey key = CreateKey(id);

            while (key.Fallback())
            {
                f = m.Get(key.CurrentID);
                if (f != null)
                {
                    return(f.GetDisplayName(id, locale));
                }
            }

            return(null);
        }
示例#13
0
        /// <summary>
        /// Convenience override for callers using locales.  This uses
        /// <see cref="CreateKey(string, int)"/> to create a key, calls
        /// <see cref="ICUService.GetKey(ICUServiceKey)"/>, and then
        /// if <paramref name="actualReturn"/> is not null, returns the actualResult from
        /// <see cref="ICUService.GetKey(ICUServiceKey)"/> (stripping any prefix) into a <see cref="ULocale"/>.
        /// </summary>
        /// <param name="locale"></param>
        /// <param name="kind"></param>
        /// <param name="actualReturn"></param>
        /// <returns></returns>
        public virtual object Get(ULocale locale, int kind, ULocale[] actualReturn)
        {
            ICUServiceKey key = CreateKey(locale, kind);

            if (actualReturn == null)
            {
                return(GetKey(key));
            }

            string[] temp   = new string[1];
            object   result = GetKey(key, temp);

            if (result != null)
            {
                int n = temp[0].IndexOf('/');
                if (n >= 0)
                {
                    temp[0] = temp[0].Substring(n + 1);
                }
                actualReturn[0] = new ULocale(temp[0]);
            }
            return(result);
        }
示例#14
0
        /// <summary>
        /// Convenience override for callers using locales. This uses
        /// <see cref="CreateKey(string, int)"/> to create a key, and returns the result of
        /// <see cref="ICUService.GetKey(ICUServiceKey)"/>.
        /// </summary>
        /// <param name="locale"></param>
        /// <param name="kind"></param>
        /// <returns></returns>
        public virtual object Get(UCultureInfo locale, int kind)
        {
            ICUServiceKey key = CreateKey(locale, kind);

            return(GetKey(key));
        }
示例#15
0
 /// <summary>
 /// Convenience override for <see cref="GetKey(ICUServiceKey, out string)"/>.
 /// </summary>
 public virtual object GetKey(ICUServiceKey key)
 {
     return(GetKey(key, out _));
 }
示例#16
0
 /// <summary>
 /// Given a <paramref name="key"/>, return a service object, and, if <paramref name="actualReturn"/>
 /// is not null, the descriptor with which it was found in the
 /// first element of <paramref name="actualReturn"/>.  If no service object matches
 /// this key, return null, and leave <paramref name="actualReturn"/> unchanged.
 /// </summary>
 /// <remarks>
 /// This queries the cache using the <paramref name="key"/>'s descriptor, and if no
 /// object in the cache matches it, tries the <paramref name="key"/> on each
 /// registered factory, in order.  If none generates a service
 /// object for the key, repeats the process with each fallback of
 /// the <paramref name="key"/>, until either one returns a service object, or the <paramref name="key"/>
 /// has no fallback.
 /// <para/>
 /// If <paramref name="key"/> is null, just returns null.
 /// </remarks>
 public virtual object GetKey(ICUServiceKey key, string[] actualReturn)
 {
     return(GetKey(key, actualReturn, null));
 }
示例#17
0
 /// <summary>
 /// Default handler for this service if no factory in the list
 /// handled the <paramref name="key"/>.
 /// </summary>
 protected virtual object HandleDefault(ICUServiceKey key, out string actualIDReturn)
 {
     actualIDReturn = null;
     return(null);
 }
示例#18
0
        private CacheEntry GetKeyCacheEntry(ICUServiceKey key, IServiceFactory factory)
        {
            if (DEBUG)
            {
                Console.Out.WriteLine("Service: " + m_name + " key: " + key.CanonicalID);
            }

            if (key != null)
            {
                try
                {
                    // The factory list can't be modified until we're done,
                    // otherwise we might update the cache with an invalid result.
                    // The cache has to stay in synch with the factory list.
                    factoryLock.AcquireRead();

                    IDictionary <string, CacheEntry> cache = this.cache; // copy so we don't need to sync on this
                    if (cache == null)
                    {
                        if (DEBUG)
                        {
                            Console.Out.WriteLine("Service " + m_name + " cache was empty");
                        }
                        // synchronized since additions and queries on the cache must be atomic
                        // they can be interleaved, though
                        cache = new ConcurrentDictionary <string, CacheEntry>();
                    }

                    string        currentDescriptor   = null;
                    List <string> cacheDescriptorList = null;
                    bool          putInCache          = false;

                    int NDebug = 0;

                    int  startIndex  = 0;
                    int  limit       = factories.Count;
                    bool cacheResult = true;
                    if (factory != null)
                    {
                        for (int i = 0; i < limit; ++i)
                        {
                            if (factory == factories[i])
                            {
                                startIndex = i + 1;
                                break;
                            }
                        }
                        if (startIndex == 0)
                        {
                            throw new InvalidOperationException("Factory " + factory + "not registered with service: " + this);
                        }
                        cacheResult = false;
                    }


                    CacheEntry result;
                    //outer:
                    do
                    {
                        currentDescriptor = key.GetCurrentDescriptor();
                        if (DEBUG)
                        {
                            Console.Out.WriteLine(m_name + "[" + NDebug++ + "] looking for: " + currentDescriptor);
                        }
                        if (cache.TryGetValue(currentDescriptor, out result) && result != null)
                        {
                            if (DEBUG)
                            {
                                Console.Out.WriteLine(m_name + " found with descriptor: " + currentDescriptor);
                            }
                            goto outer_break;
                        }
                        else
                        {
                            if (DEBUG)
                            {
                                Console.Out.WriteLine("did not find: " + currentDescriptor + " in cache");
                            }
                        }

                        // first test of cache failed, so we'll have to update
                        // the cache if we eventually succeed-- that is, if we're
                        // going to update the cache at all.
                        putInCache = cacheResult;

                        //  int n = 0;
                        int index = startIndex;
                        while (index < limit)
                        {
                            IServiceFactory f = factories[index++];
                            if (DEBUG)
                            {
                                Console.Out.WriteLine("trying factory[" + (index - 1) + "] " + f.ToString());
                            }
                            object service = f.Create(key, this);
                            if (service != null)
                            {
                                result = new CacheEntry(currentDescriptor, service);
                                if (DEBUG)
                                {
                                    Console.Out.WriteLine(m_name + " factory supported: " + currentDescriptor + ", caching");
                                }
                                goto outer_break;
                            }
                            else
                            {
                                if (DEBUG)
                                {
                                    Console.Out.WriteLine("factory did not support: " + currentDescriptor);
                                }
                            }
                        }

                        // prepare to load the cache with all additional ids that
                        // will resolve to result, assuming we'll succeed.  We
                        // don't want to keep querying on an id that's going to
                        // fallback to the one that succeeded, we want to hit the
                        // cache the first time next goaround.
                        if (cacheDescriptorList == null)
                        {
                            cacheDescriptorList = new List <string>(5);
                        }
                        cacheDescriptorList.Add(currentDescriptor);
                    } while (key.Fallback());
                    outer_break : { }

                    if (result != null)
                    {
                        if (putInCache)
                        {
                            if (DEBUG)
                            {
                                Console.Out.WriteLine("caching '" + result.actualDescriptor + "'");
                            }
                            cache[result.actualDescriptor] = result;
                            if (cacheDescriptorList != null)
                            {
                                foreach (string desc in cacheDescriptorList)
                                {
                                    if (DEBUG)
                                    {
                                        Console.Out.WriteLine(m_name + " adding descriptor: '" + desc + "' for actual: '" + result.actualDescriptor + "'");
                                    }

                                    cache[desc] = result;
                                }
                            }
                            // Atomic update.  We held the read lock all this time
                            // so we know our cache is consistent with the factory list.
                            // We might stomp over a cache that some other thread
                            // rebuilt, but that's the breaks.  They're both good.
                            this.cache = cache;
                        }

                        if (DEBUG)
                        {
                            Console.Out.WriteLine("found in service: " + m_name);
                        }

                        return(result);
                    }
                }
                finally
                {
                    factoryLock.ReleaseRead();
                }
            }

            if (DEBUG)
            {
                Console.Out.WriteLine("not found in service: " + m_name);
            }

            return(null);
        }
示例#19
0
 /// <summary>
 /// Default handler for this service if no factory in the list
 /// handled the <paramref name="key"/>.
 /// </summary>
 protected virtual object HandleDefault(ICUServiceKey key, string[] actualIDReturn)
 {
     return(null);
 }
示例#20
0
 /// <summary>
 /// Given a <paramref name="key"/>, return a service object, and the descriptor with which
 /// it was found in the <paramref name="actualReturn"/>. If no service object matches
 /// this key, return <c>null</c>, and leave <paramref name="actualReturn"/> <c>null</c>.
 /// </summary>
 /// <remarks>
 /// This queries the cache using the <paramref name="key"/>'s descriptor, and if no
 /// object in the cache matches it, tries the <paramref name="key"/> on each
 /// registered factory, in order.  If none generates a service
 /// object for the <paramref name="key"/>, repeats the process with each fallback of
 /// the <paramref name="key"/>, until either one returns a service object, or the <paramref name="key"/>
 /// has no fallback.
 /// <para/>
 /// If <paramref name="key"/> is <c>null</c>, just returns <c>null</c>.
 /// </remarks>
 public virtual object GetKey(ICUServiceKey key, out string actualReturn)
 {
     return(GetKey(key, null, out actualReturn));
 }