Changeset 29 for trunk/sources
- Timestamp:
- 02/28/08 18:02:45 (16 years ago)
- Location:
- trunk/sources
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.PluginInfrastructure.GUI/ManagerForm.cs
r18 r29 37 37 private TreeNode availablePlugins; 38 38 private TreeNode allPlugins; 39 private TreeNode disabledPlugins; 39 40 private List<PluginTag> allTags = new List<PluginTag>(); 40 41 private Dictionary<PluginTag, PluginAction> actions = new Dictionary<PluginTag, PluginAction>(); … … 75 76 allPlugins.ImageIndex = 1; 76 77 allPlugins.SelectedImageIndex = 1; 78 disabledPlugins = new TreeNode("Disabled plugins"); 79 disabledPlugins.ImageIndex = 1; 80 disabledPlugins.SelectedImageIndex = 1; 77 81 78 82 pluginTreeView.Nodes.Add(installedPlugins); 79 83 pluginTreeView.Nodes.Add(availablePlugins); 84 pluginTreeView.Nodes.Add(disabledPlugins); 80 85 pluginTreeView.Nodes.Add(allPlugins); 81 86 82 foreach(PluginInfo pluginInfo in PluginManager.Manager. InstalledPlugins) {87 foreach(PluginInfo pluginInfo in PluginManager.Manager.ActivePlugins) { 83 88 // create a new PluginAction tag for the plugin 84 89 PluginTag tag = new PluginTag(allTags, pluginInfo, PluginState.Installed); … … 91 96 installedPlugins.Nodes.Add(installedPluginsNode); 92 97 98 // add to all "plugins node" 99 TreeNode allPluginsNode = new TreeNode(pluginInfo.Name); 100 allPluginsNode.ContextMenuStrip = pluginContextMenuStrip; 101 allPluginsNode.Tag = tag; 102 allPluginsNode.ImageIndex = 0; 103 allPlugins.Nodes.Add(allPluginsNode); 104 } 105 foreach(PluginInfo pluginInfo in PluginManager.Manager.DisabledPlugins) { 106 PluginTag tag = new PluginTag(allTags, pluginInfo, PluginState.Disabled); 107 allTags.Add(tag); 108 TreeNode disabledPluginsNode = new TreeNode(pluginInfo.Name); 109 disabledPluginsNode.ContextMenuStrip = pluginContextMenuStrip; 110 disabledPluginsNode.Tag = tag; 111 disabledPluginsNode.ImageIndex = 0; 112 disabledPlugins.Nodes.Add(disabledPluginsNode); 93 113 // add to all "plugins node" 94 114 TreeNode allPluginsNode = new TreeNode(pluginInfo.Name); … … 290 310 allAvailablePlugins.ForEach(delegate(PluginDescription availablePlugin) { 291 311 List<PluginTag> oldPlugins = allTags.FindAll(delegate(PluginTag currentPlugin) { 292 return currentPlugin.PluginName == availablePlugin.Name && currentPlugin.State == PluginState.Installed;312 return currentPlugin.PluginName == availablePlugin.Name && currentPlugin.State == (PluginState.Installed | PluginState.Disabled); 293 313 }); 294 314 … … 567 587 publishButton.Enabled = (tag.State & PluginState.Installed) == PluginState.Installed; 568 588 installButton.Enabled = (tag.State & PluginState.Available) == PluginState.Available; 569 deleteButton.Enabled = (tag.State & (PluginState.Installed | PluginState.Upgradeable )) != 0;589 deleteButton.Enabled = (tag.State & (PluginState.Installed | PluginState.Upgradeable | PluginState.Disabled)) != 0; 570 590 571 591 installButton.Checked = GetAction(tag) == ManagerAction.Install; … … 605 625 private List<TreeNode> FindPluginNodes(PluginTag pluginTag) { 606 626 List<TreeNode> nodes = new List<TreeNode>(); 607 foreach(TreeNode rootNode in new TreeNode[] { installedPlugins, availablePlugins, allPlugins }) {627 foreach(TreeNode rootNode in new TreeNode[] { installedPlugins, availablePlugins, allPlugins, disabledPlugins }) { 608 628 foreach(TreeNode node in rootNode.Nodes) { 609 629 if(pluginTag.Equals(node.Tag)) { -
trunk/sources/HeuristicLab.PluginInfrastructure.GUI/PluginTag.cs
r2 r29 31 31 Available = 2, 32 32 Upgradeable = 4, 33 Disabled = 8, 33 34 }; 34 35 … … 218 219 219 220 public override int GetHashCode() { 220 return pluginName.GetHashCode() + pluginVersion.GetHashCode(); 221 if(pluginVersion != null) { 222 return pluginName.GetHashCode() + pluginVersion.GetHashCode(); 223 } else return pluginName.GetHashCode(); 221 224 } 222 225 } -
trunk/sources/HeuristicLab.PluginInfrastructure/DiscoveryService.cs
r2 r29 33 33 public PluginInfo[] Plugins { 34 34 get { 35 return PluginManager.Manager.LoadedPlugins; 35 PluginInfo[] plugins = new PluginInfo[PluginManager.Manager.LoadedPlugins.Count]; 36 PluginManager.Manager.LoadedPlugins.CopyTo(plugins, 0); 37 return plugins; 36 38 } 37 39 } -
trunk/sources/HeuristicLab.PluginInfrastructure/Loader.cs
r28 r29 33 33 public delegate void PluginLoadFailedEventHandler(string pluginName, string args); 34 34 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>(); 36 38 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>(); 43 40 private string pluginDir = Application.StartupPath + "/" + HeuristicLab.PluginInfrastructure.Properties.Settings.Default.PluginDir; 44 41 45 42 internal event PluginLoadFailedEventHandler MissingPluginFile; 46 47 43 internal event PluginManagerActionEventHandler PluginAction; 48 44 49 internal PluginInfo[]ActivePlugins {45 internal ICollection<PluginInfo> ActivePlugins { 50 46 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 { 58 58 get { 59 59 return new List<PluginInfo>(allPlugins.Keys); … … 61 61 } 62 62 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 { 65 71 get { 66 72 return applications; … … 69 75 70 76 private IPlugin FindPlugin(PluginInfo plugin) { 71 return a ctivePlugins[plugin];77 return allPlugins[plugin]; 72 78 } 73 79 … … 85 91 internal void Init() { 86 92 AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += delegate(object sender, ResolveEventArgs args) { return Assembly.ReflectionOnlyLoad(args.Name); }; 87 activePlugins.Clear();88 93 allPlugins.Clear(); 94 disabledPlugins.Clear(); 89 95 pluginInfos.Clear(); 90 96 pluginsByName.Clear(); 91 loadablePlugins.Clear();92 97 pluginDependencies.Clear(); 93 pluginAssemblies.Clear();94 98 95 99 List<Assembly> assemblies = ReflectionOnlyLoadDlls(); 96 100 CheckAssemblyDependencies(assemblies); 101 CheckPluginFiles(); 102 CheckPluginDependencies(); 97 103 LoadPlugins(); 98 CheckPluginFiles();99 104 100 105 DiscoveryService service = new DiscoveryService(); 101 106 IApplication[] apps = service.GetInstances<IApplication>(); 102 applications = new ApplicationInfo[apps.Length]; 103 104 int i = 0; 107 applications = new List<ApplicationInfo>(); 108 105 109 foreach(IApplication application in apps) { 106 110 ApplicationInfo info = new ApplicationInfo(); … … 111 115 info.PluginType = application.GetType().Namespace + "." + application.GetType().Name; 112 116 113 applications [i++] = info;117 applications.Add(info); 114 118 } 115 119 } … … 129 133 130 134 private void CheckAssemblyDependencies(List<Assembly> assemblies) { 131 132 135 foreach(Assembly assembly in assemblies) { 133 134 136 // GetExportedTypes throws FileNotFoundException when a referenced assembly 135 137 // of the current assembly is missing. … … 138 140 139 141 foreach(Type t in exported) { 140 // if the typeimplements IPlugin142 // if there is a type that implements IPlugin 141 143 if(Array.Exists<Type>(t.GetInterfaces(), delegate(Type iface) { 142 144 // use AssemblyQualifiedName to compare the types because we can't directly … … 144 146 return iface.AssemblyQualifiedName == typeof(IPlugin).AssemblyQualifiedName; 145 147 })) { 148 // fetch the attributes of the IPlugin type 146 149 GetPluginAttributeData(t); 147 150 } 148 149 151 } 150 152 } catch(FileNotFoundException) { 151 153 // 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 allDependencies.Clear(); 159 CheckPluginDependencies(pluginName); 154 } 160 155 } 161 156 } … … 170 165 // get all attributes of that type 171 166 IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(t); 172 173 167 List<string> pluginAssemblies = new List<string>(); 174 168 List<string> pluginDependencies = new List<string>(); 169 List<string> pluginFiles = new List<string>(); 175 170 string pluginName = ""; 176 177 // extract relevant parameters178 171 // iterate through all custom attributes and search for named arguments that we are interested in 179 172 foreach(CustomAttributeData attributeData in attributes) { 180 173 List<CustomAttributeNamedArgument> namedArguments = new List<CustomAttributeNamedArgument>(attributeData.NamedArguments); 181 182 174 // if the current attribute contains a named argument with the name "Name" then extract the plugin name 183 175 CustomAttributeNamedArgument pluginNameArgument = namedArguments.Find(delegate(CustomAttributeNamedArgument arg) { … … 187 179 pluginName = (string)pluginNameArgument.TypedValue.Value; 188 180 } 189 190 181 // if the current attribute contains a named argument with the name "Dependency" then extract the dependency 191 182 // and store it in the list of all dependencies … … 193 184 return arg.MemberInfo.Name == "Dependency"; 194 185 }); 195 196 186 if(dependencyNameArgument.MemberInfo != null) { 197 187 pluginDependencies.Add((string)dependencyNameArgument.TypedValue.Value); 198 188 } 199 200 189 // if the current attribute has a named argument "Filename" then find if the argument "Filetype" is also supplied 201 190 // and if the filetype is Assembly then store the name of the assembly in the list of assemblies … … 207 196 }); 208 197 if(filenameArg.MemberInfo != null && filetypeArg.MemberInfo != null) { 198 pluginFiles.Add(pluginDir + "/" + (string)filenameArg.TypedValue.Value); 209 199 if((PluginFileType)filetypeArg.TypedValue.Value == PluginFileType.Assembly) { 210 200 pluginAssemblies.Add(pluginDir + "/" + (string)filenameArg.TypedValue.Value); … … 213 203 } 214 204 215 // m ake sure that we found reasonable values205 // minimal sanity check of the attribute values 216 206 if(pluginName != "" && pluginAssemblies.Count > 0) { 217 this.pluginDependencies[pluginName] = pluginDependencies; 218 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); 219 215 } else { 220 216 throw new InvalidPluginException(); … … 222 218 } 223 219 224 private List<string> allDependencies = new List<string>(); 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>(); 225 234 private bool CheckPluginDependencies(string pluginName) { 226 // when we already checked the dependencies of this plugin earlier then just return true 227 if(loadablePlugins.Contains(pluginName)) { 228 return true; 229 } else if(!pluginAssemblies.ContainsKey(pluginName) || allDependencies.Contains(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)) { 230 238 // when the plugin is not available return false; 231 239 return false; … … 233 241 // otherwise check if all dependencies of the plugin are OK 234 242 // if yes then this plugin is also ok and we store it in the list of loadable plugins 235 allDependencies.Add(pluginName); 236 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); 237 248 if(CheckPluginDependencies(dependency) == false) { 238 249 // if only one dependency is not available that means that the current plugin also is unloadable 239 250 return false; 240 251 } 241 }242 // all dependencies OK -> add to loadable list and return true243 loadablePlugins.Add(pluginName);252 visitedDependencies.Remove(pluginName); 253 } 254 // all dependencies OK 244 255 return true; 245 256 } … … 248 259 249 260 private Dictionary<string, IPlugin> pluginsByName = new Dictionary<string, IPlugin>(); 250 251 261 private void LoadPlugins() { 252 262 // load all loadable plugins (all dependencies available) into the execution context 253 foreach( string plugin in loadablePlugins) {254 {255 foreach(string assembly in plugin Assemblies[plugin]) {263 foreach(PluginInfo pluginInfo in preloadedPluginInfos) { 264 if(!disabledPlugins.Contains(pluginInfo)) { 265 foreach(string assembly in pluginInfo.Assemblies) { 256 266 Assembly.LoadFrom(assembly); 257 267 } … … 266 276 continue; 267 277 Type[] availablePluginTypes = service.GetTypes(typeof(IPlugin), assembly); 268 269 270 278 foreach(Type pluginType in availablePluginTypes) { 271 279 if(!pluginType.IsAbstract && !pluginType.IsInterface && !pluginType.HasElementType) { 272 280 IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType); 273 281 PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializingPlugin)); 274 275 282 pluginsByName.Add(plugin.Name, plugin); 276 PluginInfo pluginInfo = GetPluginInfo(plugin); 277 278 279 allPlugins.Add(pluginInfo, plugin); 280 PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializedPlugin)); 281 } 282 } 283 } 284 } 285 286 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 } 287 293 private PluginInfo GetPluginInfo(IPlugin plugin) { 288 294 if(pluginInfos.ContainsKey(plugin)) { 289 295 return pluginInfos[plugin]; 290 296 } 291 292 297 // store the data of the plugin in a description file which can be used without loading the plugin assemblies 293 298 PluginInfo pluginInfo = new PluginInfo(); … … 302 307 }); 303 308 304 // each plugin can have multiple assemlies associated 305 // for each assembly of the plugin find the dependencies 306 // and get the pluginDescriptions for all dependencies 307 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) { 308 311 // always use \ as directory separator (this is necessary for discovery of types in 309 312 // plugins see DiscoveryService.GetTypes() 310 313 pluginInfo.Assemblies.Add(assembly.Replace('/', '\\')); 311 312 } 313 foreach(string dependency in pluginDependencies[plugin.Name]) { 314 } 315 foreach(string dependency in pluginDependencies[preloadedInfo]) { 314 316 // accumulate the dependencies of each assembly into the dependencies of the whole plugin 315 317 PluginInfo dependencyInfo = GetPluginInfo(pluginsByName[dependency]); 316 318 pluginInfo.Dependencies.Add(dependencyInfo); 317 319 } 318 319 320 pluginInfos[plugin] = pluginInfo; 320 321 321 return pluginInfo; 322 322 } 323 323 324 324 private void CheckPluginFiles() { 325 foreach(PluginInfo plugin in allPlugins.Keys) { 326 CheckPluginFiles(plugin); 325 foreach(PluginInfo plugin in preloadedPluginInfos) { 326 if(!CheckPluginFiles(plugin)) { 327 disabledPlugins.Add(plugin); 328 } 327 329 } 328 330 } 329 331 330 332 private bool CheckPluginFiles(PluginInfo pluginInfo) { 331 if(activePlugins.ContainsKey(pluginInfo)) {332 return true;333 }334 foreach(PluginInfo dependency in pluginInfo.Dependencies) {335 if(!CheckPluginFiles(dependency)) {336 return false;337 }338 }339 333 foreach(string filename in pluginInfo.Files) { 340 334 if(!File.Exists(filename)) { 341 MissingPluginFile(pluginInfo.Name, filename); 335 if(MissingPluginFile != null) { 336 MissingPluginFile(pluginInfo.Name, filename); 337 } 342 338 return false; 343 339 } 344 340 } 345 346 activePlugins.Add(pluginInfo, allPlugins[pluginInfo]);347 341 return true; 348 342 } -
trunk/sources/HeuristicLab.PluginInfrastructure/PluginInfo.cs
r2 r29 83 83 84 84 public override int GetHashCode() { 85 return name.GetHashCode() + version.GetHashCode(); 85 if(version != null) { 86 return name.GetHashCode() + version.GetHashCode(); 87 } else return name.GetHashCode(); 86 88 } 87 89 } -
trunk/sources/HeuristicLab.PluginInfrastructure/PluginManager.cs
r2 r29 53 53 } 54 54 55 public List<PluginInfo> InstalledPlugins {55 public ICollection<PluginInfo> InstalledPlugins { 56 56 get { return remoteLoader.InstalledPlugins; } 57 57 } 58 58 59 public ApplicationInfo[] InstalledApplications { 59 public ICollection<PluginInfo> DisabledPlugins { 60 get { return remoteLoader.DisabledPlugins; } 61 } 62 63 public ICollection<PluginInfo> ActivePlugins { 64 get { return remoteLoader.ActivePlugins; } 65 } 66 67 public ICollection<ApplicationInfo> InstalledApplications { 60 68 get { return remoteLoader.InstalledApplications; } 61 69 } 62 70 63 private PluginInfo[]loadedPlugins;64 public PluginInfo[]LoadedPlugins {71 private ICollection<PluginInfo> loadedPlugins; 72 public ICollection<PluginInfo> LoadedPlugins { 65 73 get { return loadedPlugins; } 66 74 internal set { loadedPlugins = value; } … … 72 80 public void Initialize() { 73 81 NotifyListeners(PluginManagerAction.Initializing, "-"); 74 75 82 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; 76 83 setup.PrivateBinPath = pluginDir; 77 84 pluginDomain = AppDomain.CreateDomain("plugin domain", null, setup); 78 79 85 remoteLoader = (Loader)pluginDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfraStructure", "HeuristicLab.PluginInfrastructure.Loader"); 80 81 86 remoteLoader.PluginAction += delegate(object sender, PluginManagerActionEventArgs args) { if(Action != null) Action(this, args); }; 82 87 remoteLoader.Init(); 83 84 88 NotifyListeners(PluginManagerAction.Initialized, "-"); 85 89 } … … 99 103 setup.PrivateBinPath = pluginDir; 100 104 AppDomain applicationDomain = AppDomain.CreateDomain(appInfo.Name + " AppDomain", null, setup); 101 105 102 106 Runner remoteRunner = (Runner)applicationDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfrastructure", "HeuristicLab.PluginInfrastructure.Runner"); 103 107 NotifyListeners(PluginManagerAction.Initializing, "All plugins"); … … 116 120 public List<PluginInfo> GetDependentPlugins(PluginInfo pluginInfo) { 117 121 List<PluginInfo> mergedList = new List<PluginInfo>(); 118 InstalledPlugins.ForEach(delegate(PluginInfo plugin) {122 foreach(PluginInfo plugin in InstalledPlugins) { 119 123 if(plugin.Dependencies.Contains(pluginInfo)) { 120 124 if(!mergedList.Contains(plugin)) { … … 125 129 GetDependentPlugins(plugin).ForEach(delegate(PluginInfo dependentPlugin) { 126 130 if(!mergedList.Contains(dependentPlugin)) { 127 mergedList.Add(dependentPlugin); 131 mergedList.Add(dependentPlugin); 128 132 } 129 133 }); 130 134 } 131 }); 132 135 } 133 136 return mergedList; 134 137 } -
trunk/sources/HeuristicLab.PluginInfrastructure/Runner.cs
r2 r29 28 28 internal class Runner : MarshalByRefObject { 29 29 30 public void LoadPlugins( PluginInfo[]plugins) {30 public void LoadPlugins(ICollection<PluginInfo> plugins) { 31 31 foreach(PluginInfo pluginInfo in plugins) { 32 32 foreach(string assemblyName in pluginInfo.Assemblies) { … … 34 34 } 35 35 } 36 37 36 PluginManager.Manager.LoadedPlugins = plugins; 38 37 }
Note: See TracChangeset
for help on using the changeset viewer.