#region Copyright /* * Copyright (c) 2005,2006,2007, OpenMI Association * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenMI Association nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY "OpenMI Association" ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL "OpenMI Association" BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #endregion using System; using System.IO; using System.Collections; using System.ComponentModel; using System.Reflection; namespace RTCTools.OpenMI.Sdk.DevelopmentSupport { /// /// This class registers extra information about classes and (optionally) properties in your application. /// For example, information about how to write a property of a class into an xml file can be stored here. /// This mechanism has great similarities with the attribute mechanism in the .Net framework, but differences are that /// 1) entries can be set dynamically /// 2) no code modification is necessary in the target classes (the classes for which information is stored) /// /// /// MetaInfo.SetAttribute (typeof(ILinkableComponent), "XmlFile", true); /// Tells that the interface ILinkableComponent has subject XmlFile, which has corresponding value true. /// There must be another class which knows that subject XmlFile exists and uses this information in some way. /// MetaInfo.SetAttribute (typeof(IElementSet), "ID", "XmlRefName", "RefID"); /// Tells that the property ID in the interface IElementSet has subject XmlRefName, which has corresponding value "RefID". /// public class MetaInfo { private static bool _initialized = false; private static EntryList _targets = new EntryList(); private static Hashtable _subjectTypes = new Hashtable(); /// /// Writes all metainfo to a file /// /// The file public static void Write (FileInfo file) { MetaInfo.Initialize(); XmlFile.Write (_targets, file); } /// /// Reads all metainfo from file /// /// The file public static void Read (FileInfo file) { MetaInfo.Initialize(); XmlFile.Read (_targets, file); } /// /// Sets metainfo about the xml file where meta info is saved in /// private static void Initialize() { if (!_initialized) { MetaInfo.SetAttribute (typeof(EntryList), "XmlItemType", "RTCTools.OpenMI.Sdk.DevelopmentSupport.MetaInfoEntry"); MetaInfo.SetAttribute (typeof(MetaInfoEntry), "Properties", "XmlItemType", "RTCTools.OpenMI.Sdk.DevelopmentSupport.MetaInfoClass"); MetaInfo.SetAttribute (typeof(MetaInfoClass), "ObjectAggregate", "RTCTools.OpenMI.Sdk.DevelopmentSupport.MetaInfoClassAggregate"); _initialized = true; } } /// /// Gets all metainfo concerning a given class /// /// The class name /// All metainfo about a class, null if not found private static MetaInfoEntry GetEntry (string target) { foreach (MetaInfoEntry entry in _targets) { if (entry.ClassName.Equals (target)) { return entry; } } return null; } /// /// Gets all metainfo concerning a given class and creates an empty block if not found /// /// The class name /// All metainfo about a class private static MetaInfoEntry GetEntryForced (string target) { MetaInfoEntry entry = MetaInfo.GetEntry (target); if (entry == null) { entry = new MetaInfoEntry (target); _targets.Add (entry); } return entry; } /// /// Stores information about a class /// /// The class about which information is stored (usually as class type or string) /// The type of information (e.g. how the class is named in an xml file) /// The actual value public static void SetAttribute (object target, string subject, object targetValue) { MetaInfo.SetAttribute (target, null, subject, targetValue); } /// /// Stores information about a class and property /// /// The class about which information is stored (usually as class type or string) /// The property in the class /// The type of information (e.g. how the property is named in an xml file) /// The actual value public static void SetAttribute (object target, string property, string subject, object targetValue) { if (target is Type) { target = ((Type)target).FullName; } else if (target is Assembly) { target = ((Assembly)target).GetName().Name; } MetaInfoEntry table = MetaInfo.GetEntryForced (target.ToString()); table.SetValue (property, subject, targetValue); } /// /// Gets the stored information for a class. /// Not only the class is examined, but also all superclasses and implemented interfaces. /// /// The class about which information will be retrieved /// The type of information required /// The information stored for this object and type of information, null if not found public static object GetAttribute (Type target, string subject) { return MetaInfo.GetAttributeDefault (target, null, subject, null); } /// /// Gets the stored information for a class and property. /// Not only the class is examined, but also all superclasses and implemented interfaces. /// /// The class type about which information will be retrieved /// The property for which information is to be required /// The type of information required /// The information stored for the class and property, null if not found public static object GetAttribute (Type target, string property, string subject) { return MetaInfo.GetAttributeDefault (target, property, subject, null); } /// /// Gets the stored information for a class. /// Not only the class is examined, but also all superclasses and implemented interfaces. /// /// The object about which information will be retrieved /// The type of information required /// Default value if the information is not found /// The information stored for this object and type, the default value if not found public static object GetAttributeDefault (Type targetClass, string subject, object defaultValue) { return MetaInfo.GetAttributeDefault (targetClass, null, subject, defaultValue); } /// /// Gets the stored information for a class and property. /// Not only the class is examined, but also all superclasses and implemented interfaces. /// /// The object about which information will be retrieved /// The property in the class /// The type of information required /// Default value if the information is not found /// The information stored for this class, property and type, the default value if not found public static object GetAttributeDefault (Type targetClass, string property, string subject, object defaultValue) { // try to find appropriate value in super class Type targetType = targetClass; while (targetType != null) { string target = targetType.FullName; MetaInfoEntry table = MetaInfo.GetEntry (target); if (table != null) { if (table.Contains(property, subject)) { return table.GetValue (property, subject); } } targetType = targetType.BaseType; } // try to find an interface implemented by the target type foreach (Type implementedInterface in targetClass.GetInterfaces()) { object attribute = MetaInfo.GetAttributeDefault (implementedInterface, property, subject, null); if (attribute != null) { return attribute; } } return defaultValue; } /// /// Gets the stored information for an assembly. /// /// The assembly about which information will be retrieved /// The type of information required /// Default value if the information is not found /// The information stored for this class, property and type, the default value if not found public static object GetAttributeDefault (Assembly targetAssembly, string subject, object defaultValue) { return MetaInfo.GetAttributeDefault (targetAssembly.GetName().Name, subject, defaultValue); } /// /// Gets the stored information for a string /// /// The string about which information will be retrieved /// The type of information required /// Default value if the information is not found /// The information stored for this class, property and type, the default value if not found public static object GetAttributeDefault (string target, string subject, object defaultValue) { MetaInfoEntry table = MetaInfo.GetEntry (target); if (table != null) { if (table.Contains(null, subject)) { return table.GetValue (null, subject); } } return defaultValue; } /// /// Gets a list of all properties in a class, for which a value has been stored. /// All superclasses and implemented interfaces of the class are examined too. /// /// The class /// List of properties public static string[] GetProperties (Type targetClass) { // try to find appropriate value in super class ArrayList subjects = new ArrayList(); Type targetType = targetClass; while (targetType != null) { string fullName = targetType.FullName; MetaInfoEntry entry = MetaInfo.GetEntry (fullName); if (entry != null) { foreach (MetaInfoClass property in entry.Properties) { if (!subjects.Contains(property.Name)) { subjects.Add (property.Name); } } } targetType = targetType.BaseType; } // try to find interfaces implemented by the target type foreach (Type implementedInterface in targetClass.GetInterfaces()) { string[] interfaceProperties = MetaInfo.GetProperties (implementedInterface); foreach (string interfaceProperty in interfaceProperties) { if (!subjects.Contains(interfaceProperty)) { subjects.Add (interfaceProperty); } } } return (string[]) subjects.ToArray(typeof(string)); } } /// /// Special list for all entered information in MetaInfo /// internal class EntryList : ArrayList { } /// /// Class which groups all information stored for a class in MetaInfo /// internal class MetaInfoEntry { private string _name; private ArrayList _properties = new ArrayList(); private MetaInfoClass _classProperties = new MetaInfoClass(null); /// /// Default constructor /// /// The class public MetaInfoEntry (string className) { _name = className; } /// /// Class for which information is stored /// public string ClassName { get {return _name;} set {_name = value;} } /// /// Group of subjects and stored values directly under the class (so without properties) /// public MetaInfoClass Class { get {return _classProperties;} } /// /// List of all properties for which a value is stored /// public ArrayList Properties { get {return _properties;} } /// /// Gets a group of subjects and associated values for a property in the class /// /// The property /// Group of subjects and associated values private MetaInfoClass GetMetaInfo (string property) { foreach (MetaInfoClass metaInfo in _properties) { if (metaInfo.Name.Equals (property)) { return metaInfo; } } return null; } /// /// Gets a list of all properties for which a value is stored /// /// The list of properties public string[] GetProperties() { ArrayList list = new ArrayList(); foreach (MetaInfoClass metaInfo in _properties) { list.Add (metaInfo.Name); } return (string[]) list.ToArray(typeof(string)); } /// /// Gets the stored value directly under a class for a certain subject /// /// The subject /// The stored value, null if not found public object GetValue (string subject) { return _classProperties[subject]; } /// /// Gets the stored value directly under a class for a certain subject /// /// The subject /// The new value public void SetValue (string subject, object targetValue) { _classProperties[subject] = targetValue; } /// /// Gets the stored value for a subject and property in the class /// /// The property /// The subject /// The stored value, null if not found public object GetValue (string property, string subject) { if (property == null) { return this.GetValue (subject); } MetaInfoClass metaInfo = this.GetMetaInfo (property); if (metaInfo != null) { return metaInfo[subject]; } return null; } /// /// Stores a new value for a subject and property in the class /// /// The property /// The subject /// The new value public void SetValue (string property, string subject, object targetValue) { if (property == null) { this.SetValue (subject, targetValue); return; } MetaInfoClass metaInfo = this.GetMetaInfo (property); if (metaInfo == null) { metaInfo = new MetaInfoClass (property); _properties.Add (metaInfo); } metaInfo[subject] = targetValue; } /// /// Tells whether a value is stored for a property and subject in the class /// /// The property name /// The subject /// Indication of presence of the property and subject public bool Contains (string property, string subject) { if (property == null) { return _classProperties.Contains (subject); } MetaInfoClass metaInfo = this.GetMetaInfo (property); if (metaInfo != null) { return metaInfo.Contains (subject); } return false; } } /// /// Class which groups all information about a property of a class type in MetaInfo /// internal class MetaInfoClass { private string _name; private Hashtable _entries = new Hashtable(); /// /// Default constructor /// /// Property name public MetaInfoClass (string property) { _name = property; } /// /// The property name for which information is stored /// public string Name { get {return _name;} set {_name = value;} } /// /// Dictionary of all subjects and stored values. /// The index specified the subject. /// public object this [object index] { get {return _entries[index];} set {_entries[index] = value;} } /// /// Indication whether a subject is stored /// /// The subject /// Indication whether the subject is stored public bool Contains (object subject) { return CollectionSupport.ContainsObject (_entries.Keys, subject); } /// /// Gets a list of all subjects stored for this property. /// /// List of all subjects public string[] GetProperties() { ArrayList properties = new ArrayList(); IDictionaryEnumerator DictionaryEnumerator = _entries.GetEnumerator(); while (DictionaryEnumerator.MoveNext()) { if (DictionaryEnumerator.Key is string) { String subject = (string) DictionaryEnumerator.Key; properties.Add (subject); } } return (string[]) properties.ToArray(typeof (string)); } } /// /// Aggregate class for MetaInfoClass. /// Used when writing and reading with XmlFile. /// public class MetaInfoClassAggregate : IAggregate { #region IAggregate Members private MetaInfoClass _class; /// /// Aggregate for the meta info class /// An aggregate is an "in between" object between the element set and XmlFile. /// /> /// /> /// public MetaInfoClassAggregate (object source) { _class = (MetaInfoClass) source; UpdateAggregate(); } /// /// Gets the underlying object /// public object Source { get {return _class;} } /// /// Gets a list of properties which are accessed in a generic way. /// public string[] Properties { get { ArrayList props = new ArrayList (_class.GetProperties()); props.Add ("Name"); return (string[]) props.ToArray (typeof(string)); } } /// /// Class type of a property /// /// The property name /// The property type public Type GetType(string property) { if (property.Equals ("Name")) { return typeof(string); } return _class[property].GetType(); } /// /// Tells whether a property can be written /// /// The property name /// Indication of writable public bool CanWrite(string property) { return true; } /// /// Tells whether a property can be read /// /// The property name /// Indication of readable public bool CanRead(string property) { return true; } /// /// Gets the value of a property /// /// The property name /// The property value public object GetValue(string property) { if (property.Equals ("Name")) { return _class.Name; } return _class[property]; } /// /// Sets a value for a certain property /// /// The property name /// The new property value public void SetValue(string property, object target) { if (property.Equals ("Name")) { _class.Name = (string) target; return; } _class[property] = target; } /// /// Updates the underlying source. Takes no action. /// public void UpdateSource() { } /// /// Prepares the aggregate for subsequent GetValue calls. Takes no action. /// public void UpdateAggregate() { } /// /// Gets a referenced value, i.e. a value corresponding with a reference string within the scope of the source. /// Implementation is delegated to XmlFile.GetRegisteredTarget. /// /// Reference /// The referenced object public object GetReferencedValue (string reference) { return XmlFile.GetRegisteredTarget(this.Source, reference); } #endregion } }