1 #region Copyright & License 2 // 3 // Copyright 2001-2005 The Apache Software Foundation 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 #endregion 18 19 // .NET Compact Framework 1.0 has no support for reading assembly attributes 20 // and uses the CompactRepositorySelector instead 21 #if !NETCF 22 23 using System; 24 using System.Collections; 25 using System.Configuration; 26 using System.Reflection; 27 28 using log4net.Config; 29 using log4net.Util; 30 using log4net.Repository; 31 32 namespace log4net.Core 33 { 34 /// <summary> 35 /// The default implementation of the <see cref="IRepositorySelector"/> interface. 36 /// </summary> 37 /// <remarks> 38 /// <para> 39 /// Uses attributes defined on the calling assembly to determine how to 40 /// configure the hierarchy for the repository. 41 /// </para> 42 /// </remarks> 43 /// <author>Nicko Cadell</author> 44 /// <author>Gert Driesen</author> 45 public class DefaultRepositorySelector : IRepositorySelector 46 { 47 #region Public Events 48 49 /// <summary> 50 /// Event to notify that a logger repository has been created. 51 /// </summary> 52 /// <value> 53 /// Event to notify that a logger repository has been created. 54 /// </value> 55 /// <remarks> 56 /// <para> 57 /// Event raised when a new repository is created. 58 /// The event source will be this selector. The event args will 59 /// be a <see cref="LoggerRepositoryCreationEventArgs"/> which 60 /// holds the newly created <see cref="ILoggerRepository"/>. 61 /// </para> 62 /// </remarks> 63 public event LoggerRepositoryCreationEventHandler LoggerRepositoryCreatedEvent 64 { 65 add { m_loggerRepositoryCreatedEvent += value; } 66 remove { m_loggerRepositoryCreatedEvent -= value; } 67 } 68 69 #endregion Public Events 70 71 #region Public Instance Constructors 72 73 /// <summary> 74 /// Creates a new repository selector. 75 /// </summary> 76 /// <param name="defaultRepositoryType">The type of the repositories to create, must implement <see cref="ILoggerRepository"/></param> 77 /// <remarks> 78 /// <para> 79 /// Create an new repository selector. 80 /// The default type for repositories must be specified, 81 /// an appropriate value would be <see cref="log4net.Repository.Hierarchy.Hierarchy"/>. 82 /// </para> 83 /// </remarks> 84 /// <exception cref="ArgumentNullException"><paramref name="defaultRepositoryType"/> is <see langword="null" />.</exception> 85 /// <exception cref="ArgumentOutOfRangeException"><paramref name="defaultRepositoryType"/> does not implement <see cref="ILoggerRepository"/>.</exception> DefaultRepositorySelector(Type defaultRepositoryType)86 public DefaultRepositorySelector(Type defaultRepositoryType) 87 { 88 if (defaultRepositoryType == null) 89 { 90 throw new ArgumentNullException("defaultRepositoryType"); 91 } 92 93 // Check that the type is a repository 94 if (! (typeof(ILoggerRepository).IsAssignableFrom(defaultRepositoryType)) ) 95 { 96 throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("defaultRepositoryType", defaultRepositoryType, "Parameter: defaultRepositoryType, Value: [" + defaultRepositoryType + "] out of range. Argument must implement the ILoggerRepository interface"); 97 } 98 99 m_defaultRepositoryType = defaultRepositoryType; 100 101 LogLog.Debug("DefaultRepositorySelector: defaultRepositoryType [" + m_defaultRepositoryType + "]"); 102 } 103 104 #endregion Public Instance Constructors 105 106 #region Implementation of IRepositorySelector 107 108 /// <summary> 109 /// Gets the <see cref="ILoggerRepository"/> for the specified assembly. 110 /// </summary> 111 /// <param name="repositoryAssembly">The assembly use to lookup the <see cref="ILoggerRepository"/>.</param> 112 /// <remarks> 113 /// <para> 114 /// The type of the <see cref="ILoggerRepository"/> created and the repository 115 /// to create can be overridden by specifying the <see cref="log4net.Config.RepositoryAttribute"/> 116 /// attribute on the <paramref name="repositoryAssembly"/>. 117 /// </para> 118 /// <para> 119 /// The default values are to use the <see cref="log4net.Repository.Hierarchy.Hierarchy"/> 120 /// implementation of the <see cref="ILoggerRepository"/> interface and to use the 121 /// <see cref="AssemblyName.Name"/> as the name of the repository. 122 /// </para> 123 /// <para> 124 /// The <see cref="ILoggerRepository"/> created will be automatically configured using 125 /// any <see cref="log4net.Config.ConfiguratorAttribute"/> attributes defined on 126 /// the <paramref name="repositoryAssembly"/>. 127 /// </para> 128 /// </remarks> 129 /// <returns>The <see cref="ILoggerRepository"/> for the assembly</returns> 130 /// <exception cref="ArgumentNullException"><paramref name="repositoryAssembly"/> is <see langword="null" />.</exception> GetRepository(Assembly repositoryAssembly)131 public ILoggerRepository GetRepository(Assembly repositoryAssembly) 132 { 133 if (repositoryAssembly == null) 134 { 135 throw new ArgumentNullException("repositoryAssembly"); 136 } 137 return CreateRepository(repositoryAssembly, m_defaultRepositoryType); 138 } 139 140 /// <summary> 141 /// Gets the <see cref="ILoggerRepository"/> for the specified repository. 142 /// </summary> 143 /// <param name="repositoryName">The repository to use to lookup the <see cref="ILoggerRepository"/>.</param> 144 /// <returns>The <see cref="ILoggerRepository"/> for the specified repository.</returns> 145 /// <remarks> 146 /// <para> 147 /// Returns the named repository. If <paramref name="repositoryName"/> is <c>null</c> 148 /// a <see cref="ArgumentNullException"/> is thrown. If the repository 149 /// does not exist a <see cref="LogException"/> is thrown. 150 /// </para> 151 /// <para> 152 /// Use <see cref="CreateRepository(string, Type)"/> to create a repository. 153 /// </para> 154 /// </remarks> 155 /// <exception cref="ArgumentNullException"><paramref name="repositoryName"/> is <see langword="null" />.</exception> 156 /// <exception cref="LogException"><paramref name="repositoryName"/> does not exist.</exception> GetRepository(string repositoryName)157 public ILoggerRepository GetRepository(string repositoryName) 158 { 159 if (repositoryName == null) 160 { 161 throw new ArgumentNullException("repositoryName"); 162 } 163 164 lock(this) 165 { 166 // Lookup in map 167 ILoggerRepository rep = m_name2repositoryMap[repositoryName] as ILoggerRepository; 168 if (rep == null) 169 { 170 throw new LogException("Repository [" + repositoryName + "] is NOT defined."); 171 } 172 return rep; 173 } 174 } 175 176 /// <summary> 177 /// Create a new repository for the assembly specified 178 /// </summary> 179 /// <param name="repositoryAssembly">the assembly to use to create the repository to associate with the <see cref="ILoggerRepository"/>.</param> 180 /// <param name="repositoryType">The type of repository to create, must implement <see cref="ILoggerRepository"/>.</param> 181 /// <returns>The repository created.</returns> 182 /// <remarks> 183 /// <para> 184 /// The <see cref="ILoggerRepository"/> created will be associated with the repository 185 /// specified such that a call to <see cref="GetRepository(Assembly)"/> with the 186 /// same assembly specified will return the same repository instance. 187 /// </para> 188 /// <para> 189 /// The type of the <see cref="ILoggerRepository"/> created and 190 /// the repository to create can be overridden by specifying the 191 /// <see cref="log4net.Config.RepositoryAttribute"/> attribute on the 192 /// <paramref name="repositoryAssembly"/>. The default values are to use the 193 /// <paramref name="repositoryType"/> implementation of the 194 /// <see cref="ILoggerRepository"/> interface and to use the 195 /// <see cref="AssemblyName.Name"/> as the name of the repository. 196 /// </para> 197 /// <para> 198 /// The <see cref="ILoggerRepository"/> created will be automatically 199 /// configured using any <see cref="log4net.Config.ConfiguratorAttribute"/> 200 /// attributes defined on the <paramref name="repositoryAssembly"/>. 201 /// </para> 202 /// <para> 203 /// If a repository for the <paramref name="repositoryAssembly"/> already exists 204 /// that repository will be returned. An error will not be raised and that 205 /// repository may be of a different type to that specified in <paramref name="repositoryType"/>. 206 /// Also the <see cref="log4net.Config.RepositoryAttribute"/> attribute on the 207 /// assembly may be used to override the repository type specified in 208 /// <paramref name="repositoryType"/>. 209 /// </para> 210 /// </remarks> 211 /// <exception cref="ArgumentNullException"><paramref name="repositoryAssembly"/> is <see langword="null" />.</exception> CreateRepository(Assembly repositoryAssembly, Type repositoryType)212 public ILoggerRepository CreateRepository(Assembly repositoryAssembly, Type repositoryType) 213 { 214 return CreateRepository(repositoryAssembly, repositoryType, DefaultRepositoryName, true); 215 } 216 217 /// <summary> 218 /// Creates a new repository for the assembly specified. 219 /// </summary> 220 /// <param name="repositoryAssembly">the assembly to use to create the repository to associate with the <see cref="ILoggerRepository"/>.</param> 221 /// <param name="repositoryType">The type of repository to create, must implement <see cref="ILoggerRepository"/>.</param> 222 /// <param name="repositoryName">The name to assign to the created repository</param> 223 /// <param name="readAssemblyAttributes">Set to <c>true</c> to read and apply the assembly attributes</param> 224 /// <returns>The repository created.</returns> 225 /// <remarks> 226 /// <para> 227 /// The <see cref="ILoggerRepository"/> created will be associated with the repository 228 /// specified such that a call to <see cref="GetRepository(Assembly)"/> with the 229 /// same assembly specified will return the same repository instance. 230 /// </para> 231 /// <para> 232 /// The type of the <see cref="ILoggerRepository"/> created and 233 /// the repository to create can be overridden by specifying the 234 /// <see cref="log4net.Config.RepositoryAttribute"/> attribute on the 235 /// <paramref name="repositoryAssembly"/>. The default values are to use the 236 /// <paramref name="repositoryType"/> implementation of the 237 /// <see cref="ILoggerRepository"/> interface and to use the 238 /// <see cref="AssemblyName.Name"/> as the name of the repository. 239 /// </para> 240 /// <para> 241 /// The <see cref="ILoggerRepository"/> created will be automatically 242 /// configured using any <see cref="log4net.Config.ConfiguratorAttribute"/> 243 /// attributes defined on the <paramref name="repositoryAssembly"/>. 244 /// </para> 245 /// <para> 246 /// If a repository for the <paramref name="repositoryAssembly"/> already exists 247 /// that repository will be returned. An error will not be raised and that 248 /// repository may be of a different type to that specified in <paramref name="repositoryType"/>. 249 /// Also the <see cref="log4net.Config.RepositoryAttribute"/> attribute on the 250 /// assembly may be used to override the repository type specified in 251 /// <paramref name="repositoryType"/>. 252 /// </para> 253 /// </remarks> 254 /// <exception cref="ArgumentNullException"><paramref name="repositoryAssembly"/> is <see langword="null" />.</exception> CreateRepository(Assembly repositoryAssembly, Type repositoryType, string repositoryName, bool readAssemblyAttributes)255 public ILoggerRepository CreateRepository(Assembly repositoryAssembly, Type repositoryType, string repositoryName, bool readAssemblyAttributes) 256 { 257 if (repositoryAssembly == null) 258 { 259 throw new ArgumentNullException("repositoryAssembly"); 260 } 261 262 // If the type is not set then use the default type 263 if (repositoryType == null) 264 { 265 repositoryType = m_defaultRepositoryType; 266 } 267 268 lock(this) 269 { 270 // Lookup in map 271 ILoggerRepository rep = m_assembly2repositoryMap[repositoryAssembly] as ILoggerRepository; 272 if (rep == null) 273 { 274 // Not found, therefore create 275 LogLog.Debug("DefaultRepositorySelector: Creating repository for assembly [" + repositoryAssembly + "]"); 276 277 // Must specify defaults 278 string actualRepositoryName = repositoryName; 279 Type actualRepositoryType = repositoryType; 280 281 if (readAssemblyAttributes) 282 { 283 // Get the repository and type from the assembly attributes 284 GetInfoForAssembly(repositoryAssembly, ref actualRepositoryName, ref actualRepositoryType); 285 } 286 287 LogLog.Debug("DefaultRepositorySelector: Assembly [" + repositoryAssembly + "] using repository [" + actualRepositoryName + "] and repository type [" + actualRepositoryType + "]"); 288 289 // Lookup the repository in the map (as this may already be defined) 290 rep = m_name2repositoryMap[actualRepositoryName] as ILoggerRepository; 291 if (rep == null) 292 { 293 // Create the repository 294 rep = CreateRepository(actualRepositoryName, actualRepositoryType); 295 296 if (readAssemblyAttributes) 297 { 298 try 299 { 300 // Look for aliasing attributes 301 LoadAliases(repositoryAssembly, rep); 302 303 // Look for plugins defined on the assembly 304 LoadPlugins(repositoryAssembly, rep); 305 306 // Configure the repository using the assembly attributes 307 ConfigureRepository(repositoryAssembly, rep); 308 } 309 catch (Exception ex) 310 { 311 LogLog.Error("DefaultRepositorySelector: Failed to configure repository [" + actualRepositoryName + "] from assembly attributes.", ex); 312 } 313 } 314 } 315 else 316 { 317 LogLog.Debug("DefaultRepositorySelector: repository [" + actualRepositoryName + "] already exists, using repository type [" + rep.GetType().FullName + "]"); 318 319 if (readAssemblyAttributes) 320 { 321 try 322 { 323 // Look for plugins defined on the assembly 324 LoadPlugins(repositoryAssembly, rep); 325 } 326 catch (Exception ex) 327 { 328 LogLog.Error("DefaultRepositorySelector: Failed to configure repository [" + actualRepositoryName + "] from assembly attributes.", ex); 329 } 330 } 331 } 332 m_assembly2repositoryMap[repositoryAssembly] = rep; 333 } 334 return rep; 335 } 336 } 337 338 /// <summary> 339 /// Creates a new repository for the specified repository. 340 /// </summary> 341 /// <param name="repositoryName">The repository to associate with the <see cref="ILoggerRepository"/>.</param> 342 /// <param name="repositoryType">The type of repository to create, must implement <see cref="ILoggerRepository"/>. 343 /// If this param is <see langword="null" /> then the default repository type is used.</param> 344 /// <returns>The new repository.</returns> 345 /// <remarks> 346 /// <para> 347 /// The <see cref="ILoggerRepository"/> created will be associated with the repository 348 /// specified such that a call to <see cref="GetRepository(string)"/> with the 349 /// same repository specified will return the same repository instance. 350 /// </para> 351 /// </remarks> 352 /// <exception cref="ArgumentNullException"><paramref name="repositoryName"/> is <see langword="null" />.</exception> 353 /// <exception cref="LogException"><paramref name="repositoryName"/> already exists.</exception> CreateRepository(string repositoryName, Type repositoryType)354 public ILoggerRepository CreateRepository(string repositoryName, Type repositoryType) 355 { 356 if (repositoryName == null) 357 { 358 throw new ArgumentNullException("repositoryName"); 359 } 360 361 // If the type is not set then use the default type 362 if (repositoryType == null) 363 { 364 repositoryType = m_defaultRepositoryType; 365 } 366 367 lock(this) 368 { 369 ILoggerRepository rep = null; 370 371 // First check that the repository does not exist 372 rep = m_name2repositoryMap[repositoryName] as ILoggerRepository; 373 if (rep != null) 374 { 375 throw new LogException("Repository [" + repositoryName + "] is already defined. Repositories cannot be redefined."); 376 } 377 else 378 { 379 // Lookup an alias before trying to create the new repository 380 ILoggerRepository aliasedRepository = m_alias2repositoryMap[repositoryName] as ILoggerRepository; 381 if (aliasedRepository != null) 382 { 383 // Found an alias 384 385 // Check repository type 386 if (aliasedRepository.GetType() == repositoryType) 387 { 388 // Repository type is compatible 389 LogLog.Debug("DefaultRepositorySelector: Aliasing repository [" + repositoryName + "] to existing repository [" + aliasedRepository.Name + "]"); 390 rep = aliasedRepository; 391 392 // Store in map 393 m_name2repositoryMap[repositoryName] = rep; 394 } 395 else 396 { 397 // Invalid repository type for alias 398 LogLog.Error("DefaultRepositorySelector: Failed to alias repository [" + repositoryName + "] to existing repository ["+aliasedRepository.Name+"]. Requested repository type ["+repositoryType.FullName+"] is not compatible with existing type [" + aliasedRepository.GetType().FullName + "]"); 399 400 // We now drop through to create the repository without aliasing 401 } 402 } 403 404 // If we could not find an alias 405 if (rep == null) 406 { 407 LogLog.Debug("DefaultRepositorySelector: Creating repository [" + repositoryName + "] using type [" + repositoryType + "]"); 408 409 // Call the no arg constructor for the repositoryType 410 rep = (ILoggerRepository)Activator.CreateInstance(repositoryType); 411 412 // Set the name of the repository 413 rep.Name = repositoryName; 414 415 // Store in map 416 m_name2repositoryMap[repositoryName] = rep; 417 418 // Notify listeners that the repository has been created 419 OnLoggerRepositoryCreatedEvent(rep); 420 } 421 } 422 423 return rep; 424 } 425 } 426 427 /// <summary> 428 /// Test if a named repository exists 429 /// </summary> 430 /// <param name="repositoryName">the named repository to check</param> 431 /// <returns><c>true</c> if the repository exists</returns> 432 /// <remarks> 433 /// <para> 434 /// Test if a named repository exists. Use <see cref="CreateRepository(string, Type)"/> 435 /// to create a new repository and <see cref="GetRepository(string)"/> to retrieve 436 /// a repository. 437 /// </para> 438 /// </remarks> ExistsRepository(string repositoryName)439 public bool ExistsRepository(string repositoryName) 440 { 441 lock(this) 442 { 443 return m_name2repositoryMap.ContainsKey(repositoryName); 444 } 445 } 446 447 /// <summary> 448 /// Gets a list of <see cref="ILoggerRepository"/> objects 449 /// </summary> 450 /// <returns>an array of all known <see cref="ILoggerRepository"/> objects</returns> 451 /// <remarks> 452 /// <para> 453 /// Gets an array of all of the repositories created by this selector. 454 /// </para> 455 /// </remarks> GetAllRepositories()456 public ILoggerRepository[] GetAllRepositories() 457 { 458 lock(this) 459 { 460 ICollection reps = m_name2repositoryMap.Values; 461 ILoggerRepository[] all = new ILoggerRepository[reps.Count]; 462 reps.CopyTo(all, 0); 463 return all; 464 } 465 } 466 467 #endregion Implementation of IRepositorySelector 468 469 #region Public Instance Methods 470 471 /// <summary> 472 /// Aliases a repository to an existing repository. 473 /// </summary> 474 /// <param name="repositoryAlias">The repository to alias.</param> 475 /// <param name="repositoryTarget">The repository that the repository is aliased to.</param> 476 /// <remarks> 477 /// <para> 478 /// The repository specified will be aliased to the repository when created. 479 /// The repository must not already exist. 480 /// </para> 481 /// <para> 482 /// When the repository is created it must utilize the same repository type as 483 /// the repository it is aliased to, otherwise the aliasing will fail. 484 /// </para> 485 /// </remarks> 486 /// <exception cref="ArgumentNullException"> 487 /// <para><paramref name="repositoryAlias" /> is <see langword="null" />.</para> 488 /// <para>-or-</para> 489 /// <para><paramref name="repositoryTarget" /> is <see langword="null" />.</para> 490 /// </exception> AliasRepository(string repositoryAlias, ILoggerRepository repositoryTarget)491 public void AliasRepository(string repositoryAlias, ILoggerRepository repositoryTarget) 492 { 493 if (repositoryAlias == null) 494 { 495 throw new ArgumentNullException("repositoryAlias"); 496 } 497 if (repositoryTarget == null) 498 { 499 throw new ArgumentNullException("repositoryTarget"); 500 } 501 502 lock(this) 503 { 504 // Check if the alias is already set 505 if (m_alias2repositoryMap.Contains(repositoryAlias)) 506 { 507 // Check if this is a duplicate of the current alias 508 if (repositoryTarget != ((ILoggerRepository)m_alias2repositoryMap[repositoryAlias])) 509 { 510 // Cannot redefine existing alias 511 throw new InvalidOperationException("Repository [" + repositoryAlias + "] is already aliased to repository [" + ((ILoggerRepository)m_alias2repositoryMap[repositoryAlias]).Name + "]. Aliases cannot be redefined."); 512 } 513 } 514 // Check if the alias is already mapped to a repository 515 else if (m_name2repositoryMap.Contains(repositoryAlias)) 516 { 517 // Check if this is a duplicate of the current mapping 518 if ( repositoryTarget != ((ILoggerRepository)m_name2repositoryMap[repositoryAlias]) ) 519 { 520 // Cannot define alias for already mapped repository 521 throw new InvalidOperationException("Repository [" + repositoryAlias + "] already exists and cannot be aliased to repository [" + repositoryTarget.Name + "]."); 522 } 523 } 524 else 525 { 526 // Set the alias 527 m_alias2repositoryMap[repositoryAlias] = repositoryTarget; 528 } 529 } 530 } 531 532 #endregion Public Instance Methods 533 534 #region Protected Instance Methods 535 536 /// <summary> 537 /// Notifies the registered listeners that the repository has been created. 538 /// </summary> 539 /// <param name="repository">The repository that has been created.</param> 540 /// <remarks> 541 /// <para> 542 /// Raises the <see cref="LoggerRepositoryCreatedEvent"/> event. 543 /// </para> 544 /// </remarks> OnLoggerRepositoryCreatedEvent(ILoggerRepository repository)545 protected virtual void OnLoggerRepositoryCreatedEvent(ILoggerRepository repository) 546 { 547 LoggerRepositoryCreationEventHandler handler = m_loggerRepositoryCreatedEvent; 548 if (handler != null) 549 { 550 handler(this, new LoggerRepositoryCreationEventArgs(repository)); 551 } 552 } 553 554 #endregion Protected Instance Methods 555 556 #region Private Instance Methods 557 558 /// <summary> 559 /// Gets the repository name and repository type for the specified assembly. 560 /// </summary> 561 /// <param name="assembly">The assembly that has a <see cref="log4net.Config.RepositoryAttribute"/>.</param> 562 /// <param name="repositoryName">in/out param to hold the repository name to use for the assembly, caller should set this to the default value before calling.</param> 563 /// <param name="repositoryType">in/out param to hold the type of the repository to create for the assembly, caller should set this to the default value before calling.</param> 564 /// <exception cref="ArgumentNullException"><paramref name="assembly" /> is <see langword="null" />.</exception> GetInfoForAssembly(Assembly assembly, ref string repositoryName, ref Type repositoryType)565 private void GetInfoForAssembly(Assembly assembly, ref string repositoryName, ref Type repositoryType) 566 { 567 if (assembly == null) 568 { 569 throw new ArgumentNullException("assembly"); 570 } 571 572 try 573 { 574 LogLog.Debug("DefaultRepositorySelector: Assembly [" + assembly.FullName + "] Loaded From [" + SystemInfo.AssemblyLocationInfo(assembly) + "]"); 575 } 576 catch 577 { 578 // Ignore exception from debug call 579 } 580 581 try 582 { 583 // Look for the RepositoryAttribute on the assembly 584 object[] repositoryAttributes = Attribute.GetCustomAttributes(assembly, typeof(log4net.Config.RepositoryAttribute), false); 585 if (repositoryAttributes == null || repositoryAttributes.Length == 0) 586 { 587 // This is not a problem, but its nice to know what is going on. 588 LogLog.Debug("DefaultRepositorySelector: Assembly [" + assembly + "] does not have a RepositoryAttribute specified."); 589 } 590 else 591 { 592 if (repositoryAttributes.Length > 1) 593 { 594 LogLog.Error("DefaultRepositorySelector: Assembly [" + assembly + "] has multiple log4net.Config.RepositoryAttribute assembly attributes. Only using first occurrence."); 595 } 596 597 log4net.Config.RepositoryAttribute domAttr = repositoryAttributes[0] as log4net.Config.RepositoryAttribute; 598 599 if (domAttr == null) 600 { 601 LogLog.Error("DefaultRepositorySelector: Assembly [" + assembly + "] has a RepositoryAttribute but it does not!."); 602 } 603 else 604 { 605 // If the Name property is set then override the default 606 if (domAttr.Name != null) 607 { 608 repositoryName = domAttr.Name; 609 } 610 611 // If the RepositoryType property is set then override the default 612 if (domAttr.RepositoryType != null) 613 { 614 // Check that the type is a repository 615 if (typeof(ILoggerRepository).IsAssignableFrom(domAttr.RepositoryType)) 616 { 617 repositoryType = domAttr.RepositoryType; 618 } 619 else 620 { 621 LogLog.Error("DefaultRepositorySelector: Repository Type [" + domAttr.RepositoryType + "] must implement the ILoggerRepository interface."); 622 } 623 } 624 } 625 } 626 } 627 catch (Exception ex) 628 { 629 LogLog.Error("DefaultRepositorySelector: Unhandled exception in GetInfoForAssembly", ex); 630 } 631 } 632 633 /// <summary> 634 /// Configures the repository using information from the assembly. 635 /// </summary> 636 /// <param name="assembly">The assembly containing <see cref="log4net.Config.ConfiguratorAttribute"/> 637 /// attributes which define the configuration for the repository.</param> 638 /// <param name="repository">The repository to configure.</param> 639 /// <exception cref="ArgumentNullException"> 640 /// <para><paramref name="assembly" /> is <see langword="null" />.</para> 641 /// <para>-or-</para> 642 /// <para><paramref name="repository" /> is <see langword="null" />.</para> 643 /// </exception> ConfigureRepository(Assembly assembly, ILoggerRepository repository)644 private void ConfigureRepository(Assembly assembly, ILoggerRepository repository) 645 { 646 if (assembly == null) 647 { 648 throw new ArgumentNullException("assembly"); 649 } 650 if (repository == null) 651 { 652 throw new ArgumentNullException("repository"); 653 } 654 655 // Look for the Configurator attributes (e.g. XmlConfiguratorAttribute) on the assembly 656 object[] configAttributes = Attribute.GetCustomAttributes(assembly, typeof(log4net.Config.ConfiguratorAttribute), false); 657 if (configAttributes != null && configAttributes.Length > 0) 658 { 659 // Sort the ConfiguratorAttributes in priority order 660 Array.Sort(configAttributes); 661 662 // Delegate to the attribute the job of configuring the repository 663 foreach(log4net.Config.ConfiguratorAttribute configAttr in configAttributes) 664 { 665 if (configAttr != null) 666 { 667 try 668 { 669 configAttr.Configure(assembly, repository); 670 } 671 catch (Exception ex) 672 { 673 LogLog.Error("DefaultRepositorySelector: Exception calling ["+configAttr.GetType().FullName+"] .Configure method.", ex); 674 } 675 } 676 } 677 } 678 679 if (repository.Name == DefaultRepositoryName) 680 { 681 // Try to configure the default repository using an AppSettings specified config file 682 // Do this even if the repository has been configured (or claims to be), this allows overriding 683 // of the default config files etc, if that is required. 684 685 string repositoryConfigFile = SystemInfo.GetAppSetting("log4net.Config"); 686 if (repositoryConfigFile != null && repositoryConfigFile.Length > 0) 687 { 688 string applicationBaseDirectory = null; 689 try 690 { 691 applicationBaseDirectory = SystemInfo.ApplicationBaseDirectory; 692 } 693 catch(Exception ex) 694 { 695 LogLog.Warn("DefaultRepositorySelector: Exception getting ApplicationBaseDirectory. appSettings log4net.Config path ["+repositoryConfigFile+"] will be treated as an absolute URI", ex); 696 } 697 698 // As we are not going to watch the config file it is easiest to just resolve it as a 699 // URI and pass that to the Configurator 700 Uri repositoryConfigUri = null; 701 try 702 { 703 if (applicationBaseDirectory != null) 704 { 705 // Resolve the config path relative to the application base directory URI 706 repositoryConfigUri = new Uri(new Uri(applicationBaseDirectory), repositoryConfigFile); 707 } 708 else 709 { 710 repositoryConfigUri = new Uri(repositoryConfigFile); 711 } 712 } 713 catch(Exception ex) 714 { 715 LogLog.Error("DefaultRepositorySelector: Exception while parsing log4net.Config file path ["+repositoryConfigFile+"]", ex); 716 } 717 718 if (repositoryConfigUri != null) 719 { 720 LogLog.Debug("DefaultRepositorySelector: Loading configuration for default repository from AppSettings specified Config URI ["+repositoryConfigUri.ToString()+"]"); 721 722 try 723 { 724 // TODO: Support other types of configurator 725 XmlConfigurator.Configure(repository, repositoryConfigUri); 726 } 727 catch (Exception ex) 728 { 729 LogLog.Error("DefaultRepositorySelector: Exception calling XmlConfigurator.Configure method with ConfigUri ["+repositoryConfigUri+"]", ex); 730 } 731 } 732 } 733 } 734 } 735 736 /// <summary> 737 /// Loads the attribute defined plugins on the assembly. 738 /// </summary> 739 /// <param name="assembly">The assembly that contains the attributes.</param> 740 /// <param name="repository">The repository to add the plugins to.</param> 741 /// <exception cref="ArgumentNullException"> 742 /// <para><paramref name="assembly" /> is <see langword="null" />.</para> 743 /// <para>-or-</para> 744 /// <para><paramref name="repository" /> is <see langword="null" />.</para> 745 /// </exception> LoadPlugins(Assembly assembly, ILoggerRepository repository)746 private void LoadPlugins(Assembly assembly, ILoggerRepository repository) 747 { 748 if (assembly == null) 749 { 750 throw new ArgumentNullException("assembly"); 751 } 752 if (repository == null) 753 { 754 throw new ArgumentNullException("repository"); 755 } 756 757 // Look for the PluginAttribute on the assembly 758 object[] configAttributes = Attribute.GetCustomAttributes(assembly, typeof(log4net.Config.PluginAttribute), false); 759 if (configAttributes != null && configAttributes.Length > 0) 760 { 761 foreach(log4net.Plugin.IPluginFactory configAttr in configAttributes) 762 { 763 try 764 { 765 // Create the plugin and add it to the repository 766 repository.PluginMap.Add(configAttr.CreatePlugin()); 767 } 768 catch(Exception ex) 769 { 770 LogLog.Error("DefaultRepositorySelector: Failed to create plugin. Attribute [" + configAttr.ToString() + "]", ex); 771 } 772 } 773 } 774 } 775 776 /// <summary> 777 /// Loads the attribute defined aliases on the assembly. 778 /// </summary> 779 /// <param name="assembly">The assembly that contains the attributes.</param> 780 /// <param name="repository">The repository to alias to.</param> 781 /// <exception cref="ArgumentNullException"> 782 /// <para><paramref name="assembly" /> is <see langword="null" />.</para> 783 /// <para>-or-</para> 784 /// <para><paramref name="repository" /> is <see langword="null" />.</para> 785 /// </exception> LoadAliases(Assembly assembly, ILoggerRepository repository)786 private void LoadAliases(Assembly assembly, ILoggerRepository repository) 787 { 788 if (assembly == null) 789 { 790 throw new ArgumentNullException("assembly"); 791 } 792 if (repository == null) 793 { 794 throw new ArgumentNullException("repository"); 795 } 796 797 // Look for the AliasRepositoryAttribute on the assembly 798 object[] configAttributes = Attribute.GetCustomAttributes(assembly, typeof(log4net.Config.AliasRepositoryAttribute), false); 799 if (configAttributes != null && configAttributes.Length > 0) 800 { 801 foreach(log4net.Config.AliasRepositoryAttribute configAttr in configAttributes) 802 { 803 try 804 { 805 AliasRepository(configAttr.Name, repository); 806 } 807 catch(Exception ex) 808 { 809 LogLog.Error("DefaultRepositorySelector: Failed to alias repository [" + configAttr.Name + "]", ex); 810 } 811 } 812 } 813 } 814 815 #endregion Private Instance Methods 816 817 #region Private Static Fields 818 819 private const string DefaultRepositoryName = "log4net-default-repository"; 820 821 #endregion Private Static Fields 822 823 #region Private Instance Fields 824 825 private readonly Hashtable m_name2repositoryMap = new Hashtable(); 826 private readonly Hashtable m_assembly2repositoryMap = new Hashtable(); 827 private readonly Hashtable m_alias2repositoryMap = new Hashtable(); 828 private readonly Type m_defaultRepositoryType; 829 830 private event LoggerRepositoryCreationEventHandler m_loggerRepositoryCreatedEvent; 831 832 #endregion Private Instance Fields 833 } 834 } 835 836 #endif // !NETCF 837