JD2022-TU1/main/tools/framework/JD.TeaBoxAddinSystem/Addins/Internal/Node.cs

254 lines
7.4 KiB
C#

using System;
using System.Collections.Generic;
using JD.Kernel.Classes;
using JD.Kernel.Structs;
using JD.LogService;
using JD.TeaBoxAddinSystem.Addins.Attributes;
using JD.TeaBoxAddinSystem.Addins.Description;
namespace JD.TeaBoxAddinSystem.Addins.Internal
{
/// <summary>
/// A generic node.
/// </summary>
public abstract class Node
{
#region Inner Types
private class DeserializationLoggingContext : LoggingContext
{
protected override void OnEventLogged(ItemEventArgs<LogEvent> e)
{
AddinManager.Log(e.Item);
base.OnEventLogged(e);
}
}
#endregion
#region Constants
#if DEBUG
private static Dictionary<string, object> m_standardAttributes = new Dictionary<string,object>();
#endif
#endregion
#region Variables
// Set through Initialize
private Module m_module;
private NodeType m_type;
#endregion
#region Constructor
static Node()
{
#if DEBUG
m_standardAttributes.Add("id", null);
m_standardAttributes.Add("insertbefore", null);
m_standardAttributes.Add("insertafter", null);
#endif
}
/// <summary>
/// Internal constructor to forbid inheritance by other assemblies.
/// </summary>
internal Node()
{
}
#endregion
#region Properties
/// <summary>
/// Gets the file location of the extension node.
/// </summary>
/// <returns></returns>
public virtual FileLocation FileLocation
{
get
{
return m_module.FileLocation.GetValueOrDefault();
}
}
/// <summary>
/// Addin of this node.
/// </summary>
public Addin Addin
{
get
{
return m_module.Addin;
}
}
/// <summary>
/// Module of this node.
/// </summary>
public Module Module
{
get
{
return m_module;
}
}
/// <summary>
/// Type of this node.
/// </summary>
public NodeType Type
{
get
{
return m_type;
}
}
#endregion
#region Methods
/// <summary>
/// Reads the node from a <see cref="DeserializationContext"/>.
/// </summary>
/// <remarks>
/// Consider using <see cref="NodeAttributeAttribute"/>s to deserialize automatically.
/// </remarks>
/// <param name="context">Context to deserialize from.</param>
protected virtual void Read(DeserializationContext context)
{
}
/// <summary>
/// Watch out, do not call this method! Use Initialize of derived class.
/// </summary>
/// <param name="module"></param>
/// <param name="description"></param>
/// <param name="type"></param>
/// <returns></returns>
internal bool Initialize(Module module, NodeDescription description, NodeType type)
{
System.Diagnostics.Debug.Assert(module != null);
m_module = module;
m_type = type;
if (description != null)
{
try
{
if (!ReadDefault(description))
{
return false;
}
LoggingContext loggingContext = new DeserializationLoggingContext();
Read(new DeserializationContext(description, loggingContext));
if (loggingContext.Errors.Count > 0)
{
return false;
}
}
catch (Exception e)
{
description.LogError("Unexpected error while deserializing node of type {0}: {1}", GetType().FullName, e.Message);
return false;
}
}
return true;
}
private bool ReadDefault(NodeDescription description)
{
System.Diagnostics.Debug.Assert(description != null);
System.Diagnostics.Debug.Assert(Type != null);
System.Diagnostics.Debug.Assert(Type.Type != null);
System.Diagnostics.Debug.Assert(Type.Descriptors != null);
StringPropertyConverter deserializer = new StringPropertyConverter();
deserializer.ErrorLogger = delegate(string errorMsg)
{
description.LogError(errorMsg);
};
#if DEBUG
deserializer.SuperfluousPropertiesProduceErrors = true;
deserializer.SuperfluousPropertyLogger = delegate(string property)
{
if (!m_standardAttributes.ContainsKey(property.ToLowerInvariant()))
{
AddinManager.Log(new Error(LogCategory.Warning, "Attribute '{0}' is an unknown attribute for extension node '{1}'", property, Type));
}
};
#endif
deserializer.CustomConverter = delegate(System.Type targetType, string value, out object convertedValue)
{
object[] attributes = targetType.GetCustomAttributes(typeof(AddinConverterAttribute), true);
if (attributes.Length > 0)
{
convertedValue = ((AddinConverterAttribute)attributes[0]).Convert(targetType, value, this);
return true;
}
convertedValue = null;
return false;
};
return deserializer.Deserialize(this, Type.Descriptors, description.Attributes);
}
internal static T CreateNode<T>(string nodeTypeName, NodeType type) where T : Node
{
System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(nodeTypeName));
System.Diagnostics.Debug.Assert(type != null);
Type nodeType = type.Type;
if (nodeType == null)
{
// Something went wrong
return null;
}
T node = null;
try
{
node = Activator.CreateInstance(nodeType) as T;
}
catch (System.MissingMethodException)
{
type.LogError("Cannot create {0} node of type {1} because it doesn't have a parameterless public constructor", nodeTypeName, nodeType.FullName);
return null;
}
catch (System.Reflection.TargetInvocationException e)
{
type.LogError("Unexpected exception thrown while creating {0} node of type {1}: {2}", nodeTypeName, nodeType.FullName, e.InnerException.Message);
return null;
}
catch (Exception e)
{
type.LogError("Unexpected error while creating {0} node of type {0}: {1}", nodeTypeName, nodeType.FullName, e.Message);
return null;
}
if (node == null)
{
string correctName = nodeTypeName.ToUpper()[0] + nodeTypeName.Substring(1);
type.LogError("{0} node type {1} must be a subclass of {2}", correctName, nodeType.FullName, typeof(T).Name);
return null;
}
return node;
}
#endregion
}
}