/*
OpenNxSerialization Framework
Copyright (C) 2006 - 2008 "NeXtreme Innovations"
[The Next Xtreme Innovations]
This program is free software, distributed under the terms of
the GNU General Public License Version 2. See the "License.txt" file
at the top of the source tree.
*/
using System;
using System.Collections;
using NeXtreme.OpenNxSerialization.Surrogates;
namespace NeXtreme.OpenNxSerialization
{
/// <summary>
/// Provides the common type identification system. Takes care of registering type surrogates
/// and type handles.
/// </summary>
public sealed class NxTypeSurrogateSelector : INxTypeSurrogateSelector
{
/// <summary>
/// Minimum id that can be assigned to a user defined type.
/// </summary>
/// <remarks>
/// If you specify a fixed type handle make sure it is in the range <see cref="NxTypeSurrogateSelector.MinTypeHandle"/>
/// and <see cref="NxTypeSurrogateSelector.MaxTypeHandle"/> (inclusive).
/// </remarks>
public const short MinTypeHandle = short.MinValue + 512;
/// <summary>
/// Maximum id that can be assigned to a user defined type.
/// </summary>
/// <remarks>
/// If you specify a fixed type handle make sure it is in the range <see cref="NxTypeSurrogateSelector.MinTypeHandle"/>
/// and <see cref="NxTypeSurrogateSelector.MaxTypeHandle"/> (inclusive).
/// </remarks>
public const short MaxTypeHandle = short.MaxValue;
private static INxTypeSurrogateSelector msDefault;
private INxSerializationSurrogate mNullSurrogate;
private INxSerializationSurrogate mDefaultSurrogate;
private IDictionary mTypeSurrogateMap;
private IDictionary mHandleSurrogateMap;
private short mNewTypeHandle;
/// <summary>
/// Static constructor registers built-in surrogates with the system.
/// </summary>
static NxTypeSurrogateSelector()
{
msDefault = new NxTypeSurrogateSelector();
}
/// <summary>
/// Constructs the object with built-in surrogates.
/// </summary>
public NxTypeSurrogateSelector()
: this(true)
{
}
/// <summary>
/// Constructs the object with or without built-in surrogates.
/// </summary>
/// <param name="useBuiltinSurrogates">If true built-in surrogates are
/// registered</param>
public NxTypeSurrogateSelector(bool useBuiltinSurrogates)
{
mTypeSurrogateMap = /*Hashtable.Synchronized*/(new Hashtable(100));
mHandleSurrogateMap = /*Hashtable.Synchronized*/(new Hashtable(100));
//mTypeSurrogateMap = Hashtable.Synchronized(new Hashtable(100, 0.1f));
//mHandleSurrogateMap = Hashtable.Synchronized(new Hashtable(100, 0.1f));
mNewTypeHandle = MinTypeHandle;
mNullSurrogate = new NxNullSerializationSurrogate();
mDefaultSurrogate = new NxObjectSerializationSurrogate(typeof(object));
Register(mNullSurrogate, 0);
Register(mDefaultSurrogate, 1);
Register(new NxObjRefSerializationSurrogate(), 2);
if (useBuiltinSurrogates)
{
RegisterBuiltinSurrogates();
}
}
/// <summary>
/// Returns the default type surrogate selector object
/// </summary>
/// <value>The default <see cref="NxTypeSurrogateSelector"/> object</value>
public static INxTypeSurrogateSelector Default
{
get { return NxTypeSurrogateSelector.msDefault; }
set { NxTypeSurrogateSelector.msDefault = value; }
}
/// <summary>
/// Gets and object that can be used to synchronize access to the <see cref="NxTypeSurrogateSelector"/>
/// </summary>
public object SyncRoot
{
get { return mTypeSurrogateMap.SyncRoot; }
}
/// <summary>
/// Returns the default type surrogate for null
/// </summary>
/// <value>The default <see cref="INxSerializationSurrogate"/> for null</value>
public INxSerializationSurrogate NullSurrogate
{
get { return mNullSurrogate; }
set { mNullSurrogate = value; }
}
/// <summary>
/// Returns the default type surrogate
/// </summary>
/// <remarks>
/// The default surrogate is used when no specialized surrogate is found for a type
/// </remarks>
/// <value>The default <see cref="INxSerializationSurrogate"/> object</value>
public INxSerializationSurrogate DefaultSurrogate
{
get { return mDefaultSurrogate; }
set { mDefaultSurrogate = value; }
}
/// <summary>
/// Use this to determine whether the specified surrogate is a built-in surrogate
/// </summary>
/// <returns>
/// Returns true if the specified surrogate is a built-in surrogate
/// </returns>
public bool IsBuiltinSurrogate(INxSerializationSurrogate surrogate)
{
if (surrogate == null)
throw new ArgumentNullException("surrogate");
return typeof(INxBuiltinSerializationSurrogate).IsAssignableFrom(surrogate.GetType());
}
/// <summary>
/// Returns an object that can be used to iterate over the collection of surrogates
/// </summary>
/// <returns>
/// An <see cref="IEnumerator"/> that can be used to iterate over the collection of surrogates
/// </returns>
public IEnumerator GetEnumerator()
{
return mTypeSurrogateMap.Values.GetEnumerator();
}
/// <summary>
/// Finds and returns an appropriate <see cref="INxSerializationSurrogate"/> for the given
/// object.
/// </summary>
/// <param name="graph">specified object</param>
/// <returns><see cref="INxSerializationSurrogate"/> object</returns>
public INxSerializationSurrogate GetSurrogateForObject(object graph)
{
if (graph == null)
return mNullSurrogate;
return GetSurrogateForType(graph.GetType());
}
/// <summary>
/// Finds and returns an appropriate <see cref="INxSerializationSurrogate"/> for the given
/// type.
/// </summary>
/// <param name="type">specified type</param>
/// <returns><see cref="INxSerializationSurrogate"/> object</returns>
/// <remarks>
/// If no surrogate is found for the specified <paramref name="type"/>, the <see cref="Default"/>
/// surrogate is returned.
/// </remarks>
public INxSerializationSurrogate GetSurrogateForType(Type type)
{
INxSerializationSurrogate surrogate = (INxSerializationSurrogate)mTypeSurrogateMap[type];
if (surrogate == null)
surrogate = mDefaultSurrogate;
return surrogate;
}
/// <summary>
/// Finds and returns <see cref="INxSerializationSurrogate"/> for the given
/// type. Allows you to inhibit the usage of default surrogate.
/// </summary>
/// <param name="type">specified type</param>
/// <param name="strict">Specifies whether the default surrogate will be returned.</param>
/// <returns><see cref="INxSerializationSurrogate"/> object</returns>
public INxSerializationSurrogate GetSurrogateForType(Type type, bool strict)
{
INxSerializationSurrogate surrogate = (INxSerializationSurrogate)mTypeSurrogateMap[type];
if (!strict && surrogate == null)
surrogate = mDefaultSurrogate;
return surrogate;
}
/// <summary>
/// Finds and returns an appropriate <see cref="INxSerializationSurrogate"/> for the given
/// type handle.
/// </summary>
/// <param name="handle">type handle</param>
/// <returns><see cref="INxSerializationSurrogate"/> object</returns>
public INxSerializationSurrogate GetSurrogateForTypeHandle(short handle)
{
INxSerializationSurrogate surrogate = (INxSerializationSurrogate)mHandleSurrogateMap[handle];
if (surrogate == null)
surrogate = mDefaultSurrogate;
return surrogate;
}
#region / INxSerializationSurrogate registration specific /
/// <summary>
/// Registers the specified <see cref="INxSerializationSurrogate"/> with the system.
/// </summary>
/// <param name="surrogate">specified surrogate</param>
/// <returns>false if the surrogated type already has a surrogate</returns>
public bool Register(INxSerializationSurrogate surrogate)
{
if (surrogate == null)
throw new ArgumentNullException("surrogate");
for (;;)
{
try
{
return Register(surrogate, ++mNewTypeHandle);
}
catch (ArgumentException) { }
catch (Exception)
{
throw;
}
}
}
/// <summary>
/// Registers the specified <see cref="INxSerializationSurrogate"/> with the given type handle.
/// Gives more control over the way type handles are generated by the system and allows the
/// user to supply *HARD* handles for better interoperability among applications.
/// </summary>
/// <param name="surrogate">specified surrogate</param>
/// <param name="typeHandle">specified HARD handle for type</param>
/// <returns>false if the surrogated type already has a surrogate</returns>
/// <remarks>
/// <paramref name="typeHandle"/> must be in the range <see cref="NxTypeSurrogateSelector.MinTypeHandle"/>
/// and <see cref="NxTypeSurrogateSelector.MaxTypeHandle"/> (inclusive).
/// </remarks>
public bool Register(INxSerializationSurrogate surrogate, short typeHandle)
{
if (!IsBuiltinSurrogate(surrogate))
{
if (typeHandle < MinTypeHandle)
{
throw new ArgumentException(Resources.Surrogates_HandleOutOfRange);
}
}
lock (mTypeSurrogateMap.SyncRoot)
{
if (mHandleSurrogateMap.Contains(typeHandle))
throw new ArgumentException(Resources.Surrogates_AlreadyRegistered);
if (!mTypeSurrogateMap.Contains(surrogate.ActualType))
{
surrogate.TypeHandle = typeHandle;
mTypeSurrogateMap.Add(surrogate.ActualType, surrogate);
mHandleSurrogateMap.Add(surrogate.TypeHandle, surrogate);
return true;
}
}
return false;
}
/// <summary>
/// Unregisters the specified <see cref="INxSerializationSurrogate"/> from the system.
/// </summary>
/// <param name="surrogate">specified surrogate</param>
public void Unregister(INxSerializationSurrogate surrogate)
{
if (surrogate == null)
throw new ArgumentNullException("surrogate");
lock (mTypeSurrogateMap.SyncRoot)
{
mTypeSurrogateMap.Remove(surrogate.ActualType);
mHandleSurrogateMap.Remove(surrogate.TypeHandle);
}
}
/// <summary>
/// Unregisters all surrogates, except null and default ones.
/// </summary>
public void Clear()
{
lock (mTypeSurrogateMap.SyncRoot)
{
mTypeSurrogateMap.Clear();
mHandleSurrogateMap.Clear();
mNewTypeHandle = MinTypeHandle;
Register(mNullSurrogate, 0);
Register(mDefaultSurrogate, 1);
Register(new NxObjRefSerializationSurrogate(), 2);
}
}
#endregion
#region / Builtin surrogates /
/// <summary>
/// Registers built-in surrogates with the system.
/// </summary>
public void RegisterBuiltinSurrogates()
{
short typeHandle = 32;
lock (mTypeSurrogateMap.SyncRoot)
{
Register(new NxSerializationInfoSurrogate(), typeHandle++);
Register(new NxBooleanSerializationSurrogate(), typeHandle++);
Register(new NxByteSerializationSurrogate(), typeHandle++);
Register(new NxCharSerializationSurrogate(), typeHandle++);
Register(new NxSingleSerializationSurrogate(), typeHandle++);
Register(new NxDoubleSerializationSurrogate(), typeHandle++);
Register(new NxDecimalSerializationSurrogate(), typeHandle++);
Register(new NxInt16SerializationSurrogate(), typeHandle++);
Register(new NxInt32SerializationSurrogate(), typeHandle++);
Register(new NxInt64SerializationSurrogate(), typeHandle++);
Register(new NxStringSerializationSurrogate(), typeHandle++);
Register(new NxDateTimeSerializationSurrogate(), typeHandle++);
Register(new NxGuidSerializationSurrogate(), typeHandle++);
Register(new NxSByteSerializationSurrogate(), typeHandle++);
Register(new NxUInt16SerializationSurrogate(), typeHandle++);
Register(new NxUInt32SerializationSurrogate(), typeHandle++);
Register(new NxUInt64SerializationSurrogate(), typeHandle++);
Register(new NxObjectArraySerializationSurrogate(), typeHandle++);
Register(new NxBooleanArraySerializationSurrogate(), typeHandle++);
Register(new NxByteArraySerializationSurrogate(), typeHandle++);
Register(new NxCharArraySerializationSurrogate(), typeHandle++);
Register(new NxSingleArraySerializationSurrogate(), typeHandle++);
Register(new NxDoubleArraySerializationSurrogate(), typeHandle++);
Register(new NxDecimalArraySerializationSurrogate(), typeHandle++);
Register(new NxInt16ArraySerializationSurrogate(), typeHandle++);
Register(new NxInt32ArraySerializationSurrogate(), typeHandle++);
Register(new NxInt64ArraySerializationSurrogate(), typeHandle++);
Register(new NxStringArraySerializationSurrogate(), typeHandle++);
Register(new NxDateTimeArraySerializationSurrogate(), typeHandle++);
Register(new NxGuidArraySerializationSurrogate(), typeHandle++);
Register(new NxSByteArraySerializationSurrogate(), typeHandle++);
Register(new NxUInt16ArraySerializationSurrogate(), typeHandle++);
Register(new NxUInt32ArraySerializationSurrogate(), typeHandle++);
Register(new NxUInt64ArraySerializationSurrogate(), typeHandle++);
// TODO: Would a custom surrogate be faster?
Register(new NxISerializableSerializationSurrogate(typeof(Exception)), typeHandle++);
Register(new NxISerializableSerializationSurrogate(typeof(WeakReference)), typeHandle++);
Register(new NxArraySerializationSurrogate(typeof(Array)), typeHandle++);
Register(new NxIListSerializationSurrogate(typeof(IList)), typeHandle++);
Register(new NxIListSerializationSurrogate(typeof(ArrayList)), typeHandle++);
Register(new NxIDictionarySerializationSurrogate(typeof(IDictionary)), typeHandle++);
Register(new NxIDictionarySerializationSurrogate(typeof(Hashtable)), typeHandle++);
Register(new NxIDictionarySerializationSurrogate(typeof(SortedList)), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Boolean>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Byte>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Char>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Single>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Double>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Decimal>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Int16>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Int32>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Int64>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<DateTime>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<Guid>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<SByte>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<UInt16>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<UInt32>(), typeHandle++);
Register(new NxNullableArraySerializationSurrogate<UInt64>(), typeHandle++);
Register(new NxHeaderSerializationSurrogate(), typeHandle++);
Register(new NxHeaderArraySerializationSurrogate(), typeHandle++);
}
}
#endregion
}
}