--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianUtils/PluginManager/PluginManager.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,419 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Reflection;
+
+namespace SymbianUtils.PluginManager
+{
+ public class PluginManager<T> : DisposableObject, IEnumerable<T>
+ {
+ #region Events
+ public delegate void PluginLoadedHandler( T aPlugin );
+ public event PluginLoadedHandler PluginLoaded;
+ #endregion
+
+ #region Constructors
+ public PluginManager()
+ {
+ }
+
+ public PluginManager( bool aDiagnostics )
+ {
+ iDiagnostics = aDiagnostics;
+ }
+
+ public PluginManager( int aMinimumNumberOfExpectedPlugins )
+ {
+ iMinimumNumberOfExpectedPlugins = aMinimumNumberOfExpectedPlugins;
+ }
+
+ public PluginManager( bool aDiagnostics, int aMinimumNumberOfExpectedPlugins )
+ : this( aDiagnostics )
+ {
+ iMinimumNumberOfExpectedPlugins = aMinimumNumberOfExpectedPlugins;
+ }
+ #endregion
+
+ #region API - loading
+ public void Load( object[] aPluginConstructorParameters )
+ {
+ Trace( "Load() - invoked by: " + System.Environment.StackTrace );
+ Assembly assembly = Assembly.GetCallingAssembly();
+ string path = Path.GetDirectoryName( assembly.Location );
+ FindPluginsWithinPath( path, KDefaultSearchSpecification, aPluginConstructorParameters, assembly );
+ }
+
+ public void LoadFromCallingAssembly()
+ {
+ Trace( "LoadFromCallingAssembly(1) - invoked by: " + System.Environment.StackTrace );
+ Assembly assembly = Assembly.GetCallingAssembly();
+ FindPluginsWithinAssembly( assembly, true, new object[] {} );
+ Rationalise();
+ }
+
+ public void LoadFromCallingAssembly( object[] aPluginConstructorParameters )
+ {
+ Trace( "LoadFromCallingAssembly(2) - invoked by: " + System.Environment.StackTrace );
+ Assembly assembly = Assembly.GetCallingAssembly();
+ FindPluginsWithinAssembly( assembly, true, aPluginConstructorParameters );
+ Rationalise();
+ }
+
+ public void LoadFromPath( string aPath, object[] aPluginConstructorParameters )
+ {
+ FindPluginsWithinPath( aPath, KDefaultSearchSpecification, aPluginConstructorParameters, null );
+ }
+
+ public void LoadFromPath( string aPath, string aMatchSpec, object[] aPluginConstructorParameters )
+ {
+ FindPluginsWithinPath( aPath, aMatchSpec, aPluginConstructorParameters, null );
+ }
+ #endregion
+
+ #region API - misc
+ public void Unload()
+ {
+ foreach ( T plugin in iPlugins )
+ {
+ IDisposable disposable = plugin as IDisposable;
+ if ( disposable != null )
+ {
+ disposable.Dispose();
+ }
+ }
+ //
+ iPlugins.Clear();
+ }
+
+ public void Sort( IComparer<T> aComparer )
+ {
+ iPlugins.Sort( aComparer );
+ }
+
+ public void Sort( Comparison<T> aComparer )
+ {
+ iPlugins.Sort( aComparer );
+ }
+
+ public bool Predicate( Predicate<T> aPredicate )
+ {
+ bool ret = iPlugins.Exists( aPredicate );
+ return ret;
+ }
+
+ public void Rationalise()
+ {
+ List<T> plugins = iPlugins;
+ iPlugins = new List<T>();
+ //
+ int count = plugins.Count;
+ for ( int i = count - 1; i >= 0; i-- )
+ {
+ T pluginToCheck = plugins[ i ];
+ plugins.RemoveAt( i );
+ Trace( "Rationalise() - checking hierarchy for derivates of: " + pluginToCheck.GetType().ToString() );
+ //
+ bool isDerviedFromByOtherPlugin = IsClassDerivedFrom( plugins, pluginToCheck );
+ Trace( "Rationalise() - is base class for other plugin: " + isDerviedFromByOtherPlugin );
+ //
+ if ( !isDerviedFromByOtherPlugin )
+ {
+ iPlugins.Add( pluginToCheck );
+ Trace( "Rationalise() - found good plugin: " + pluginToCheck.GetType().ToString() );
+ OnPluginLoaded( pluginToCheck );
+ }
+ }
+
+ // Check that we loaded the expected minimum amount
+ count = iPlugins.Count;
+ SymbianUtils.SymDebug.SymDebugger.Assert( iMinimumNumberOfExpectedPlugins < 0 || count >= iMinimumNumberOfExpectedPlugins );
+ }
+ #endregion
+
+ #region Properties
+ public int Count
+ {
+ get { return iPlugins.Count; }
+ }
+
+ public T this[ int aIndex ]
+ {
+ get { return iPlugins[ aIndex ]; }
+ }
+
+ public Type PluginType
+ {
+ get { return typeof( T ); }
+ }
+ #endregion
+
+ #region Internal constants
+ private const string KDefaultSearchSpecification = "*.plugin.dll";
+ #endregion
+
+ #region Event propgation
+ private void OnPluginLoaded( T aPlugin )
+ {
+ if ( PluginLoaded != null )
+ {
+ PluginLoaded( aPlugin );
+ }
+ }
+ #endregion
+
+ #region Internal methods
+ private void Trace( string aMessage )
+ {
+ System.Diagnostics.Debug.WriteLineIf( iDiagnostics, "PluginLoader<" + typeof(T).Name + "> " + aMessage );
+ }
+
+ private void Trace( Exception aException, string aFunction )
+ {
+ Trace( string.Format( "PluginLoader.{0}() - exception: {1}", aFunction, aException.Message ) );
+ Trace( string.Format( "PluginLoader.{0}() - stack: {1}", aFunction, aException.StackTrace ) );
+ //
+ if ( aException is ReflectionTypeLoadException )
+ {
+ ReflectionTypeLoadException refEx = (ReflectionTypeLoadException) aException;
+ foreach ( Exception l in refEx.LoaderExceptions )
+ {
+ Trace( string.Format( " loader exception: {0}", l.Message ) );
+ Trace( string.Format( " loader stack: {0}", l.StackTrace ) );
+ }
+ }
+ else if ( aException is FileNotFoundException )
+ {
+ FileNotFoundException fnf = (FileNotFoundException) aException;
+ Trace( string.Format( " file name: {0}", fnf.FileName ) );
+ Trace( string.Format( " fusion log: {0}", fnf.FusionLog ) );
+ }
+ }
+
+ private static bool IsClassDerivedFrom( List<T> aPluginList, T aPlugin )
+ {
+ bool ret = false;
+ Type checkType = aPlugin.GetType();
+ //
+ foreach ( T plugin in aPluginList )
+ {
+ Type type = plugin.GetType();
+ if ( type.IsSubclassOf( checkType ) )
+ {
+ ret = true;
+ break;
+ }
+ }
+ //
+ return ret;
+ }
+
+ private void CreateFromTypes( Type[] aTypes, object[] aPluginConstructorParameters )
+ {
+ Type pluginType = PluginType;
+ Trace( "CreateFromTypes() - got " + aTypes.Length + " types. Searching for instances of: " + pluginType.Name );
+ //
+ foreach ( Type type in aTypes )
+ {
+ if ( pluginType.IsAssignableFrom( type ) )
+ {
+ Trace( "CreateFromTypes() - found type: " + type.Name );
+ if ( !type.IsAbstract )
+ {
+ Trace( "CreateFromTypes() - type \'" + type.Name + "\' is concrete implementation" );
+ CreateFromType( type, aPluginConstructorParameters );
+ }
+ }
+ }
+ }
+
+ private void CreateFromType( Type aType, object[] aPluginConstructorParameters )
+ {
+ try
+ {
+ Trace( "CreateFromType() - calling constructor: " + aType.Name );
+ //
+ object ret = CallConstructor( aType, aPluginConstructorParameters );
+ if ( ret != null )
+ {
+ T plugin = (T) ret;
+ Trace( "CreateFromType() - saving instance: " + plugin.GetType().ToString() );
+ iPlugins.Add( plugin );
+ }
+ }
+ catch ( FileNotFoundException )
+ {
+ }
+ catch ( Exception e )
+ {
+ Trace( e, "CreateFromType" );
+ }
+ }
+
+ private object CallConstructor( Type aType, object[] aParameters )
+ {
+ object ret = null;
+ //
+ try
+ {
+ ret = Activator.CreateInstance( aType, aParameters );
+ }
+ catch ( Exception e )
+ {
+ Trace( e, "CallConstructor" );
+ }
+ //
+ return ret;
+ }
+
+ private void LoadAssemblyAndCreatePlugins( string aFileName, object[] aPluginConstructorParameters, bool aExplicit )
+ {
+ try
+ {
+ Trace( "LoadAssemblyAndCreatePlugins() - Trying to load plugins from dll: " + aFileName );
+ if ( SymbianUtils.Assemblies.AssemblyHelper.IsCLRAssembly( aFileName ) )
+ {
+ Assembly pluginAssembly = Assembly.LoadFrom( aFileName );
+ if ( pluginAssembly != null )
+ {
+ FindPluginsWithinAssembly( pluginAssembly, aExplicit, aPluginConstructorParameters );
+ }
+ }
+ }
+ catch ( BadImageFormatException )
+ {
+ // Not a managed dll - ignore error
+ }
+ catch ( Exception assemblyLoadException )
+ {
+ Trace( assemblyLoadException, "LoadAssemblyAndCreatePlugins" );
+ }
+ }
+
+ private void FindPluginsWithinAssembly( Assembly aAssembly, bool aExplit, object[] aPluginConstructorParameters )
+ {
+ bool okayToGetTypes = aExplit;
+
+#if BETTER_PERFORMANCE
+ // If explit load requested, then don't check for plugin attribute. Otherwise, to avoid
+ // enumerating all types we can check for our special "plugin" attribute
+ object[] attributes = aAssembly.GetCustomAttributes( typeof( PluginAssemblyAttribute ), false) ;
+ if ( attributes != null && attributes.Length > 0 )
+ {
+ okayToGetTypes = true;
+ }
+#else
+ okayToGetTypes = true;
+#endif
+
+ // Now get types
+ if ( okayToGetTypes )
+ {
+ Trace( "DoLoad() - getting types from assembly: " + aAssembly.Location );
+ Type[] types = aAssembly.GetTypes();
+ CreateFromTypes( types, aPluginConstructorParameters );
+ }
+ }
+
+ private void FindPluginsWithinPath( string aPath, string aMatchSpec, object[] aPluginConstructorParameters, Assembly aAdditionalSearchAssembly )
+ {
+ Trace( string.Format( "FindPluginsWithinPath() - path: {0}, matchSpec: {1}, invoked by: {2}", aPath, aMatchSpec, System.Environment.StackTrace ) );
+ Unload();
+
+ // Find from path
+ string[] dllNames = Directory.GetFiles( aPath, aMatchSpec );
+ foreach ( string dll in dllNames )
+ {
+ string justFileName = Path.GetFileName( dll );
+ LoadAssemblyAndCreatePlugins( dll, aPluginConstructorParameters, false );
+ }
+
+ // Check additional assembly
+ if ( aAdditionalSearchAssembly != null )
+ {
+ FindPluginsWithinAssembly( aAdditionalSearchAssembly, true, aPluginConstructorParameters );
+ }
+
+ // Check hierarchy for derived plugins
+ Rationalise();
+ }
+ #endregion
+
+ #region From IEnumerable<T>
+ public IEnumerator<T> GetEnumerator()
+ {
+ foreach ( T p in iPlugins )
+ {
+ yield return p;
+ }
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ foreach ( T p in iPlugins )
+ {
+ yield return p;
+ }
+ }
+ #endregion
+
+ #region From System.Object
+ public override string ToString()
+ {
+ StringBuilder ret = new StringBuilder();
+ ret.AppendFormat( "Found: {0} of type: {1}", iPlugins.Count, typeof(T).Name );
+ if ( iMinimumNumberOfExpectedPlugins > 0 )
+ {
+ ret.AppendFormat( ", expected: {2}", iMinimumNumberOfExpectedPlugins );
+ }
+ return ret.ToString();
+ }
+ #endregion
+
+ #region From DisposableObject
+ protected override void CleanupManagedResources()
+ {
+ try
+ {
+ base.CleanupManagedResources();
+ }
+ finally
+ {
+ foreach ( T obj in iPlugins )
+ {
+ IDisposable disp = obj as IDisposable;
+ if ( disp != null )
+ {
+ disp.Dispose();
+ }
+ }
+ //
+ iPlugins.Clear();
+ iPlugins = null;
+ }
+ }
+ #endregion
+
+ #region Data members
+ private bool iDiagnostics = false;
+ private int iMinimumNumberOfExpectedPlugins = -1;
+ private List<T> iPlugins = new List<T>();
+ #endregion
+ }
+}