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 { /// /// A generic node. /// public abstract class Node { #region Inner Types private class DeserializationLoggingContext : LoggingContext { protected override void OnEventLogged(ItemEventArgs e) { AddinManager.Log(e.Item); base.OnEventLogged(e); } } #endregion #region Constants #if DEBUG private static Dictionary m_standardAttributes = new Dictionary(); #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 } /// /// Internal constructor to forbid inheritance by other assemblies. /// internal Node() { } #endregion #region Properties /// /// Gets the file location of the extension node. /// /// public virtual FileLocation FileLocation { get { return m_module.FileLocation.GetValueOrDefault(); } } /// /// Addin of this node. /// public Addin Addin { get { return m_module.Addin; } } /// /// Module of this node. /// public Module Module { get { return m_module; } } /// /// Type of this node. /// public NodeType Type { get { return m_type; } } #endregion #region Methods /// /// Reads the node from a . /// /// /// Consider using s to deserialize automatically. /// /// Context to deserialize from. protected virtual void Read(DeserializationContext context) { } /// /// Watch out, do not call this method! Use Initialize of derived class. /// /// /// /// /// 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(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 } }