crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianUtils/PluginManager/PluginManager.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 * 
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 using System;
       
    18 using System.Collections.Generic;
       
    19 using System.Text;
       
    20 using System.IO;
       
    21 using System.Reflection;
       
    22 
       
    23 namespace SymbianUtils.PluginManager
       
    24 {
       
    25     public class PluginManager<T> : DisposableObject, IEnumerable<T>
       
    26     {
       
    27         #region Events
       
    28         public delegate void PluginLoadedHandler( T aPlugin );
       
    29         public event PluginLoadedHandler PluginLoaded;
       
    30         #endregion
       
    31 
       
    32         #region Constructors
       
    33         public PluginManager()
       
    34         {
       
    35         }
       
    36 
       
    37         public PluginManager( bool aDiagnostics )
       
    38         {
       
    39             iDiagnostics = aDiagnostics;
       
    40         }
       
    41 
       
    42         public PluginManager( int aMinimumNumberOfExpectedPlugins )
       
    43         {
       
    44             iMinimumNumberOfExpectedPlugins = aMinimumNumberOfExpectedPlugins;
       
    45         }
       
    46 
       
    47         public PluginManager( bool aDiagnostics, int aMinimumNumberOfExpectedPlugins )
       
    48             : this( aDiagnostics )
       
    49         {
       
    50             iMinimumNumberOfExpectedPlugins = aMinimumNumberOfExpectedPlugins;
       
    51         }
       
    52         #endregion
       
    53 
       
    54         #region API - loading
       
    55         public void Load( object[] aPluginConstructorParameters )
       
    56         {
       
    57             Trace( "Load() - invoked by: " + System.Environment.StackTrace );
       
    58             Assembly assembly = Assembly.GetCallingAssembly();
       
    59             string path = Path.GetDirectoryName( assembly.Location );
       
    60             FindPluginsWithinPath( path, KDefaultSearchSpecification, aPluginConstructorParameters, assembly );
       
    61         }
       
    62 
       
    63         public void LoadFromCallingAssembly()
       
    64         {
       
    65             Trace( "LoadFromCallingAssembly(1) - invoked by: " + System.Environment.StackTrace );
       
    66             Assembly assembly = Assembly.GetCallingAssembly();
       
    67             FindPluginsWithinAssembly( assembly, true, new object[] {} );
       
    68             Rationalise();
       
    69         }
       
    70 
       
    71         public void LoadFromCallingAssembly( object[] aPluginConstructorParameters )
       
    72         {
       
    73             Trace( "LoadFromCallingAssembly(2) - invoked by: " + System.Environment.StackTrace );
       
    74             Assembly assembly = Assembly.GetCallingAssembly();
       
    75             FindPluginsWithinAssembly( assembly, true, aPluginConstructorParameters );
       
    76             Rationalise();
       
    77         }
       
    78 
       
    79         public void LoadFromPath( string aPath, object[] aPluginConstructorParameters )
       
    80         {
       
    81             FindPluginsWithinPath( aPath, KDefaultSearchSpecification, aPluginConstructorParameters, null );
       
    82         }
       
    83 
       
    84         public void LoadFromPath( string aPath, string aMatchSpec, object[] aPluginConstructorParameters )
       
    85         {
       
    86             FindPluginsWithinPath( aPath, aMatchSpec, aPluginConstructorParameters, null );
       
    87         }
       
    88         #endregion
       
    89 
       
    90         #region API - misc
       
    91         public void Unload()
       
    92         {
       
    93             foreach ( T plugin in iPlugins )
       
    94             {
       
    95                 IDisposable disposable = plugin as IDisposable;
       
    96                 if ( disposable != null )
       
    97                 {
       
    98                     disposable.Dispose();
       
    99                 }
       
   100             }
       
   101             //
       
   102             iPlugins.Clear();
       
   103         }
       
   104 
       
   105         public void Sort( IComparer<T> aComparer )
       
   106         {
       
   107             iPlugins.Sort( aComparer );
       
   108         }
       
   109 
       
   110         public void Sort( Comparison<T> aComparer )
       
   111         {
       
   112             iPlugins.Sort( aComparer );
       
   113         }
       
   114 
       
   115         public bool Predicate( Predicate<T> aPredicate )
       
   116         {
       
   117             bool ret = iPlugins.Exists( aPredicate );
       
   118             return ret;
       
   119         }
       
   120 
       
   121         public void Rationalise()
       
   122         {
       
   123             List<T> plugins = iPlugins;
       
   124             iPlugins = new List<T>();
       
   125             //
       
   126             int count = plugins.Count;
       
   127             for ( int i = count - 1; i >= 0; i-- )
       
   128             {
       
   129                 T pluginToCheck = plugins[ i ];
       
   130                 plugins.RemoveAt( i );
       
   131                 Trace( "Rationalise() - checking hierarchy for derivates of: " + pluginToCheck.GetType().ToString() );
       
   132                 //
       
   133                 bool isDerviedFromByOtherPlugin = IsClassDerivedFrom( plugins, pluginToCheck );
       
   134                 Trace( "Rationalise() - is base class for other plugin: " + isDerviedFromByOtherPlugin );
       
   135                 //
       
   136                 if ( !isDerviedFromByOtherPlugin )
       
   137                 {
       
   138                     iPlugins.Add( pluginToCheck );
       
   139                     Trace( "Rationalise() - found good plugin: " + pluginToCheck.GetType().ToString() );
       
   140                     OnPluginLoaded( pluginToCheck );
       
   141                 }
       
   142             }
       
   143 
       
   144             // Check that we loaded the expected minimum amount
       
   145             count = iPlugins.Count;
       
   146             SymbianUtils.SymDebug.SymDebugger.Assert( iMinimumNumberOfExpectedPlugins < 0 || count >= iMinimumNumberOfExpectedPlugins );
       
   147         }
       
   148         #endregion
       
   149 
       
   150         #region Properties
       
   151         public int Count
       
   152         {
       
   153             get { return iPlugins.Count; }
       
   154         }
       
   155 
       
   156         public T this[ int aIndex ]
       
   157         {
       
   158             get { return iPlugins[ aIndex ]; }
       
   159         }
       
   160 
       
   161         public Type PluginType
       
   162         {
       
   163             get { return typeof( T ); }
       
   164         }
       
   165         #endregion
       
   166         
       
   167         #region Internal constants
       
   168         private const string KDefaultSearchSpecification = "*.plugin.dll";
       
   169         #endregion
       
   170 
       
   171         #region Event propgation
       
   172         private void OnPluginLoaded( T aPlugin )
       
   173         {
       
   174             if ( PluginLoaded != null )
       
   175             {
       
   176                 PluginLoaded( aPlugin );
       
   177             }
       
   178         }
       
   179         #endregion
       
   180 
       
   181         #region Internal methods
       
   182         private void Trace( string aMessage )
       
   183         {
       
   184             System.Diagnostics.Debug.WriteLineIf( iDiagnostics, "PluginLoader<" + typeof(T).Name + "> " + aMessage );
       
   185         }
       
   186 
       
   187         private void Trace( Exception aException, string aFunction )
       
   188         {
       
   189             Trace( string.Format( "PluginLoader.{0}() - exception: {1}", aFunction, aException.Message ) );
       
   190             Trace( string.Format( "PluginLoader.{0}() - stack:     {1}", aFunction, aException.StackTrace ) );
       
   191             //
       
   192             if ( aException is ReflectionTypeLoadException )
       
   193             {
       
   194                 ReflectionTypeLoadException refEx = (ReflectionTypeLoadException) aException;
       
   195                 foreach ( Exception l in refEx.LoaderExceptions )
       
   196                 {
       
   197                     Trace( string.Format( "     loader exception: {0}", l.Message ) );
       
   198                     Trace( string.Format( "     loader stack:     {0}", l.StackTrace ) );
       
   199                 }
       
   200             }
       
   201             else if ( aException is FileNotFoundException )
       
   202             {
       
   203                 FileNotFoundException fnf = (FileNotFoundException) aException;
       
   204                 Trace( string.Format( "     file name:  {0}", fnf.FileName ) );
       
   205                 Trace( string.Format( "     fusion log: {0}", fnf.FusionLog ) );
       
   206             }
       
   207         }
       
   208 
       
   209         private static bool IsClassDerivedFrom( List<T> aPluginList, T aPlugin )
       
   210         {
       
   211             bool ret = false;
       
   212             Type checkType = aPlugin.GetType();
       
   213             //
       
   214             foreach ( T plugin in aPluginList )
       
   215             {
       
   216                 Type type = plugin.GetType();
       
   217                 if ( type.IsSubclassOf( checkType ) )
       
   218                 {
       
   219                     ret = true;
       
   220                     break;
       
   221                 }
       
   222             }
       
   223             //
       
   224             return ret;
       
   225         }
       
   226 
       
   227         private void CreateFromTypes( Type[] aTypes, object[] aPluginConstructorParameters )
       
   228         {
       
   229             Type pluginType = PluginType;
       
   230             Trace( "CreateFromTypes() - got " + aTypes.Length + " types. Searching for instances of: " + pluginType.Name );
       
   231             // 
       
   232             foreach ( Type type in aTypes )
       
   233             {
       
   234                 if ( pluginType.IsAssignableFrom( type ) )
       
   235                 {
       
   236                     Trace( "CreateFromTypes() - found type: " + type.Name );
       
   237                     if ( !type.IsAbstract )
       
   238                     {
       
   239                         Trace( "CreateFromTypes() - type \'" + type.Name + "\' is concrete implementation" );
       
   240                         CreateFromType( type, aPluginConstructorParameters );
       
   241                     }
       
   242                 }
       
   243             }
       
   244         }
       
   245 
       
   246         private void CreateFromType( Type aType, object[] aPluginConstructorParameters )
       
   247         {
       
   248             try
       
   249             {
       
   250                 Trace( "CreateFromType() - calling constructor: " + aType.Name );
       
   251                 //
       
   252                 object ret = CallConstructor( aType, aPluginConstructorParameters );
       
   253                 if ( ret != null )
       
   254                 {
       
   255                     T plugin = (T) ret;
       
   256                     Trace( "CreateFromType() - saving instance: " + plugin.GetType().ToString() );
       
   257                     iPlugins.Add( plugin );
       
   258                 }
       
   259             }
       
   260             catch ( FileNotFoundException )
       
   261             {
       
   262             }
       
   263             catch ( Exception e )
       
   264             {
       
   265                 Trace( e, "CreateFromType" );
       
   266             }
       
   267         }
       
   268 
       
   269         private object CallConstructor( Type aType, object[] aParameters )
       
   270         {
       
   271             object ret = null;
       
   272             //
       
   273             try
       
   274             {
       
   275                 ret = Activator.CreateInstance( aType, aParameters );
       
   276             }
       
   277             catch ( Exception e )
       
   278             {
       
   279                 Trace( e, "CallConstructor" );
       
   280             }
       
   281             //
       
   282             return ret;
       
   283         }
       
   284 
       
   285         private void LoadAssemblyAndCreatePlugins( string aFileName, object[] aPluginConstructorParameters, bool aExplicit )
       
   286         {
       
   287             try
       
   288             {
       
   289                 Trace( "LoadAssemblyAndCreatePlugins() - Trying to load plugins from dll: " + aFileName );
       
   290                 if ( SymbianUtils.Assemblies.AssemblyHelper.IsCLRAssembly( aFileName ) )
       
   291                 {
       
   292                     Assembly pluginAssembly = Assembly.LoadFrom( aFileName );
       
   293                     if ( pluginAssembly != null )
       
   294                     {
       
   295                         FindPluginsWithinAssembly( pluginAssembly, aExplicit, aPluginConstructorParameters );
       
   296                     }
       
   297                 }
       
   298             }
       
   299             catch ( BadImageFormatException )
       
   300             {
       
   301                 // Not a managed dll - ignore error
       
   302             }
       
   303             catch ( Exception assemblyLoadException )
       
   304             {
       
   305                 Trace( assemblyLoadException, "LoadAssemblyAndCreatePlugins" );
       
   306             }
       
   307         }
       
   308 
       
   309         private void FindPluginsWithinAssembly( Assembly aAssembly, bool aExplit, object[] aPluginConstructorParameters )
       
   310         {
       
   311             bool okayToGetTypes = aExplit;
       
   312 
       
   313 #if BETTER_PERFORMANCE
       
   314             // If explit load requested, then don't check for plugin attribute. Otherwise, to avoid
       
   315             // enumerating all types we can check for our special "plugin" attribute
       
   316             object[] attributes = aAssembly.GetCustomAttributes( typeof( PluginAssemblyAttribute ), false) ;
       
   317             if ( attributes != null && attributes.Length > 0 ) 
       
   318             {
       
   319                 okayToGetTypes = true;
       
   320             }
       
   321 #else
       
   322             okayToGetTypes = true;
       
   323 #endif
       
   324 
       
   325             // Now get types
       
   326             if ( okayToGetTypes )
       
   327             {
       
   328                 Trace( "DoLoad() - getting types from assembly: " + aAssembly.Location );
       
   329                 Type[] types = aAssembly.GetTypes();
       
   330                 CreateFromTypes( types, aPluginConstructorParameters );
       
   331             }
       
   332         }
       
   333 
       
   334         private void FindPluginsWithinPath( string aPath, string aMatchSpec, object[] aPluginConstructorParameters, Assembly aAdditionalSearchAssembly )
       
   335         {
       
   336             Trace( string.Format( "FindPluginsWithinPath() - path: {0}, matchSpec: {1}, invoked by: {2}", aPath, aMatchSpec, System.Environment.StackTrace ) );
       
   337             Unload();
       
   338             
       
   339             // Find from path
       
   340             string[] dllNames = Directory.GetFiles( aPath, aMatchSpec );
       
   341             foreach ( string dll in dllNames )
       
   342             {
       
   343                 string justFileName = Path.GetFileName( dll );
       
   344                 LoadAssemblyAndCreatePlugins( dll, aPluginConstructorParameters, false );
       
   345             }
       
   346 
       
   347             // Check additional assembly
       
   348             if ( aAdditionalSearchAssembly != null )
       
   349             {
       
   350                 FindPluginsWithinAssembly( aAdditionalSearchAssembly, true, aPluginConstructorParameters );
       
   351             }
       
   352    
       
   353             // Check hierarchy for derived plugins
       
   354             Rationalise();
       
   355         }
       
   356         #endregion
       
   357 
       
   358         #region From IEnumerable<T>
       
   359         public IEnumerator<T> GetEnumerator()
       
   360         {
       
   361             foreach ( T p in iPlugins )
       
   362             {
       
   363                 yield return p;
       
   364             }
       
   365         }
       
   366 
       
   367         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
       
   368         {
       
   369             foreach ( T p in iPlugins )
       
   370             {
       
   371                 yield return p;
       
   372             }
       
   373         }
       
   374         #endregion
       
   375 
       
   376         #region From System.Object
       
   377         public override string ToString()
       
   378         {
       
   379             StringBuilder ret = new StringBuilder();
       
   380             ret.AppendFormat( "Found: {0} of type: {1}", iPlugins.Count, typeof(T).Name );
       
   381             if ( iMinimumNumberOfExpectedPlugins > 0 )
       
   382             {
       
   383                 ret.AppendFormat( ", expected: {2}", iMinimumNumberOfExpectedPlugins );
       
   384             }
       
   385             return ret.ToString();
       
   386         }
       
   387         #endregion
       
   388 
       
   389         #region From DisposableObject
       
   390         protected override void CleanupManagedResources()
       
   391         {
       
   392             try
       
   393             {
       
   394                 base.CleanupManagedResources();
       
   395             }
       
   396             finally
       
   397             {
       
   398                 foreach ( T obj in iPlugins )
       
   399                 {
       
   400                     IDisposable disp = obj as IDisposable;
       
   401                     if ( disp != null )
       
   402                     {
       
   403                         disp.Dispose();
       
   404                     }
       
   405                 }
       
   406                 //
       
   407                 iPlugins.Clear();
       
   408                 iPlugins = null;
       
   409             }
       
   410         }
       
   411         #endregion
       
   412 
       
   413         #region Data members
       
   414         private bool iDiagnostics = false;
       
   415         private int iMinimumNumberOfExpectedPlugins = -1;
       
   416         private List<T> iPlugins = new List<T>();
       
   417         #endregion
       
   418     }
       
   419 }