Changeset 2750 for trunk/sources/HeuristicLab.PluginInfrastructure
- Timestamp:
- 02/04/10 12:20:43 (15 years ago)
- Location:
- trunk/sources/HeuristicLab.PluginInfrastructure
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.PluginInfrastructure/Attributes/AssemblyBuildDateAttribute.cs
r2504 r2750 45 45 /// <exception cref="FormatException">Thrown when the time stamp could not be parsed as build date.</exception> 46 46 /// <param name="buildDate">The build date of the assembly.</param> 47 [Obsolete] 47 48 public AssemblyBuildDateAttribute(string buildDate) 48 49 : base() { -
trunk/sources/HeuristicLab.PluginInfrastructure/Attributes/PluginAttribute.cs
r2748 r2750 47 47 } 48 48 49 private Version version; 50 /// <summary> 51 /// Gets the version of the plugin. 52 /// </summary> 53 public Version Version { 54 get { return version; } 55 } 56 57 [Obsolete] 58 public PluginAttribute(string name) : this(name, "0.0.0.0") { } 59 49 60 /// <summary> 50 61 /// Initializes a new instance of <see cref="PluginAttribute"/>. 51 62 /// <param name="name">Name of the plugin</param> 63 /// <param name="version">Version of the plugin</param> 52 64 /// </summary> 53 public PluginAttribute(string name )54 : this(name, string.Empty ) {65 public PluginAttribute(string name, string version) 66 : this(name, string.Empty, version) { 55 67 } 56 68 57 69 /// <summary> 58 70 /// Initializes a new instance of <see cref="PluginAttribute"/>. 71 /// </summary> 59 72 /// <param name="name">Name of the plugin</param> 60 73 /// <param name="description">Description of the plugin</param> 61 /// < /summary>62 public PluginAttribute(string name, string description ) {74 /// <param name="version">Version of the plugin</param> 75 public PluginAttribute(string name, string description, string version) { 63 76 if (string.IsNullOrEmpty(name)) throw new ArgumentException("Plugin name is null or empty."); 64 77 if (description == null) throw new ArgumentNullException("description"); 78 if (string.IsNullOrEmpty(version)) new ArgumentException("Version string is null or empty."); 65 79 this.name = name; 66 80 this.description = description; 81 this.version = new Version(version); // throws format exception if the version string can't be parsed 67 82 } 68 83 } -
trunk/sources/HeuristicLab.PluginInfrastructure/Attributes/PluginDependencyAttribute.cs
r2748 r2750 39 39 } 40 40 41 private Version version; 42 /// <summary> 43 /// Gets the version of the plugin dependency. 44 /// </summary> 45 public Version Version { 46 get { return version; } 47 } 48 41 49 /// <summary> 42 50 /// Initializes a new instance of <see cref="PluginDependencyAttribute"/>. 43 51 /// <param name="dependency">The name of the plugin that is needed to load a plugin.</param> 44 52 /// </summary> 45 public PluginDependencyAttribute(string dependency) { 46 if (string.IsNullOrEmpty(dependency)) throw new ArgumentException("Dependency is null or empty.", "dependency"); 53 [Obsolete] 54 public PluginDependencyAttribute(string dependency) 55 : this(dependency, "0.0.0.0") { 56 } 57 58 public PluginDependencyAttribute(string dependency, string version) { 59 if (string.IsNullOrEmpty(dependency)) throw new ArgumentException("Dependency name is null or empty.", "dependency"); 60 if (string.IsNullOrEmpty(version)) throw new ArgumentException("Dependency version is null or empty.", "version"); 47 61 this.dependency = dependency; 62 this.version = new Version(version); // throws format exception if the version string can't be parsed 48 63 } 49 64 } -
trunk/sources/HeuristicLab.PluginInfrastructure/InvalidPluginException.cs
r2504 r2750 31 31 [Serializable] 32 32 public sealed class InvalidPluginException : Exception { 33 /// <summary> 34 /// Initializes a new InvalidPluginException 35 /// </summary> 33 36 public InvalidPluginException() : base() { } 37 /// <summary> 38 /// Initializes a new InvalidPluginException with an error message. 39 /// </summary> 40 /// <param name="message">The exception message</param> 34 41 public InvalidPluginException(string message) : base(message) { } 35 public InvalidPluginException(string message, Exception exception) : base(message, exception) { } 42 /// <summary> 43 /// Initializes a new InvalidPluginException with an error message and an inner exception. 44 /// </summary> 45 /// <param name="message">The exception message.</param> 46 /// <param name="innerException">The original exception.</param> 47 public InvalidPluginException(string message, Exception innerException) : base(message, innerException) { } 48 /// <summary> 49 /// Constructor for serialization. 50 /// </summary> 51 /// <param name="info">The serialization info.</param> 52 /// <param name="contex">The serialization context.</param> 36 53 private InvalidPluginException(SerializationInfo info, StreamingContext contex) : base(info, contex) { } 37 54 } -
trunk/sources/HeuristicLab.PluginInfrastructure/Manager/PluginValidator.cs
r2690 r2750 36 36 /// </summary> 37 37 internal sealed class PluginValidator : MarshalByRefObject { 38 // private class to store plugin dependency declarations while reflecting over plugins 39 private class PluginDependency { 40 public string Name { get; private set; } 41 public Version Version { get; private set; } 42 43 public PluginDependency(string name, Version version) { 44 this.Name = name; 45 this.Version = version; 46 } 47 } 48 49 38 50 internal event EventHandler<PluginInfrastructureEventArgs> PluginLoaded; 39 51 40 private Dictionary<PluginDescription, List<string>> pluginDependencies;52 private Dictionary<PluginDescription, IEnumerable<PluginDependency>> pluginDependencies; 41 53 42 54 private List<ApplicationDescription> applications; … … 61 73 62 74 internal PluginValidator() { 63 this.pluginDependencies = new Dictionary<PluginDescription, List<string>>();75 this.pluginDependencies = new Dictionary<PluginDescription, IEnumerable<PluginDependency>>(); 64 76 65 77 // ReflectionOnlyAssemblyResolveEvent must be handled because we load assemblies from the plugin path … … 250 262 // get all attributes of that type 251 263 IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(pluginType); 252 List< string> pluginDependencies = new List<string>();264 List<PluginDependency> pluginDependencies = new List<PluginDependency>(); 253 265 List<PluginFile> pluginFiles = new List<PluginFile>(); 254 266 string pluginName = null; 255 267 string pluginDescription = null; 268 string pluginVersion = "0.0.0.0"; 256 269 // iterate through all custom attributes and search for attributed that we are interested in 257 270 foreach (CustomAttributeData attributeData in attributes) { 258 271 if (IsAttributeDataForType(attributeData, typeof(PluginAttribute))) { 259 272 pluginName = (string)attributeData.ConstructorArguments[0].Value; 260 if (attributeData.ConstructorArguments.Count() == 2) { 261 pluginDescription = (string)attributeData.ConstructorArguments[1].Value; 262 } else pluginDescription = pluginName; 273 if (attributeData.ConstructorArguments.Count() > 1) { 274 pluginVersion = (string)attributeData.ConstructorArguments[1].Value; 275 } 276 if (attributeData.ConstructorArguments.Count() > 2) { 277 pluginDescription = (string)attributeData.ConstructorArguments[2].Value; 278 } else { 279 // no description given => use name as description 280 pluginDescription = pluginName; 281 } 263 282 } else if (IsAttributeDataForType(attributeData, typeof(PluginDependencyAttribute))) { 264 pluginDependencies.Add((string)attributeData.ConstructorArguments[0].Value); 283 string name = (string)attributeData.ConstructorArguments[0].Value; 284 Version version = new Version(); 285 // check if version is given for now 286 // later when the constructore of PluginDependencyAttribute with only one argument has been removed 287 // this conditional can be removed as well 288 if (attributeData.ConstructorArguments.Count > 1) { 289 try { 290 version = new Version((string)attributeData.ConstructorArguments[1].Value); // throws FormatException 291 } 292 catch (FormatException ex) { 293 throw new InvalidPluginException("Invalid version format of dependency " + name + " in plugin " + pluginType.ToString(), ex); 294 } 295 } 296 pluginDependencies.Add(new PluginDependency(name, version)); 265 297 } else if (IsAttributeDataForType(attributeData, typeof(PluginFileAttribute))) { 266 298 string pluginFileName = (string)attributeData.ConstructorArguments[0].Value; … … 270 302 } 271 303 272 var buildDates = from attr in CustomAttributeData.GetCustomAttributes(pluginType.Assembly)273 where IsAttributeDataForType(attr, typeof(AssemblyBuildDateAttribute))274 select (string)attr.ConstructorArguments[0].Value;275 276 304 // minimal sanity check of the attribute values 277 305 if (!string.IsNullOrEmpty(pluginName) && 278 306 pluginFiles.Count > 0 && // at least on file 279 pluginFiles.Any(f => f.Type == PluginFileType.Assembly) && // at least on assembly 280 buildDates.Count() == 1) { // build date must be declared 307 pluginFiles.Any(f => f.Type == PluginFileType.Assembly)) { // at least on assembly 281 308 // create a temporary PluginDescription that contains the attribute values 282 309 PluginDescription info = new PluginDescription(); 283 310 info.Name = pluginName; 284 311 info.Description = pluginDescription; 285 info.Version = pluginType.Assembly.GetName().Version; 286 info.BuildDate = DateTime.Parse(buildDates.Single(), System.Globalization.CultureInfo.InvariantCulture); 312 info.Version = new Version(pluginVersion); 287 313 info.AddFiles(pluginFiles); 288 314 … … 303 329 private void BuildDependencyTree(IEnumerable<PluginDescription> pluginDescriptions) { 304 330 foreach (var desc in pluginDescriptions) { 305 foreach (string pluginName in pluginDependencies[desc]) { 306 var matchingDescriptions = pluginDescriptions.Where(x => x.Name == pluginName); 331 foreach (var dependency in pluginDependencies[desc]) { 332 var matchingDescriptions = from availablePlugin in pluginDescriptions 333 where availablePlugin.Name == dependency.Name 334 where IsCompatiblePluginVersion(availablePlugin.Version, dependency.Version) 335 select availablePlugin; 307 336 if (matchingDescriptions.Count() > 0) { 308 337 desc.AddDependency(matchingDescriptions.Single()); … … 313 342 } 314 343 } 344 } 345 346 /// <summary> 347 /// Checks if version <paramref name="available"/> is compatible to version <paramref name="requested"/>. 348 /// Note: the compatibility relation is not bijective. 349 /// Compatibility rules: 350 /// * major and minor number must be the same 351 /// * build and revision number of <paramref name="available"/> must be larger or equal to <paramref name="requested"/>. 352 /// </summary> 353 /// <param name="available">The available version which should be compared to <paramref name="requested"/>.</param> 354 /// <param name="requested">The requested version that must be matched.</param> 355 /// <returns></returns> 356 private bool IsCompatiblePluginVersion(Version available, Version requested) { 357 // this condition must be removed after all plugins have been updated to declare plugin and dependency versions 358 if ( 359 (requested.Major == 0 && requested.Minor == 0) || 360 (available.Major == 0 && available.Minor == 0)) return true; 361 return 362 available.Major == requested.Major && 363 available.Minor == requested.Minor && 364 available.Build >= requested.Build && 365 available.Revision >= requested.Revision; 315 366 } 316 367
Note: See TracChangeset
for help on using the changeset viewer.