The Manager Interfaces
There will be two types of plugins used in Charlie.
The first type of plugin will provide “stuff” that Charlie and other plugins will want to use. For example, the SecurityPlugin will provide a UserManager and a RoleManager that will be used by others when implementing their security. As another example, the LoggingPlugin will provide a LoggingManager that will be used by others when recording their activity.
The second type of plugin will not provide anything of interest to others. For example, an ArticlesPlugin will just be called when the time comes to render a page that contains an article. Before and after the ArticlesPlugin has added an article to the page, Charlie and the other plugins have no interest in it.
The question is, how will Charlie and other plugins find and use the first type of plugin—the type that provides Managers of interest? My current resolution has been to introduce “pointer” classes. These classes hide the fact that the functionality is being provided by a Plugin rather than by Charlie. Put another way, these pointer classes mean that a plugin only ever talks to Charlie, never knowing that Charlie is in fact passing the responsibility on to another plugin.
I have said that other plugins will need to use the LoggingManager in order to save messages. So, Charlie provides a LoggingManager class with a Current property:
namespace Charlie.Framework.Business.Logging { public class LoggingManager { public static ILoggingManager Current { get { return PluginManager.Current.LoggingManager; } } } }
If a class in the SecurityPlugin needs to log a message, then the code is very simple:
using Charlie.Framework.Business.Logging; public class UserManager : EntityManager { public void LogoutUser(User user) { HttpContext context = HttpContext.Current; if (context.User != null && context.User.Identity.IsAuthenticated) { FormsAuthentication.SignOut(); } LoggingManager.Current.LogMessage("User logged out."); } }
So, from the point of view of the SecurityPlugin, it is sending a message directly to Charlie’s own LoggingManager. But behind the scenes, Charlie’s own LoggingManager does nothing more than say to Charlie’s PluginManager, “Hey, quick, give me a LoggingManager that understands how to log a message!” So that Charlie’s make-believe LoggingManager and the real LoggingManager work the same way, it is necessary to define the interface that a LoggingManager must implement:
public interface ILoggingManager { void LogMessage(String message); }
So that Charlie’s PluginManager can obtain a LoggingManager from a LoggingPlugin, the interface for a LoggingPlugin will be as follows:
public interface ILoggingPlugin : IPlugin { ILoggingManager GetLoggingManager(); }
I must admit that I don’t think I have explained this too well. If I were being paid to write a book, I would scrap this explanation and start again. But for a weblog, this will have to do. The bottom line is that by defining manager interfaces (ILoggingManager, IUserManager, IRoleManager), Charlie and its plugins can make calls to Charlie’s LoggingManager.Current, UserManager.Current, and RoleManager.Current objects, never knowing that these managers are “fake,” and behind the scenes Charlie is passing the responsibility to the “real” Manager that is obtained from a Plugin.
I have said above that this is my current resolution for how to expose Managers that actually come from Plugins. I am not entirely happy with this solution, as having these “fake” managers seems too contrived. Then again, the solution is very simple, broadly applicable, and works. Unless I learn of a better solution, I will follow the old adage, “If it ain’t broke, don’t fix it.”
by Alister Jones | Next up: The Plugin System →
----
Post a Comment