Click here to Skip to main content
15,892,059 members
Articles / Programming Languages / C#

Plugins Manager

Rate me:
Please Sign up or sign in to vote.
4.00/5 (6 votes)
22 May 2008CPOL3 min read 50.8K   1.9K   62  
A plugins manager class to manage a plugins structure
/*
 * Creato da SharpDevelop.
 * Utente: lucabonotto
 * Data: 01/03/2008
 * Ora: 14.52
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections;
using System.IO;
using System.Runtime.Remoting;
using System.Windows.Forms;
using System.Xml;

namespace LBSoft.PluginManager
{
	#region Enums
	/// <summary>
	/// Message type enumerator
	/// </summary>
	public enum MessageType
	{
		Normal = 0,
		Error,
		Warning,
	}
	#endregion
	
	#region Interfaces
	/// <summary>
	/// Interface for the plugin provider
	/// </summary>
	public interface ILBPluginsManager
	{
		/// <summary>
		/// Method to view the processing message
		/// </summary>
		/// <param name="message">Message body</param>
		/// <param name="addEndLine">Flag to add a newline character</param>
		void OutputMessage ( string message, bool addEndLine );
		
		/// <summary>
		/// Method to view the processing message
		/// </summary>
		/// <param name="message">Message body</param>
		/// <param name="addEndLine">Flag to add a newline character</param>
		/// <param name="type">Type of the message</param>
		void OutputMessage ( string message, bool addEndLine, MessageType type );
	}
	
	/// <summary>
	/// Base plugin interface
	/// </summary>
	public interface ILBPlugin
	{
		/// <summary>
		/// Method to initialize the plugin
		/// </summary>
		/// <param name="piPath">Plugin path</param>
		/// <returns></returns>
		bool Initialize	();
		
		/// <summary>
		/// Method to release the plugin object
		/// </summary>
		/// <returns></returns>
		bool Release ();
	}
	#endregion
	
	#region Classes
	/// <summary>
	/// Class for the plugin definitions. This class is the object with
	/// the definition readed from the 'Plugins.xml' definitions file
	/// </summary>
	public class Plugin
	{
		#region Field
		// Plugin name
		private	string	pluginName = System.String.Empty;
		// Relative path from the application path
		private	string	pluginPath = System.String.Empty;
		// Assembly of the plugin
		private string	pluginAssembly = System.String.Empty;
		// Plugin version
		private string	pluginVersion = System.String.Empty;
		// Name of the plugin object
		private string	pluginObject = System.String.Empty;
		#endregion
		
		#region Ctors
		/// <summary>
		/// Ctor of the class
		/// </summary>
		public Plugin()
		{
		}
		#endregion
		
		#region Properties
		/// <summary>
		/// Description name of the plugin object
		/// </summary>
		public string Name
		{
			get { return this.pluginName; }
			set { this.pluginName = value; }
		}
		
		/// <summary>
		/// Path of the plugin assembly
		/// </summary>
		public string Path
		{
			get { return this.pluginPath; }
			set { this.pluginPath = value; }
		}
		
		/// <summary>
		/// Assembly name of the plugin object
		/// </summary>
		public string Assembly
		{
			get { return this.pluginAssembly; }
			set { this.pluginAssembly = value; }
		}
		
		/// <summary>
		/// Version of the plugin object
		/// </summary>
		public string Version
		{
			get { return this.pluginVersion; }
			set { this.pluginVersion = value; }
		}			
		
		/// <summary>
		/// Name of the plugin object in the assembly with the namespace
		/// </summary>
		public string Object
		{
			get { return this.pluginObject; }
			set { this.pluginObject = value; }
		}	
		#endregion
	}

	/// <summary>
	/// Class for the menagement of the plugins object and definitions
	/// </summary>
	public class PluginsManager
	{
		#region Fields
		private string				definitionsFile = "Plugins.xml";
		// List of the plugins definitions
		private ArrayList			plugins;
		// List of the loaded plugins objects
		private ArrayList			pluginObjs;
		// Path of the plugins
		private String				pluginsPath;
		// Last error message
		private String				lastMessageErr;
		// Interface for the plugin manager
		private ILBPluginsManager	provider = null;
		// Flag to show the messages
		private bool				showMessages = true;
		#endregion
		
		#region Ctors
		/// <summary>
		/// Ctor of the class
		/// </summary>
		public PluginsManager()
			: this ( string.Empty)
		{
		}
		
		/// <summary>
		/// Ctor of the class
		/// </summary>
		/// <param name="path">Path of the plugins assemblies</param>
		public PluginsManager( string path )
		{
			this.plugins = new ArrayList();
			this.pluginObjs = new ArrayList();
			this.PluginsPath = path;
		}
		#endregion
		
		#region Properties
		/// <summary>
		/// Definitions file path
		/// </summary>
		public string DefinitionsFile
		{
			set { this.definitionsFile = value; }
			get { return this.definitionsFile; }		
		}
		
		/// <summary>
		/// Provider interface for the manager
		/// </summary>
		public ILBPluginsManager Provider
		{
			set { this.provider = value; }
			get { return this.provider; }
		}
		
		/// <summary>
		/// Path of the plugins assemblies
		/// </summary>
		public string PluginsPath
		{
			set 
			{ 
				this.pluginsPath = value; 
				char sep = Path.DirectorySeparatorChar;
				this.pluginsPath = this.pluginsPath.TrimEnd ( sep );
			}
			get { return this.pluginsPath; }
		}
		
		/// <summary>
		/// Strig of the last error
		/// </summary>
		public string LastMessaggeError
		{
			get { return this.lastMessageErr; }
		}
		
		/// <summary>
		/// List of the plugins definitions
		/// </summary>
		public ArrayList Plugins
		{
			get { return this.plugins; }
		}
		
		/// <summary>
		/// List of the loaded plugins objects
		/// </summary>
		public ArrayList PluginsObjects
		{
			get { return this.pluginObjs; }
		}
		
		/// <summary>
		/// Enable the messages visibility
		/// </summary>
		public bool ShowMessages
		{
			set { this.showMessages = value; }
			get { return this.showMessages; }
		}
		#endregion
		
		#region Public methods
		/// <summary>
		/// Retrieve the plugin definitions
		/// </summary>
		/// <param name="name">Name of the plugin definition</param>
		/// <returns></returns>
		public Plugin GetPlugin( string name )
		{
			foreach (Plugin plugin in plugins) 
			{
				if ( plugin.Name == name )
					return plugin;
			}
			
			return null;
			
		}
		
		/// <summary>
		/// Load the plugin object
		/// </summary>
		/// <param name="name">Name of the plugin</param>
		/// <returns>Plugin object or null</returns>
		public ILBPlugin LoadPlugin ( string name )
		{
			this.lastMessageErr = "";
			
			// Find plugin definitions
			Plugin pi = this.GetPlugin ( name );
			if ( pi == null )
			{
				this.lastMessageErr = "Plugin not found";
				return null;
			}
			
			// Create the path for the plugin assembly
			string str = string.Empty;
			if ( this.PluginsPath == string.Empty )
				str = ".";
			
			str += this.PluginsPath + System.IO.Path.DirectorySeparatorChar;
			if ( pi.Path != null )
			{
				if ( pi.Path != string.Empty )
					str += pi.Path + System.IO.Path.DirectorySeparatorChar;
			}
			
			str += pi.Assembly;

			// Try to create an object
			ILBPlugin piObj = null;			
			try
			{
				// Create the plugin instance
	            ObjectHandle oHandle = Activator.CreateInstanceFrom( str,
	                												 pi.Object );
				
				// Set the object
	            piObj = oHandle.Unwrap() as ILBPlugin;
	            		        
	            // Initialization of the plugin
	            if ( piObj.Initialize() == false )
	            	return null;
					
				// Add to the list
				this.pluginObjs.Add ( piObj );
			}
			catch( Exception e )
			{
				this.OutputMessage ( e.ToString(), true );
				this.lastMessageErr = e.ToString();
			}
			
			// Return the plugin object
			return piObj;
		}
		
		/// <summary>
		/// Unload the plugin oblect
		/// </summary>
		/// <param name="piObj">Plugin object</param>
		/// <returns>true if there is no error, otherwise false</returns>
		public bool UnloadPlugin( ILBPlugin piObj )
		{
			if ( piObj != null )
			{
				// Release the object
				if ( piObj.Release() == false )
					return false;
				
				// Remove from the list
				this.pluginObjs.Remove ( piObj );
			}
			
			return true;
		}
		
		/// <summary>
		/// Load the plugins configuration file
		/// </summary>
		/// <returns>true if there is no error, otherwise false</returns>
		public bool LoadPluginsConfig ()
		{
			bool ret = true;

			try
			{
				// Message
				this.OutputMessage ( "Reading plugins definitions...", false );
				
				// Open definitions file
				XmlDocument doc = new XmlDocument();
				doc.Load ( this.definitionsFile );
				
				// Find root node
				XmlNode pluginsNode = doc.SelectSingleNode ( "Plugins") ;
				if ( pluginsNode == null )
					throw new XmlException ( "Definitions file is not valid\n" );
				
				// Scan the childs nodes
				foreach ( XmlNode node in pluginsNode.ChildNodes )
				{
					// Find the attributes
					XmlAttribute attrName = node.Attributes["Name"];
					XmlAttribute attrPath = node.Attributes["Path"];
					XmlAttribute attrAssembly = node.Attributes["Assembly"];
					XmlAttribute attrVersion = node.Attributes["Version"];
					XmlAttribute attrObjectName = node.Attributes["ObjectName"];
					
					// Check attributes
					if ( ( attrName.Value == String.Empty ) || ( attrPath.Value == String.Empty ) ||
					    ( attrAssembly.Value == String.Empty ) || ( attrVersion.Value == String.Empty ) ||
					    ( attrObjectName.Value == String.Empty ) )
					{
						throw new XmlException ( "Node attributes are not valid\n" );
					}
						
					// Create a plugin definitions object
					Plugin piData = new Plugin();
					if ( piData == null )
						throw new ApplicationException ( "Unable to create plugin definitions object\n" );
					
					// Set the data
					piData.Name = attrName.Value;
					piData.Path = attrPath.Value;
					piData.Assembly = attrAssembly.Value;
					piData.Version = attrVersion.Value;
					piData.Object = attrObjectName.Value;
					
					// Add definitions in the list
					this.plugins.Add ( piData );
				}
				
				// Message all ok
				this.OutputMessage ( "Ok", true );
			}
			catch ( XmlException eXml )
			{
				// XML exception
				this.OutputMessage ( "Failed", true, MessageType.Warning );
				this.OutputMessage ( eXml.Message, true, MessageType.Warning );

				ret = false;
			}
			catch( Exception e )
			{
				// General exception
				this.OutputMessage ( "Failed", true, MessageType.Warning );
				this.OutputMessage ( e.Message, true, MessageType.Warning );
				
				ret = false;
			}
			
			return ret;
		}
		#endregion
		
		#region Virtual methods
		/// <summary>
		/// Metodh for viewing the message
		/// </summary>
		/// <param name="message">Message body</param>
		/// <param name="addEndLine">Flag for add a newline character</param>
		protected virtual void OutputMessage( string message, bool addEndLine )
		{
			this.OutputMessage ( message, addEndLine, MessageType.Normal );
		}
		
		/// <summary>
		/// Metodh for viewing the message
		/// </summary>
		/// <param name="message">Message body</param>
		/// <param name="addEndLine">Flag for add a newline character</param>
		/// <param name="type">Type of the message</param>
		protected virtual void OutputMessage( string message, bool addEndLine, MessageType type )
		{
			if ( this.ShowMessages == false )
				return;
			
			if ( this.Provider != null )
				this.Provider.OutputMessage ( message, addEndLine, type );
			else
			{
				MessageBoxIcon mi = MessageBoxIcon.None;
				switch ( type )
				{
					case MessageType.Error:
						mi = MessageBoxIcon.Error;
						break;
						
					case MessageType.Warning:
						mi = MessageBoxIcon.Warning;
						break;						
				}
				
				MessageBox.Show ( message, this.GetType().Name, MessageBoxButtons.OK, mi );
			}
		}
		#endregion
	}
	#endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Promax Srl
Italy Italy
Software developer with over 16 years of experience, specializing on MFC/C++, C# and software architecture


Company : Promax S.r.l.


Comments and Discussions