// 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
{
///
/// 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.
///
[AddComponentMenu("Scripts/MRTK/SDK/BaseServiceManager")]
public class BaseServiceManager : MonoBehaviour, IMixedRealityServiceRegistrar
{
///
/// The collection of registered services.
///
protected Dictionary registeredServices = new Dictionary();
#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
///
public T GetService(string name = null, bool showLogs = true) where T : IMixedRealityService
{
T serviceInstance = FindService(name);
if (showLogs && (serviceInstance == null))
{
Debug.LogError($"Failed to get the requested service of type {typeof(T)}.");
}
return serviceInstance;
}
///
public IReadOnlyList GetServices(string name = null) where T : IMixedRealityService
{
Type interfaceType = typeof(T);
List matchingServices = new List();
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;
}
///
public bool IsServiceRegistered(string name = null) where T : IMixedRealityService
{
return (GetService(name) != null);
}
///
public bool RegisterService(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(serviceInstance, this);
if (registered)
{
registeredServices.Add(interfaceType, serviceInstance);
}
return registered;
}
///
public bool RegisterService(Type concreteType, SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1), params object[] args) where T : IMixedRealityService
{
T serviceInstance = ActivateInstance(concreteType, supportedPlatforms, args);
if (serviceInstance == null)
{
return false;
}
return RegisterService(serviceInstance);
}
///
public bool UnregisterService(string name = null) where T : IMixedRealityService
{
T serviceInstance = FindService(name);
if (serviceInstance == null) { return false; }
return UnregisterService(serviceInstance);
}
///
public bool UnregisterService(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(serviceInstance, this);
}
///
/// Activates an instance of the specified concrete type using the provided argument collection.
///
/// The interface which must be implemented by the concrete type.
/// The type of object to be instantiated.
/// The platform(s) on which the concrete type is supported.
/// Collection of arguments to provide to the concrete type's constructor.
/// An instance of the concrete type. Returns a default value of T (typically null) in the event of a failure.
private T ActivateInstance(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
///
/// Initialize a service.
///
/// The interface type for the service to be initialized.
/// The concrete type of the service to initialize.
/// The platform(s) on which the service is supported.
/// Arguments to provide to the service class constructor.
protected virtual void Initialize(Type concreteType, SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1), params object[] args) where T : IMixedRealityService
{
if (!RegisterService(concreteType, supportedPlatforms, args))
{
Debug.LogError($"Failed to register the {concreteType.Name} service.");
}
T serviceInstance = FindService();
serviceInstance?.Initialize();
}
///
/// Uninitialize a service.
///
/// The interface type for the service to uninitialize.
protected virtual void Uninitialize() where T : IMixedRealityService
{
T serviceInstance = FindService();
if (serviceInstance != null)
{
registeredServices.Remove(typeof(T));
MixedRealityServiceRegistry.RemoveService(serviceInstance, this);
}
}
///
/// Locates a service instance in the registry,
///
/// The interface type of the service to locate.
/// The name of the desired service.
/// Instance of the interface type, or null if not found.
private T FindService(string name = null) where T : IMixedRealityService
{
Type interfaceType = typeof(T);
IMixedRealityService serviceInstance;
if (!registeredServices.TryGetValue(interfaceType, out serviceInstance)) { return default(T); }
return (T)serviceInstance;
}
}
}