diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianUtils/PluginManager/PluginManager.cs --- /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 : DisposableObject, IEnumerable + { + #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 aComparer ) + { + iPlugins.Sort( aComparer ); + } + + public void Sort( Comparison aComparer ) + { + iPlugins.Sort( aComparer ); + } + + public bool Predicate( Predicate aPredicate ) + { + bool ret = iPlugins.Exists( aPredicate ); + return ret; + } + + public void Rationalise() + { + List plugins = iPlugins; + iPlugins = new List(); + // + 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 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 + public IEnumerator 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 iPlugins = new List(); + #endregion + } +}