// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using Microsoft.SqlTools.Hosting.Utility; using Microsoft.SqlTools.Hosting.v2; namespace Microsoft.SqlTools.Hosting.Extensibility { /// /// A service provider implementation that allows registering of specific services /// public class RegisteredServiceProvider : ServiceProviderBase { public delegate IEnumerable ServiceLookup(); protected readonly Dictionary services = new Dictionary(); /// /// Registers a singular service to be returned during lookup /// /// /// this provider, to simplify fluent declarations /// If service is null /// If an existing service is already registered public virtual RegisteredServiceProvider RegisterSingleService(T service) { Validate.IsNotNull(nameof(service), service); ThrowIfAlreadyRegistered(); services.Add(typeof(T), () => service.AsSingleItemEnumerable()); return this; } /// /// Registers a singular service to be returned during lookup /// /// /// Type or interface this service should be registed as. Any request /// for that type will return this service /// /// service object to be added /// this provider, to simplify fluent declarations /// If service is null /// If an existing service is already registered public virtual RegisteredServiceProvider RegisterSingleService(Type type, object service) { Validate.IsNotNull(nameof(type), type); Validate.IsNotNull(nameof(service), service); ThrowIfAlreadyRegistered(type); ThrowIfIncompatible(type, service); services.Add(type, service.AsSingleItemEnumerable); return this; } /// /// Registers a function that can look up multiple services /// /// /// this provider, to simplify fluent declarations /// If is null /// If an existing service is already registered public virtual RegisteredServiceProvider Register(Func> serviceLookup) { Validate.IsNotNull(nameof(serviceLookup), serviceLookup); ThrowIfAlreadyRegistered(); services.Add(typeof(T), () => serviceLookup()); return this; } public virtual void RegisterHostedServices() { // Register all hosted services the service provider for their requested service type. // This ensures that when searching for the ConnectionService (eg) you can get it // without searching for an IHosted service of type ConnectionService foreach (IHostedService service in GetServices()) { RegisterSingleService(service.ServiceType, service); } } private void ThrowIfAlreadyRegistered() { ThrowIfAlreadyRegistered(typeof(T)); } private void ThrowIfAlreadyRegistered(Type type) { if (services.ContainsKey(type)) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.ServiceAlreadyRegistered, type.Name)); } } private void ThrowIfIncompatible(Type type, object service) { if (!type.IsInstanceOfType(service)) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.ServiceNotOfExpectedType, service.GetType().Name, type.Name)); } } protected override IEnumerable GetServicesImpl() { ServiceLookup serviceLookup; if (services.TryGetValue(typeof(T), out serviceLookup)) { return serviceLookup().Cast(); } return Enumerable.Empty(); } } }