Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.PluginInfrastructure/Loader.cs

    r11 r29  
    3333    public delegate void PluginLoadFailedEventHandler(string pluginName, string args);
    3434
    35     private Dictionary<PluginInfo, IPlugin> activePlugins = new Dictionary<PluginInfo, IPlugin>();
     35    private Dictionary<PluginInfo, List<string>> pluginDependencies = new Dictionary<PluginInfo, List<string>>();
     36    private List<PluginInfo> preloadedPluginInfos = new List<PluginInfo>();
     37    private Dictionary<IPlugin, PluginInfo> pluginInfos = new Dictionary<IPlugin, PluginInfo>();
    3638    private Dictionary<PluginInfo, IPlugin> allPlugins = new Dictionary<PluginInfo, IPlugin>();
    37     private Dictionary<IPlugin, PluginInfo> pluginInfos = new Dictionary<IPlugin, PluginInfo>();
    38 
    39     private Dictionary<string, List<string>> pluginDependencies = new Dictionary<string, List<string>>();
    40     private Dictionary<string, List<string>> pluginAssemblies = new Dictionary<string, List<string>>();
    41 
    42     private List<string> loadablePlugins = new List<string>();
     39    private List<PluginInfo> disabledPlugins = new List<PluginInfo>();
    4340    private string pluginDir = Application.StartupPath + "/" + HeuristicLab.PluginInfrastructure.Properties.Settings.Default.PluginDir;
    4441
    4542    internal event PluginLoadFailedEventHandler MissingPluginFile;
    46 
    4743    internal event PluginManagerActionEventHandler PluginAction;
    4844
    49     internal PluginInfo[] ActivePlugins {
     45    internal ICollection<PluginInfo> ActivePlugins {
    5046      get {
    51         PluginInfo[] plugins = new PluginInfo[activePlugins.Count];
    52         activePlugins.Keys.CopyTo(plugins, 0);
    53         return plugins;
    54       }
    55     }
    56 
    57     internal List<PluginInfo> InstalledPlugins {
     47        List<PluginInfo> list = new List<PluginInfo>();
     48        foreach(PluginInfo info in allPlugins.Keys) {
     49          if(!disabledPlugins.Exists(delegate(PluginInfo disabledInfo) { return info.Name == disabledInfo.Name; })) {
     50            list.Add(info);
     51          }
     52        }
     53        return list;
     54      }
     55    }
     56
     57    internal ICollection<PluginInfo> InstalledPlugins {
    5858      get {
    5959        return new List<PluginInfo>(allPlugins.Keys);
     
    6161    }
    6262
    63     private ApplicationInfo[] applications;
    64     internal ApplicationInfo[] InstalledApplications {
     63    internal ICollection<PluginInfo> DisabledPlugins {
     64      get {
     65        return disabledPlugins;
     66      }
     67    }
     68
     69    private ICollection<ApplicationInfo> applications;
     70    internal ICollection<ApplicationInfo> InstalledApplications {
    6571      get {
    6672        return applications;
     
    6975
    7076    private IPlugin FindPlugin(PluginInfo plugin) {
    71       return activePlugins[plugin];
     77      return allPlugins[plugin];
    7278    }
    7379
     
    8591    internal void Init() {
    8692      AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += delegate(object sender, ResolveEventArgs args) { return Assembly.ReflectionOnlyLoad(args.Name); };
    87       activePlugins.Clear();
    8893      allPlugins.Clear();
     94      disabledPlugins.Clear();
    8995      pluginInfos.Clear();
    9096      pluginsByName.Clear();
    91       loadablePlugins.Clear();
    9297      pluginDependencies.Clear();
    93       pluginAssemblies.Clear();
    9498
    9599      List<Assembly> assemblies = ReflectionOnlyLoadDlls();
    96100      CheckAssemblyDependencies(assemblies);
     101      CheckPluginFiles();
     102      CheckPluginDependencies();
    97103      LoadPlugins();
    98       CheckPluginFiles();
    99104
    100105      DiscoveryService service = new DiscoveryService();
    101106      IApplication[] apps = service.GetInstances<IApplication>();
    102       applications = new ApplicationInfo[apps.Length];
    103 
    104       int i = 0;
     107      applications = new List<ApplicationInfo>();
     108
    105109      foreach(IApplication application in apps) {
    106110        ApplicationInfo info = new ApplicationInfo();
     
    111115        info.PluginType = application.GetType().Namespace + "." + application.GetType().Name;
    112116
    113         applications[i++] = info;
     117        applications.Add(info);
    114118      }
    115119    }
     
    129133
    130134    private void CheckAssemblyDependencies(List<Assembly> assemblies) {
    131 
    132135      foreach(Assembly assembly in assemblies) {
    133 
    134136        // GetExportedTypes throws FileNotFoundException when a referenced assembly
    135137        // of the current assembly is missing.
     
    138140
    139141          foreach(Type t in exported) {
    140             // if the type implements IPlugin
     142            // if there is a type that implements IPlugin
    141143            if(Array.Exists<Type>(t.GetInterfaces(), delegate(Type iface) {
    142144              // use AssemblyQualifiedName to compare the types because we can't directly
     
    144146              return iface.AssemblyQualifiedName == typeof(IPlugin).AssemblyQualifiedName;
    145147            })) {
     148              // fetch the attributes of the IPlugin type
    146149              GetPluginAttributeData(t);
    147150            }
    148 
    149151          }
    150152        } catch(FileNotFoundException) {
    151153          // when a referenced assembly cannot be loaded then ignore this assembly in the plugin discovery
    152           // TASK: add the assembly to some kind of unloadable assemblies list
    153           // this list could be displayed to the user for diagnosis         
    154         }
    155       }
    156 
    157       foreach(string pluginName in this.pluginDependencies.Keys) {
    158         CheckPluginDependencies(pluginName);
     154        }
    159155      }
    160156    }
     
    169165      // get all attributes of that type
    170166      IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(t);
    171 
    172167      List<string> pluginAssemblies = new List<string>();
    173168      List<string> pluginDependencies = new List<string>();
     169      List<string> pluginFiles = new List<string>();
    174170      string pluginName = "";
    175 
    176       // extract relevant parameters
    177171      // iterate through all custom attributes and search for named arguments that we are interested in
    178172      foreach(CustomAttributeData attributeData in attributes) {
    179173        List<CustomAttributeNamedArgument> namedArguments = new List<CustomAttributeNamedArgument>(attributeData.NamedArguments);
    180 
    181174        // if the current attribute contains a named argument with the name "Name" then extract the plugin name
    182175        CustomAttributeNamedArgument pluginNameArgument = namedArguments.Find(delegate(CustomAttributeNamedArgument arg) {
     
    186179          pluginName = (string)pluginNameArgument.TypedValue.Value;
    187180        }
    188 
    189181        // if the current attribute contains a named argument with the name "Dependency" then extract the dependency
    190182        // and store it in the list of all dependencies
     
    192184          return arg.MemberInfo.Name == "Dependency";
    193185        });
    194 
    195186        if(dependencyNameArgument.MemberInfo != null) {
    196187          pluginDependencies.Add((string)dependencyNameArgument.TypedValue.Value);
    197188        }
    198 
    199189        // if the current attribute has a named argument "Filename" then find if the argument "Filetype" is also supplied
    200190        // and if the filetype is Assembly then store the name of the assembly in the list of assemblies
     
    206196        });
    207197        if(filenameArg.MemberInfo != null && filetypeArg.MemberInfo != null) {
     198          pluginFiles.Add(pluginDir + "/" + (string)filenameArg.TypedValue.Value);
    208199          if((PluginFileType)filetypeArg.TypedValue.Value == PluginFileType.Assembly) {
    209200            pluginAssemblies.Add(pluginDir + "/" + (string)filenameArg.TypedValue.Value);
     
    212203      }
    213204
    214       // make sure that we found reasonable values
     205      // minimal sanity check of the attribute values
    215206      if(pluginName != "" && pluginAssemblies.Count > 0) {
    216         this.pluginDependencies[pluginName] = pluginDependencies;
    217         this.pluginAssemblies[pluginName] = pluginAssemblies;
     207        // create a temporary PluginInfo that contains the attribute values
     208        PluginInfo info = new PluginInfo();
     209        info.Name = pluginName;
     210        info.Assemblies = pluginAssemblies;
     211        info.Files.AddRange(pluginFiles);
     212        info.Assemblies.AddRange(pluginAssemblies);
     213        this.pluginDependencies[info] = pluginDependencies;
     214        preloadedPluginInfos.Add(info);
    218215      } else {
    219216        throw new InvalidPluginException();
     
    221218    }
    222219
     220    private void CheckPluginDependencies() {
     221      foreach(PluginInfo pluginInfo in preloadedPluginInfos) {
     222        // don't need to check plugins that are already disabled
     223        if(disabledPlugins.Contains(pluginInfo)) {
     224          continue;
     225        }
     226        visitedDependencies.Clear();
     227        if(!CheckPluginDependencies(pluginInfo.Name)) {
     228          disabledPlugins.Add(pluginInfo);
     229        }
     230      }
     231    }
     232
     233    private List<string> visitedDependencies = new List<string>();
    223234    private bool CheckPluginDependencies(string pluginName) {
    224       // when we already checked the dependencies of this plugin earlier then just return true
    225       if(loadablePlugins.Contains(pluginName)) {
    226         return true;
    227       } else if(!pluginAssemblies.ContainsKey(pluginName)) {
     235      if(!preloadedPluginInfos.Exists(delegate(PluginInfo info) { return pluginName == info.Name; }) ||
     236        disabledPlugins.Exists(delegate(PluginInfo info) { return pluginName == info.Name; }) ||
     237        visitedDependencies.Contains(pluginName)) {
    228238        // when the plugin is not available return false;
    229239        return false;
     
    231241        // otherwise check if all dependencies of the plugin are OK
    232242        // if yes then this plugin is also ok and we store it in the list of loadable plugins
    233         foreach(string dependency in pluginDependencies[pluginName]) {
     243
     244        PluginInfo matchingInfo = preloadedPluginInfos.Find(delegate(PluginInfo info) { return info.Name == pluginName; });
     245        if(matchingInfo == null) throw new InvalidProgramException(); // shouldn't happen
     246        foreach(string dependency in pluginDependencies[matchingInfo]) {
     247          visitedDependencies.Add(pluginName);
    234248          if(CheckPluginDependencies(dependency) == false) {
    235249            // if only one dependency is not available that means that the current plugin also is unloadable
    236250            return false;
    237251          }
    238         }
    239         // all dependencies OK -> add to loadable list and return true
    240         loadablePlugins.Add(pluginName);
     252          visitedDependencies.Remove(pluginName);
     253        }
     254        // all dependencies OK
    241255        return true;
    242256      }
     
    245259
    246260    private Dictionary<string, IPlugin> pluginsByName = new Dictionary<string, IPlugin>();
    247 
    248261    private void LoadPlugins() {
    249262      // load all loadable plugins (all dependencies available) into the execution context
    250       foreach(string plugin in loadablePlugins) {
    251         {
    252           foreach(string assembly in pluginAssemblies[plugin]) {
     263      foreach(PluginInfo pluginInfo in preloadedPluginInfos) {
     264        if(!disabledPlugins.Contains(pluginInfo)) {
     265          foreach(string assembly in pluginInfo.Assemblies) {
    253266            Assembly.LoadFrom(assembly);
    254267          }
     
    263276          continue;
    264277        Type[] availablePluginTypes = service.GetTypes(typeof(IPlugin), assembly);
    265 
    266 
    267278        foreach(Type pluginType in availablePluginTypes) {
    268279          if(!pluginType.IsAbstract && !pluginType.IsInterface && !pluginType.HasElementType) {
    269280            IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
    270281            PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializingPlugin));
    271 
    272282            pluginsByName.Add(plugin.Name, plugin);
    273             PluginInfo pluginInfo = GetPluginInfo(plugin);
    274 
    275 
    276             allPlugins.Add(pluginInfo, plugin);
    277             PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializedPlugin));
    278           }
    279         }
    280       }
    281     }
    282 
    283 
     283          }
     284        }
     285      }
     286
     287      foreach(IPlugin plugin in pluginsByName.Values) {
     288        PluginInfo pluginInfo = GetPluginInfo(plugin);
     289        allPlugins.Add(pluginInfo, plugin);
     290        PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializedPlugin));
     291      }
     292    }
    284293    private PluginInfo GetPluginInfo(IPlugin plugin) {
    285294      if(pluginInfos.ContainsKey(plugin)) {
    286295        return pluginInfos[plugin];
    287296      }
    288 
    289297      // store the data of the plugin in a description file which can be used without loading the plugin assemblies
    290298      PluginInfo pluginInfo = new PluginInfo();
     
    299307      });
    300308
    301       // each plugin can have multiple assemlies associated
    302       // for each assembly of the plugin find the dependencies
    303       // and get the pluginDescriptions for all dependencies
    304       foreach(string assembly in pluginAssemblies[plugin.Name]) {
     309      PluginInfo preloadedInfo = preloadedPluginInfos.Find(delegate(PluginInfo info) { return info.Name == plugin.Name; });
     310      foreach(string assembly in preloadedInfo.Assemblies) {
    305311        // always use \ as directory separator (this is necessary for discovery of types in
    306312        // plugins see DiscoveryService.GetTypes()
    307313        pluginInfo.Assemblies.Add(assembly.Replace('/', '\\'));
    308 
    309       }
    310       foreach(string dependency in pluginDependencies[plugin.Name]) {
     314      }
     315      foreach(string dependency in pluginDependencies[preloadedInfo]) {
    311316        // accumulate the dependencies of each assembly into the dependencies of the whole plugin
    312317        PluginInfo dependencyInfo = GetPluginInfo(pluginsByName[dependency]);
    313318        pluginInfo.Dependencies.Add(dependencyInfo);
    314319      }
    315 
    316320      pluginInfos[plugin] = pluginInfo;
    317 
    318321      return pluginInfo;
    319322    }
    320323
    321324    private void CheckPluginFiles() {
    322       foreach(PluginInfo plugin in allPlugins.Keys) {
    323         CheckPluginFiles(plugin);
     325      foreach(PluginInfo plugin in preloadedPluginInfos) {
     326        if(!CheckPluginFiles(plugin)) {
     327          disabledPlugins.Add(plugin);
     328        }
    324329      }
    325330    }
    326331
    327332    private bool CheckPluginFiles(PluginInfo pluginInfo) {
    328       if(activePlugins.ContainsKey(pluginInfo)) {
    329         return true;
    330       }
    331       foreach(PluginInfo dependency in pluginInfo.Dependencies) {
    332         if(!CheckPluginFiles(dependency)) {
    333           return false;
    334         }
    335       }
    336333      foreach(string filename in pluginInfo.Files) {
    337334        if(!File.Exists(filename)) {
    338           MissingPluginFile(pluginInfo.Name, filename);
     335          if(MissingPluginFile != null) {
     336            MissingPluginFile(pluginInfo.Name, filename);
     337          }
    339338          return false;
    340339        }
    341340      }
    342 
    343       activePlugins.Add(pluginInfo, allPlugins[pluginInfo]);
    344341      return true;
    345342    }
Note: See TracChangeset for help on using the changeset viewer.