using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Soap;
using System.Xml.Serialization;
namespace Pegasus.Runtime.Serialization
{
/// <summary>
/// Summary description for DataMapper.
/// </summary>
[Obsolete( "Use SqlObjectMapper in place of this class.", false )]
public class DataMapper
{
/// <summary>
/// Hide the constructor.
/// </summary>
private DataMapper()
{
}
private static Hashtable serializerCache = new Hashtable( 10 );
private static XmlRootAttribute xRoot = new XmlRootAttribute( "MyVery_CustomRoot" );
/// <summary>
/// Map the data in the source object to a new instance of the destination object.
/// </summary>
/// <param name="source">Instance of the data object to be coppied</param>
/// <param name="destination">An instance of object to be returned</param>
/// <returns>An new instance of the destination object containing the data valued from the source</returns>
static public object MapIt( object source, object destination )
{
//Type sourceType = (source is Type) ? (Type)source : source.GetType();
Type destinationType = (destination is Type) ? (Type)destination : destination.GetType();
return MapIt( source, destinationType );
}
private static XmlSerializer GetUniqueSerializerFromCache( Type type )
{
XmlSerializer serializer = null;
if ( serializerCache.ContainsKey( type ) )
{
serializer = serializerCache[ type ] as XmlSerializer;
}
else
{
serializer = new XmlSerializer( type, xRoot );
serializerCache[ type ] = serializer;
}
return serializer;
}
/// <summary>
/// Map the data in the source object to a new instance of the destination object.
/// </summary>
/// <param name="source">Instance of the data object to be coppied</param>
/// <param name="destinationType">The type of object to be returned</param>
/// <returns>An new instance of the destination object containing the data valued from the source</returns>
static public object MapIt( object source, Type destinationType )
{
// Create the Serializer for each of the objects
XmlSerializer sourceSerializer = GetUniqueSerializerFromCache( source.GetType() );
XmlSerializer destinationSerializer = GetUniqueSerializerFromCache( destinationType );
// Get the namespaces for each of the objects
string sourceNamespace = GetNamespace( source );
string destinationNamespace = GetNamespace( destinationType );
// Serialize the object and render into a string
MemoryStream stream = new MemoryStream();
sourceSerializer.Serialize( stream, source );
stream.Seek( 0, SeekOrigin.Begin );
string data = new StreamReader(stream).ReadToEnd();
// Replace the namespace declaration in the xml from one object to the other
string changed = data;
if( sourceNamespace != null )
{
changed = data.Replace( string.Format(@" xmlns=""{0}"">", sourceNamespace), string.Format(@" xmlns=""{0}"">", destinationNamespace) );
}
// Re-constitute the object from the modified XML String
StringReader sreader = new StringReader( changed );
object obj = destinationSerializer.Deserialize( sreader ); // instanciate the object
// close the streams
stream.Close();
sreader.Close();
return obj;
}
/// <summary>
/// Get the XmlType attribute's namespace
/// </summary>
/// <param name="obj">Instance of the object or type of object</param>
/// <returns>string value of the namespace specified in the XmlType's Namespace property</returns>
private static string GetNamespace( object obj )
{
Type type = (obj is Type) ? (Type)obj : obj.GetType();
foreach( object attribute in type.GetCustomAttributes(true) )
{
if( attribute is XmlTypeAttribute )
{
return ((XmlTypeAttribute)attribute).Namespace;
}
}
return null;
}
/// <summary>
/// Map the data in the source object to a new instance of the destination object.
/// </summary>
/// <param name="source">Instance of the data object to be coppied</param>
/// <param name="destinationType">The type of object to be returned</param>
/// <returns>An new instance of the destination object containing the data valued from the source</returns>
static public object MapIt_Soap( object source, Type destinationType )
{
MemoryStream stream = null;
try
{
// Create the Soap Formatter
SoapFormatter sourceFormatter = new SoapFormatter();
DumpAttributes( source );
DumpAttributes( destinationType );
// Serialize the object and render into a string
stream = new MemoryStream();
sourceFormatter.Serialize( stream, source );
// Capture the string generated be the soap formatter's serialize
stream.Seek( 0, SeekOrigin.Begin );
string data = new StreamReader(stream).ReadToEnd();
// Re-constitute the object from the modified XML String
stream.Seek( 0, SeekOrigin.Begin );
sourceFormatter.Binder = new MyBinder();
sourceFormatter.Binder.BindToType( destinationType.Assembly.FullName, destinationType.FullName );
object obj = sourceFormatter.Deserialize( stream );
return obj;
}
catch( Exception ex )
{
Debug.WriteLine( ex );
throw;
}
finally
{
if ( stream != null )
{
stream.Close();
}
}
}
/// <summary>
/// Dump the Attribute to the debug output screen
/// </summary>
private static void DumpAttributes( object obj )
{
Type type = (obj is Type) ? (Type)obj : obj.GetType();
Debug.WriteLine( string.Format( "Attributes for {0}", obj ) );
foreach( object attribute in type.GetCustomAttributes(true) )
{
Debug.WriteLine( string.Format( " {0}", attribute ) );
}
}
/// <summary>
/// An attempt a a
/// </summary>
sealed private class MyBinder : System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType( string assemblyName, string typeName )
{
// The following line of code returns the type.
Type typeToDeserialize = Type.GetType( string.Format("{0}, {1}", typeName, assemblyName) );
return typeToDeserialize;
}
}
/// <summary>
/// Map the data in the source object to a new instance of the destination object using reflection
/// </summary>
/// <param name="source">Instance of the data object to be coppied</param>
/// <param name="destinationType">The type of object to be returned</param>
/// <returns>An new instance of the destination object containing the data valued from the source</returns>
static public object MapIt_Reflection( object source, Type destinationType )
{
if( source == null )
{
return null;
}
// find the default constructor
ConstructorInfo constructorDefault = destinationType.GetConstructor( new Type[0] );
if( constructorDefault == null )
{
// find the constructor taking a string argument
ConstructorInfo constructorTakingString = destinationType.GetConstructor( new Type[]{ typeof(string) } );
if( constructorTakingString == null )
return null;
else
return constructorTakingString.Invoke( new string[]{ source.ToString() } );
}
// Do the actual work now
try
{
object destination = constructorDefault.Invoke( new object[0] );
// Reflect all fileds to the new object
ReflectFields( source, destination );
// Reflect all properties to the new object
ReflectProperties( source, destination );
return destination;
}
catch( Exception ex )
{
Debug.WriteLine( ex );
throw;
}
}
/// <summary>
/// Maps the it_ enum.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
/// <returns></returns>
static public object MapIt_Enum(
object source,
object destination
)
{
//subDesc.Duration = (MFN.WebServices.Data.ECommerceData.Subscription.DurationEnum)Enum.Parse( typeof( MFN.WebServices.Data.ECommerceData.Subscription.DurationEnum ), subscriptionPricing.Duration.ToString(), true );
return( Enum.Parse( destination.GetType(), source.ToString(), true ) );
}
/// <summary>
/// Map the data in the source object to a new instance of the destination object using reflection
/// </summary>
/// <param name="source">Instance of the data object to be coppied</param>
/// <param name="destination">The type of object to be returned</param>
/// <returns>An new instance of the destination object containing the data valued from the source</returns>
static protected void ReflectFields( object source, object destination )
{
Type sourceType = (source is Type) ? (Type)source : source.GetType();
Type destinationType = (source is Type) ? (Type)destination : destination.GetType();
FieldInfo[] fields = sourceType.GetFields( BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.Instance );
foreach( FieldInfo source_info in fields )
{
MemberInfo dest_info;
dest_info = destination.GetType().GetField( source_info.Name );
if( dest_info != null )
{
ReflectDude( source, source_info, destination, dest_info );
}
else
{
dest_info = destination.GetType().GetProperty( source_info.Name );
if( dest_info != null )
{
ReflectDude( source, source_info, destination, dest_info );
}
}
}
}
/// <summary>
/// Map the data in the source object to a new instance of the destination object using reflection
/// </summary>
/// <param name="source">Instance of the data object to be coppied</param>
/// <param name="destination">The type of object to be returned</param>
/// <returns>An new instance of the destination object containing the data valued from the source</returns>
static protected void ReflectProperties( object source, object destination )
{
Type sourceType = (source is Type) ? (Type)source : source.GetType();
Type destinationType = (source is Type) ? (Type)destination : destination.GetType();
PropertyInfo[] props = sourceType.GetProperties( BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.GetProperty | BindingFlags.Instance );
foreach( PropertyInfo source_info in props )
{
MemberInfo dest_info;
dest_info = destination.GetType().GetProperty( source_info.Name );
if( dest_info != null )
{
ReflectDude( source, source_info, destination, dest_info );
}
dest_info = destination.GetType().GetField( source_info.Name );
if( dest_info != null )
{
ReflectDude( source, source_info, destination, dest_info );
}
}
}
/// <summary>
/// This dude maps Fields to Properties and visa-versa
/// </summary>
static protected void ReflectDude( object source, MemberInfo source_info, object destination, MemberInfo destination_info )
{
Type source_x_type = null;
object source_x_value = null;
Type destination_x_type = null;
object destination_x_value = null;
// Determine the Source type and value
if( source_info is FieldInfo )
{
FieldInfo info = (FieldInfo) source_info;
source_x_value = info.GetValue( source );
source_x_type = info.FieldType;
}
else if( source_info is PropertyInfo )
{
PropertyInfo info = (PropertyInfo) source_info;
source_x_value = info.GetValue( source, null );
source_x_type = info.PropertyType;
}
// Determine the Source type and value
if( destination_info is FieldInfo )
{
FieldInfo info = (FieldInfo) destination_info;
destination_x_value = info.GetValue( destination );
destination_x_type = info.FieldType;
}
else if( destination_info is PropertyInfo )
{
PropertyInfo info = (PropertyInfo) destination_info;
destination_x_value = info.GetValue( destination, null );
destination_x_type = info.PropertyType;
}
// Now figure out what to do to whom
if( destination_info.DeclaringType.IsClass )
{
if( source_x_type == destination_x_type )
{
DoSetValue( destination, destination_info, source_x_value );
}
else if( destination_x_type.IsEnum && source_x_type.IsEnum )
{
object o = Enum.Parse( destination_x_type, source_x_value.ToString());
DoSetValue( destination, destination_info, o );
}
else if( destination_x_type.IsArray && source_x_type.IsArray )
{
object o = MapArray_Reflection( source_x_value, destination_x_type );
DoSetValue( destination, destination_info, o );
}
else
{
// WARNING!!! Going recursive!
object o = MapIt_Reflection( source_x_value, destination_x_type );
DoSetValue( destination, destination_info, o );
}
}
else
{
DoSetValue( destination, destination_info, source_x_value );
}
}
/// <summary>
/// Set the destination object and property/field to the new value
/// </summary>
static protected void DoSetValue( object destination, MemberInfo destination_info, object new_value )
{
if( destination_info is FieldInfo )
{
((FieldInfo)destination_info).SetValue( destination, new_value );
}
else
{
((PropertyInfo)destination_info).SetValue( destination, new_value, null );
}
}
/// <summary>
/// Create an array of objects using reflection
/// </summary>
/// <param name="source">Source array of objects</param>
/// <param name="type">Type of the new array of object</param>
/// <returns></returns>
protected static object[] MapArray_Reflection( object source, Type type )
{
// Like kinds of arrays
if( type == source.GetType().GetElementType() )
{
return (object[])source;
}
ArrayList tempList = new ArrayList( );
foreach( object element in (object[])source )
{
tempList.Add( MapIt_Reflection( element, type.GetElementType() ) );
}
return (object[]) tempList.ToArray( type.GetElementType() );
}
}
}