#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
}
}