254 lines
7.4 KiB
C#
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
|
|
}
|
|
}
|