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