mixedreality/com.microsoft.mixedreality..../SDK/Experimental/ServiceManagers/Support/Scripts/BaseServiceManager.cs

272 lines
9.9 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Experimental
{
/// <summary>
/// Base class providing service registration and management functionality. This class can be used to implement a
/// custom service management component for one or more services, similar to the MixedRealityToolkit object.
/// </summary>
[AddComponentMenu("Scripts/MRTK/SDK/BaseServiceManager")]
public class BaseServiceManager : MonoBehaviour, IMixedRealityServiceRegistrar
{
/// <summary>
/// The collection of registered services.
/// </summary>
protected Dictionary<Type, IMixedRealityService> registeredServices = new Dictionary<Type, IMixedRealityService>();
#region MonoBehaviour implementation
protected virtual void Update()
{
if (Application.isPlaying)
{
foreach (IMixedRealityService service in registeredServices.Values)
{
service.Update();
}
}
}
private void LateUpdate()
{
if (Application.isPlaying)
{
if (Application.isPlaying)
{
foreach (IMixedRealityService service in registeredServices.Values)
{
service.LateUpdate();
}
}
}
}
protected virtual void OnEnable()
{
if (Application.isPlaying)
{
foreach (IMixedRealityService service in registeredServices.Values)
{
service.Enable();
}
}
}
protected virtual void OnDisable()
{
if (Application.isPlaying)
{
foreach (IMixedRealityService service in registeredServices.Values)
{
service.Disable();
}
}
}
protected virtual void OnDestroy()
{
foreach (IMixedRealityService service in registeredServices.Values)
{
service.Disable(); // Disable before destroy to ensure the service has time to get in a good state.
service.Destroy();
}
registeredServices.Clear();
}
#endregion MonoBehaviour implementation
#region IMixedRealityServiceRegistrar implementation
/// <inheritdoc />
public T GetService<T>(string name = null, bool showLogs = true) where T : IMixedRealityService
{
T serviceInstance = FindService<T>(name);
if (showLogs && (serviceInstance == null))
{
Debug.LogError($"Failed to get the requested service of type {typeof(T)}.");
}
return serviceInstance;
}
/// <inheritdoc />
public IReadOnlyList<T> GetServices<T>(string name = null) where T : IMixedRealityService
{
Type interfaceType = typeof(T);
List<T> matchingServices = new List<T>();
foreach (IMixedRealityService service in registeredServices.Values)
{
if (!interfaceType.IsAssignableFrom(service.GetType())) { continue; }
// If a name has been provided and if it matches the services's name, add the service.
if (!string.IsNullOrWhiteSpace(name) && string.Equals(service.Name, name))
{
matchingServices.Add((T)service);
}
// If no name has been specified, always add the service.
else
{
matchingServices.Add((T)service);
}
}
return matchingServices;
}
/// <inheritdoc />
public bool IsServiceRegistered<T>(string name = null) where T : IMixedRealityService
{
return (GetService<T>(name) != null);
}
/// <inheritdoc />
public bool RegisterService<T>(T serviceInstance) where T : IMixedRealityService
{
Type interfaceType = typeof(T);
if (registeredServices.ContainsKey(interfaceType))
{
Debug.LogError($"Failed to register {serviceInstance} service. There is already a registered service implementing {interfaceType}");
return false;
}
bool registered = MixedRealityServiceRegistry.AddService<T>(serviceInstance, this);
if (registered)
{
registeredServices.Add(interfaceType, serviceInstance);
}
return registered;
}
/// <inheritdoc />
public bool RegisterService<T>(Type concreteType, SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1), params object[] args) where T : IMixedRealityService
{
T serviceInstance = ActivateInstance<T>(concreteType, supportedPlatforms, args);
if (serviceInstance == null)
{
return false;
}
return RegisterService<T>(serviceInstance);
}
/// <inheritdoc />
public bool UnregisterService<T>(string name = null) where T : IMixedRealityService
{
T serviceInstance = FindService<T>(name);
if (serviceInstance == null) { return false; }
return UnregisterService<T>(serviceInstance);
}
/// <inheritdoc />
public bool UnregisterService<T>(T serviceInstance) where T : IMixedRealityService
{
if (serviceInstance == null) { return false; }
Type interfaceType = typeof(T);
if (!registeredServices.ContainsKey(interfaceType)) { return false; }
registeredServices.Remove(interfaceType);
return MixedRealityServiceRegistry.RemoveService<T>(serviceInstance, this);
}
/// <summary>
/// Activates an instance of the specified concrete type using the provided argument collection.
/// </summary>
/// <typeparam name="T">The interface which must be implemented by the concrete type.</typeparam>
/// <param name="concreteType">The type of object to be instantiated.</param>
/// <param name="supportedPlatforms">The platform(s) on which the concrete type is supported.</param>
/// <param name="args">Collection of arguments to provide to the concrete type's constructor.</param>
/// <returns>An instance of the concrete type. Returns a default value of T (typically null) in the event of a failure.</returns>
private T ActivateInstance<T>(Type concreteType, SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1), params object[] args) where T : IMixedRealityService
{
if (concreteType == null) { return default(T); }
if (!PlatformUtility.IsPlatformSupported(supportedPlatforms))
{
return default(T);
}
if (!typeof(T).IsAssignableFrom(concreteType))
{
Debug.LogError($"Error: {concreteType.Name} service must implement {typeof(T)}.");
return default(T);
}
try
{
T serviceInstance = (T)Activator.CreateInstance(concreteType, args);
return serviceInstance;
}
catch (Exception e)
{
Debug.LogError($"Error: Failed to instantiate {concreteType.Name}: {e.GetType()} - {e.Message}");
return default(T);
}
}
#endregion IMixedRealityServiceRegistrar implementation
/// <summary>
/// Initialize a service.
/// </summary>
/// <typeparam name="T">The interface type for the service to be initialized.</typeparam>
/// <param name="concreteType">The concrete type of the service to initialize.</param>
/// <param name="supportedPlatforms">The platform(s) on which the service is supported.</param>
/// <param name="args">Arguments to provide to the service class constructor.</param>
protected virtual void Initialize<T>(Type concreteType, SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1), params object[] args) where T : IMixedRealityService
{
if (!RegisterService<T>(concreteType, supportedPlatforms, args))
{
Debug.LogError($"Failed to register the {concreteType.Name} service.");
}
T serviceInstance = FindService<T>();
serviceInstance?.Initialize();
}
/// <summary>
/// Uninitialize a service.
/// </summary>
/// <typeparam name="T">The interface type for the service to uninitialize.</typeparam>
protected virtual void Uninitialize<T>() where T : IMixedRealityService
{
T serviceInstance = FindService<T>();
if (serviceInstance != null)
{
registeredServices.Remove(typeof(T));
MixedRealityServiceRegistry.RemoveService<T>(serviceInstance, this);
}
}
/// <summary>
/// Locates a service instance in the registry,
/// </summary>
/// <typeparam name="T">The interface type of the service to locate.</typeparam>
/// <param name="name">The name of the desired service.</param>
/// <returns>Instance of the interface type, or null if not found.</returns>
private T FindService<T>(string name = null) where T : IMixedRealityService
{
Type interfaceType = typeof(T);
IMixedRealityService serviceInstance;
if (!registeredServices.TryGetValue(interfaceType, out serviceInstance)) { return default(T); }
return (T)serviceInstance;
}
}
}