//
// 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();
}
}
}