/// <summary> /// Reloads the internal SPI list. /// Changes to the service list are visible after the method ends, all /// iterators (e.g, from <see cref="AvailableServices"/>,...) stay consistent. /// /// <para/><b>NOTE:</b> Only new service providers are added, existing ones are /// never removed or replaced. /// /// <para/><em>this method is expensive and should only be called for discovery /// of new service providers on the given classpath/classloader!</em> /// </summary> public void Reload() { UninterruptableMonitor.Enter(this); try { IDictionary <string, Type> services = new JCG.LinkedDictionary <string, Type>(this.services); SPIClassIterator <S> loader = SPIClassIterator <S> .Get(); foreach (var service in loader) { string clazzName = service.Name; string name = null; foreach (string suffix in suffixes) { if (clazzName.EndsWith(suffix, StringComparison.Ordinal)) { name = clazzName.Substring(0, clazzName.Length - suffix.Length).ToLowerInvariant(); break; } } if (name is null) { throw ServiceConfigurationError.Create("The class name " + service.Name + " has wrong suffix, allowed are: " + Arrays.ToString(suffixes)); } // only add the first one for each name, later services will be ignored // this allows to place services before others in classpath to make // them used instead of others // // TODO: Should we disallow duplicate names here? // Allowing it may get confusing on collisions, as different packages // could contain same factory class, which is a naming bug! // When changing this be careful to allow reload()! if (!services.ContainsKey(name)) { services.Add(name, service); } } this.services = services.AsReadOnly(); } finally { UninterruptableMonitor.Exit(this); } }
/// <summary> /// Reloads the internal SPI list. /// Changes to the service list are visible after the method ends, all /// iterators (e.g, from <see cref="AvailableServices"/>,...) stay consistent. /// /// <para/><b>NOTE:</b> Only new service providers are added, existing ones are /// never removed or replaced. /// /// <para/><em>this method is expensive and should only be called for discovery /// of new service providers on the given classpath/classloader!</em> /// </summary> public void Reload() { lock (this) { IDictionary <string, Type> services = new LinkedHashMap <string, Type>(this.services); SPIClassIterator <S> loader = SPIClassIterator <S> .Get(); foreach (var service in loader) { string clazzName = service.Name; string name = null; foreach (string suffix in suffixes) { if (clazzName.EndsWith(suffix, StringComparison.Ordinal)) { name = clazzName.Substring(0, clazzName.Length - suffix.Length).ToLowerInvariant(); break; } } if (name == null) { throw new InvalidOperationException("The class name " + service.Name + " has wrong suffix, allowed are: " + Arrays.ToString(suffixes)); } // only add the first one for each name, later services will be ignored // this allows to place services before others in classpath to make // them used instead of others // // LUCENETODO: Should we disallow duplicate names here? // Allowing it may get confusing on collisions, as different packages // could contain same factory class, which is a naming bug! // When changing this be careful to allow reload()! if (!services.ContainsKey(name)) { services.Add(name, service); } } this.services = Collections.UnmodifiableMap(services); } }