|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// THE ASSEMBLY BUILT FROM THIS SOURCE FILE HAS BEEN DEPRECATED FOR YEARS. IT IS BUILT ONLY TO PROVIDE
// BACKWARD COMPATIBILITY FOR API USERS WHO HAVE NOT YET MOVED TO UPDATED APIS. PLEASE DO NOT SEND PULL
// REQUESTS THAT CHANGE THIS FILE WITHOUT FIRST CHECKING WITH THE MAINTAINERS THAT THE FIX IS REQUIRED.
using System;
using System.Reflection;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.BuildEngine.Shared;
namespace Microsoft.Build.BuildEngine
{
/// <summary>
/// This class is used to contain information about a logger as a collection of values that
/// can be used to instantiate the logger and can be serialized to be passed between different
/// processes.
/// </summary>
public class LoggerDescription
{
#region Constructor
internal LoggerDescription()
{
}
/// <summary>
/// Creates a logger description from given data
/// </summary>
public LoggerDescription
(
string loggerClassName,
string loggerAssemblyName,
string loggerAssemblyFile,
string loggerSwitchParameters,
LoggerVerbosity verbosity
)
{
this.loggerClassName = loggerClassName;
this.loggerAssembly = new AssemblyLoadInfo(loggerAssemblyName, loggerAssemblyFile);
this.loggerSwitchParameters = loggerSwitchParameters;
this.verbosity = verbosity;
}
#endregion
#region Properties
/// <summary>
/// This property exposes the logger id which identifies each distributed logger uniquiely
/// </summary>
internal int LoggerId
{
get
{
return this.loggerId;
}
set
{
this.loggerId = value;
}
}
/// <summary>
/// This property generates the logger name by appending together the class name and assembly name
/// </summary>
internal string Name
{
get
{
if (!string.IsNullOrEmpty(this.loggerClassName) &&
!string.IsNullOrEmpty(this.loggerAssembly.AssemblyFile))
{
return this.loggerClassName + ":" + this.loggerAssembly.AssemblyFile;
}
else if (!string.IsNullOrEmpty(this.loggerClassName))
{
return this.loggerClassName;
}
else
{
return this.loggerAssembly.AssemblyFile;
}
}
}
/// <summary>
/// Returns the string of logger parameters, null if there are none
/// </summary>
public string LoggerSwitchParameters
{
get
{
return loggerSwitchParameters;
}
}
/// <summary>
/// Return the verbosity for this logger (from command line all loggers get same verbosity)
/// </summary>
public LoggerVerbosity Verbosity
{
get
{
return this.verbosity;
}
}
#endregion
#region Methods
/// <summary>
/// Create an IForwardingLogger out of the data in this description. This method may throw a variety of
/// reflection exceptions if the data is invalid. It is the resposibility of the caller to handle these
/// exceptions if desired.
/// </summary>
/// <returns></returns>
internal IForwardingLogger CreateForwardingLogger()
{
return (IForwardingLogger)CreateLogger(true);
}
/// <summary>
/// Create an ILogger out of the data in this description. This method may throw a variety of
/// reflection exceptions if the data is invalid. It is the resposibility of the caller to handle these
/// exceptions if desired.
/// </summary>
/// <returns></returns>
internal ILogger CreateLogger()
{
return CreateLogger(false);
}
/// <summary>
/// Loads a logger from its assembly, instantiates it, and handles errors.
/// </summary>
/// <returns>Instantiated logger.</returns>
private ILogger CreateLogger(bool forwardingLogger)
{
ILogger logger = null;
try
{
if (forwardingLogger)
{
// load the logger from its assembly
LoadedType loggerClass = (new TypeLoader(forwardingLoggerClassFilter)).Load(loggerClassName, loggerAssembly);
if (loggerClass != null)
{
// instantiate the logger
logger = (IForwardingLogger)Activator.CreateInstance(loggerClass.Type);
}
}
else
{
// load the logger from its assembly
LoadedType loggerClass = (new TypeLoader(loggerClassFilter)).Load(loggerClassName, loggerAssembly);
if (loggerClass != null)
{
// instantiate the logger
logger = (ILogger)Activator.CreateInstance(loggerClass.Type);
}
}
}
catch (TargetInvocationException e)
{
// At this point, the interesting stack is the internal exception;
// the outer exception is System.Reflection stuff that says nothing
// about the nature of the logger failure.
Exception innerException = e.InnerException;
if (innerException is LoggerException)
{
// Logger failed politely during construction. In order to preserve
// the stack trace at which the error occurred we wrap the original
// exception instead of throwing.
LoggerException l = ((LoggerException)innerException);
throw new LoggerException(l.Message, innerException, l.ErrorCode, l.HelpKeyword);
}
else
{
throw;
}
}
return logger;
}
/// <summary>
/// Used for finding loggers when reflecting through assemblies.
/// </summary>
private static readonly TypeFilter forwardingLoggerClassFilter = new TypeFilter(IsForwardingLoggerClass);
/// <summary>
/// Used for finding loggers when reflecting through assemblies.
/// </summary>
private static readonly TypeFilter loggerClassFilter = new TypeFilter(IsLoggerClass);
/// <summary>
/// Checks if the given type is a logger class.
/// </summary>
/// <remarks>This method is used as a TypeFilter delegate.</remarks>
/// <returns>true, if specified type is a logger</returns>
private static bool IsForwardingLoggerClass(Type type, object unused)
{
return type.IsClass &&
!type.IsAbstract &&
(type.GetInterface("IForwardingLogger") != null);
}
/// <summary>
/// Checks if the given type is a logger class.
/// </summary>
/// <remarks>This method is used as a TypeFilter delegate.</remarks>
/// <returns>true, if specified type is a logger</returns>
private static bool IsLoggerClass(Type type, object unused)
{
return type.IsClass &&
!type.IsAbstract &&
(type.GetInterface("ILogger") != null);
}
/// <summary>
/// Converts the path to the logger assembly to a full path
/// </summary>
internal void ConvertPathsToFullPaths()
{
if (loggerAssembly.AssemblyFile != null)
{
loggerAssembly =
new AssemblyLoadInfo(loggerAssembly.AssemblyName, Path.GetFullPath(loggerAssembly.AssemblyFile));
}
}
#endregion
#region Data
private string loggerClassName;
private string loggerSwitchParameters;
private AssemblyLoadInfo loggerAssembly;
private LoggerVerbosity verbosity;
private int loggerId;
#endregion
#region CustomSerializationToStream
internal void WriteToStream(BinaryWriter writer)
{
#region LoggerClassName
if (loggerClassName == null)
{
writer.Write((byte)0);
}
else
{
writer.Write((byte)1);
writer.Write(loggerClassName);
}
#endregion
#region LoggerSwitchParameters
if (loggerSwitchParameters == null)
{
writer.Write((byte)0);
}
else
{
writer.Write((byte)1);
writer.Write(loggerSwitchParameters);
}
#endregion
#region LoggerAssembly
if (loggerAssembly == null)
{
writer.Write((byte)0);
}
else
{
writer.Write((byte)1);
if (loggerAssembly.AssemblyFile == null)
{
writer.Write((byte)0);
}
else
{
writer.Write((byte)1);
writer.Write(loggerAssembly.AssemblyFile);
}
if (loggerAssembly.AssemblyName == null)
{
writer.Write((byte)0);
}
else
{
writer.Write((byte)1);
writer.Write(loggerAssembly.AssemblyName);
}
}
#endregion
writer.Write((Int32)verbosity);
writer.Write((Int32)loggerId);
}
internal void CreateFromStream(BinaryReader reader)
{
#region LoggerClassName
if (reader.ReadByte() == 0)
{
loggerClassName = null;
}
else
{
loggerClassName = reader.ReadString();
}
#endregion
#region LoggerSwitchParameters
if (reader.ReadByte() == 0)
{
loggerSwitchParameters = null;
}
else
{
loggerSwitchParameters = reader.ReadString();
}
#endregion
#region LoggerAssembly
if (reader.ReadByte() == 0)
{
loggerAssembly = null;
}
else
{
string assemblyName = null;
string assemblyFile = null;
if (reader.ReadByte() != 0)
{
assemblyFile = reader.ReadString();
}
if (reader.ReadByte() != 0)
{
assemblyName = reader.ReadString();
}
loggerAssembly = new AssemblyLoadInfo(assemblyName, assemblyFile);
}
#endregion
verbosity = (LoggerVerbosity)reader.ReadInt32();
loggerId = reader.ReadInt32();
}
#endregion
}
}
|